1/*
2 * Copyright (c) 2011 - 2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <sys/smb_apple.h>
25#include <sys/syslog.h>
26
27#include <sys/msfscc.h>
28#include <netsmb/smb.h>
29#include <netsmb/smb_2.h>
30#include <netsmb/smb_rq.h>
31#include <netsmb/smb_rq_2.h>
32#include <netsmb/smb_conn.h>
33#include <netsmb/smb_conn_2.h>
34
35#include <smbfs/smbfs.h>
36#include <smbfs/smbfs_node.h>
37#include <smbfs/smbfs_subr.h>
38#include <smbfs/smbfs_subr_2.h>
39#include <smbfs/smbfs_notify_change.h>
40#include <smbclient/ntstatus.h>
41#include <netsmb/smb_converter.h>
42
43
44static int
45smb2fs_smb_copyfile_mac(struct smb_share *share, struct smbnode *src_np,
46                        struct smbnode *tdnp, const char *tnamep, size_t tname_len,
47                        vfs_context_t context);
48static int
49smb2fs_smb_delete(struct smb_share *share, struct smbnode *np, enum vtype vnode_type,
50                  const char *namep, size_t name_len,
51                  int xattr, vfs_context_t context);
52
53static uint32_t
54smb2fs_smb_fillchunk_arr(struct smb2_copychunk_chunk *chunk_arr,
55                         uint32_t chunk_arr_size,
56                         uint64_t total_len, uint32_t max_chunk_len,
57                         uint64_t src_offset, uint64_t trg_offset,
58                         uint32_t *chunk_count_out, uint64_t *total_len_out);
59
60static uint32_t
61smb2fs_smb_get_create_options(struct smb_share *share, struct smbnode *np,
62                              const char *namep, const char *strm_namep,
63                              enum vtype vnode_type, uint32_t check_reparse);
64
65static int
66smb2fs_smb_listxattrs(struct smb_share *share, struct smbnode *np, char **xattrlist,
67                      size_t *xattrlist_len, vfs_context_t context);
68int
69smb2fs_smb_ntcreatex(struct smb_share *share, struct smbnode *np,
70                     const char *namep, size_t in_nmlen,
71                     const char *strm_namep, size_t in_strm_nmlen,
72                     uint32_t desired_access, enum vtype vnode_type,
73                     uint32_t share_access, uint32_t disposition,
74                     uint64_t create_flags, uint32_t create_options,
75                     SMBFID *fidp, struct smbfattr *fap,
76                     struct smb_rq **compound_rqp, struct smb2_create_rq **in_createp,
77                     void *create_contextp, vfs_context_t context);
78static int
79smb2fs_smb_parse_ntcreatex(struct smb_share *share, struct smbnode *np,
80                           struct smb2_create_rq *createp,
81                           SMBFID *fidp, struct smbfattr *fap,
82                           vfs_context_t context);
83static int
84smb2fs_smb_qstreaminfo(struct smb_share *share, struct smbnode *np, enum vtype vnode_type,
85                       const char *namep, size_t name_len,
86                       const char *stream_namep,
87                       uio_t uio, size_t *sizep,
88                       uint64_t *stream_sizep, uint64_t *stream_alloc_sizep,
89                       uint32_t *stream_flagsp, uint32_t *max_accessp,
90                       vfs_context_t context);
91static int
92smb2fs_smb_request_resume_key(struct smb_share *share, SMBFID fid, u_char *resume_key,
93                              vfs_context_t context);
94
95static int
96smb2fs_smb_set_eof(struct smb_share *share, SMBFID fid, uint64_t newsize,
97                   vfs_context_t context);
98
99
100/*
101 * Note:  The _smbfs_smb_ in the function name indicates that these functions
102 * are called from the smbfs kext and set up the structs necessary to call the
103 * _smb_ functions.  Then copy the results back out to smbfs.
104 *
105 *
106 * SMB 1 implementation remains in original files
107 *
108 * Implementations listed in alphabetical order
109 * 1) SMB 2/3 implementation listed first,
110 * 2) SMB 1, SMB 2/3 generic implementation next
111 *
112 */
113
114/*
115 * Compound Request Chain notes:
116 * 1) A compound req is identified by rqp->sr_next_rqp != NULL
117 * 2) The first rqp in the chain has the response data for ALL the
118 * responses. Its header data has already been parsed out and saved in
119 * the first rqp. Subsequent headers will have to be manually parsed out.
120 * 3) When parsing the response chain, even if an earlier response gets an
121 * error, continuing trying to parse the rest of the replies to get the
122 * credits granted in the response header.
123 * 4) If the first response got an error, only print that error message and
124 * skip printing any more errors for the rest of the responses in the chain.
125 */
126
127int
128smb2fs_smb_cmpd_check_copyfile(struct smb_share *share,
129                               struct smbnode *create_np,
130                               vfs_context_t context)
131{
132	int error, tmp_error;
133    SMBFID fid = 0;
134    struct smb2_create_rq *createp = NULL;
135    struct smb2_ioctl_rq *ioctlp = NULL;
136    struct smb2_close_rq *closep = NULL;
137	struct smb_rq *create_rqp = NULL;
138	struct smb_rq *ioctl_rqp = NULL;
139	struct smb_rq *close_rqp = NULL;
140	struct mdchain *mdp;
141    size_t next_cmd_offset = 0;
142    uint32_t need_delete_fid = 0;
143    uint32_t create_desired_access = SMB2_FILE_READ_DATA |
144                                     SMB2_FILE_READ_ATTRIBUTES |
145                                     SMB2_FILE_READ_EA;
146    enum vtype vnode_type = VREG;
147    uint32_t share_access = NTCREATEX_SHARE_ACCESS_READ;
148    uint64_t create_flags = 0;
149    uint32_t create_options = 0;
150    uint32_t disposition = FILE_OPEN;
151
152    /*
153     * For this function, vnode_type is the item's type. The item will be
154     * Opened and the Ioctl done on the item.
155     */
156
157    SMB_MALLOC(ioctlp,
158               struct smb2_ioctl_rq *,
159               sizeof(struct smb2_ioctl_rq),
160               M_SMBTEMP,
161               M_WAITOK | M_ZERO);
162    if (ioctlp == NULL) {
163		SMBERROR("SMB_MALLOC failed\n");
164        error = ENOMEM;
165        goto bad;
166    }
167
168    if (create_np) {
169        vnode_type = vnode_isdir(create_np->n_vnode) ? VDIR : VREG;
170    }
171
172resend:
173    /*
174     * Build the Create call
175     */
176    create_options = smb2fs_smb_get_create_options(share, create_np,
177                                                   NULL, NULL,
178                                                   vnode_type, 0);
179    error = smb2fs_smb_ntcreatex(share, create_np,
180                                 NULL, 0,
181                                 NULL, 0,
182                                 create_desired_access, vnode_type,
183                                 share_access, disposition,
184                                 create_flags, create_options,
185                                 &fid, NULL,
186                                 &create_rqp, &createp,
187                                 NULL, context);
188
189    if (error) {
190        SMBDEBUG("smb2fs_smb_ntcreatex failed %d\n", error);
191        goto bad;
192    }
193
194    /* Update Create hdr */
195    error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST);
196    if (error) {
197        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
198        goto bad;
199    }
200
201    /*
202     * Build the IOCTL request
203     */
204    ioctlp->share = share;
205    ioctlp->ctl_code = FSCTL_SRV_REQUEST_RESUME_KEY;
206    fid = 0xffffffffffffffff;   /* fid is -1 for compound requests */
207    ioctlp->fid = fid;
208
209	ioctlp->snd_input_len = 0;
210	ioctlp->snd_output_len = 0;
211	ioctlp->rcv_input_len = 0;
212	ioctlp->rcv_output_len = 0x20;
213
214    error = smb2_smb_ioctl(share, ioctlp, &ioctl_rqp, context);
215    if (error) {
216        SMBERROR("smb2_smb_ioctl failed %d\n", error);
217        goto bad;
218    }
219
220    /* Update IOCTL hdr */
221    error = smb2_rq_update_cmpd_hdr(ioctl_rqp, SMB2_CMPD_MIDDLE);
222    if (error) {
223        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
224        goto bad;
225    }
226
227    /* Chain IOCTL to the Create */
228    create_rqp->sr_next_rqp = ioctl_rqp;
229
230    /*
231     * Build the Close request
232     */
233    error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context);
234    if (error) {
235        SMBERROR("smb2_smb_close_fid failed %d\n", error);
236        goto bad;
237    }
238
239    /* Update Close hdr */
240    error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST);
241    if (error) {
242        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
243        goto bad;
244    }
245
246    /* Chain Close to the IOCTL */
247    ioctl_rqp->sr_next_rqp = close_rqp;
248
249    /*
250     * Send the compound request of Create/IOCTL/Close
251     */
252    error = smb_rq_simple(create_rqp);
253
254    if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) {
255        /* Rebuild and try sending again */
256        smb_rq_done(create_rqp);
257        create_rqp = NULL;
258
259        smb_rq_done(ioctl_rqp);
260        ioctl_rqp = NULL;
261
262        smb_rq_done(close_rqp);
263        close_rqp = NULL;
264
265        SMB_FREE(createp, M_SMBTEMP);
266        createp = NULL;
267
268        SMB_FREE(closep, M_SMBTEMP);
269        closep = NULL;
270
271        goto resend;
272    }
273
274    createp->ret_ntstatus = create_rqp->sr_ntstatus;
275
276    /* Get pointer to response data */
277    smb_rq_getreply(create_rqp, &mdp);
278
279    if (error) {
280        /* Create failed, try parsing the IOCTL */
281        SMBDEBUG("smb_rq_simple failed %d id %lld\n",
282                 error, create_rqp->sr_messageid);
283        goto parse_ioctl;
284    }
285
286    /*
287     * Parse the Create response.
288     */
289    error = smb2_smb_parse_create(share, mdp, createp);
290    if (error) {
291        /* Create parsing failed, try parsing the IOCTL */
292        SMBERROR("smb2_smb_parse_create failed %d id %lld\n",
293                 error, create_rqp->sr_messageid);
294        goto parse_ioctl;
295    }
296
297    /* At this point, fid has been entered into fid table */
298    need_delete_fid = 1;
299
300    /*
301     * No need to call smb2fs_smb_parse_ntcreatex since just need a FID.
302     */
303
304parse_ioctl:
305    /* Consume any pad bytes */
306    tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp);
307    if (tmp_error) {
308        /* Failed to find next command, so can't parse rest of the responses */
309        SMBERROR("create smb2_rq_next_command failed %d id %lld\n",
310                 tmp_error, create_rqp->sr_messageid);
311        goto bad;
312    }
313
314    /*
315     * Parse IOCTL SMB 2/3 header
316     */
317    tmp_error = smb2_rq_parse_header(ioctl_rqp, &mdp);
318    ioctlp->ret_ntstatus = ioctl_rqp->sr_ntstatus;
319    if (tmp_error) {
320        /* IOCTL got an error, try parsing the Close */
321        if (!error) {
322            SMBDEBUG("ioctl smb2_rq_parse_header failed %d, id %lld\n",
323                     tmp_error, ioctl_rqp->sr_messageid);
324            error = tmp_error;
325        }
326        goto parse_close;
327    }
328
329    /* Parse the IOCTL response */
330    tmp_error = smb2_smb_parse_ioctl(mdp, ioctlp);
331    if (tmp_error) {
332        /* IOCTL parsing got an error, try parsing the Close */
333        if (!error) {
334            SMBERROR("smb2_smb_parse_ioctl failed %d id %lld\n",
335                     tmp_error, ioctl_rqp->sr_messageid);
336            error = tmp_error;
337        }
338        goto parse_close;
339    }
340
341    /*
342     * At this point, we know the IOCTL worked. Thats all we need to
343     * know is whether this compound request worked or not.
344     */
345
346parse_close:
347    /* Update closep fid so it gets freed from FID table */
348    closep->fid = createp->ret_fid;
349
350    /* Consume any pad bytes */
351    tmp_error = smb2_rq_next_command(ioctl_rqp, &next_cmd_offset, mdp);
352    if (tmp_error) {
353        /* Failed to find next command, so can't parse rest of the responses */
354        SMBERROR("ioctl smb2_rq_next_command failed %d\n", tmp_error);
355        error = error ? error : tmp_error;
356        goto bad;
357    }
358
359    /*
360     * Parse Close SMB 2/3 header
361     */
362    tmp_error = smb2_rq_parse_header(close_rqp, &mdp);
363    closep->ret_ntstatus = close_rqp->sr_ntstatus;
364    if (tmp_error) {
365        if (!error) {
366            SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n",
367                     tmp_error, close_rqp->sr_messageid);
368            error = tmp_error;
369        }
370        goto bad;
371    }
372
373    /* Parse the Close response */
374    tmp_error = smb2_smb_parse_close(mdp, closep);
375    if (tmp_error) {
376        if (!error) {
377            SMBERROR("smb2_smb_parse_close failed %d id %lld\n",
378                     tmp_error, close_rqp->sr_messageid);
379            error = tmp_error;
380        }
381        goto bad;
382    }
383
384    /* At this point, fid has been removed from fid table */
385    need_delete_fid = 0;
386
387bad:
388    if (need_delete_fid == 1) {
389        /*
390         * Close failed but the Create worked and was successfully parsed.
391         * Try issuing the Close request again.
392         */
393        tmp_error = smb2_smb_close_fid(share, createp->ret_fid,
394                                       NULL, NULL, context);
395        if (tmp_error) {
396            SMBERROR("Second close failed %d\n", tmp_error);
397        }
398    }
399
400    if (create_rqp != NULL) {
401        smb_rq_done(create_rqp);
402    }
403    if (ioctl_rqp != NULL) {
404        smb_rq_done(ioctl_rqp);
405    }
406    if (close_rqp != NULL) {
407        smb_rq_done(close_rqp);
408    }
409
410    if (createp != NULL) {
411        SMB_FREE(createp, M_SMBTEMP);
412    }
413    if (ioctlp != NULL) {
414        SMB_FREE(ioctlp, M_SMBTEMP);
415    }
416    if (closep != NULL) {
417        SMB_FREE(closep, M_SMBTEMP);
418    }
419
420    return (error);
421}
422
423int
424smb2fs_smb_cmpd_create(struct smb_share *share, struct smbnode *np,
425                       const char *namep, size_t name_len,
426                       const char *strm_namep, size_t strm_name_len,
427                       uint32_t desired_access, enum vtype vnode_type,
428                       uint32_t share_access, uint32_t disposition,
429                       uint64_t create_flags, uint32_t *ntstatus,
430                       SMBFID *fidp, struct smbfattr *fap,
431                       void *create_contextp, vfs_context_t context)
432{
433	int error, tmp_error;
434    struct smb2_create_rq *createp = NULL;
435    struct smb2_query_info_rq *queryp = NULL;
436    struct smb2_close_rq *closep = NULL;
437	struct smb_rq *create_rqp = NULL;
438	struct smb_rq *query_rqp = NULL;
439	struct smb_rq *close_rqp = NULL;
440	struct mdchain *mdp;
441    size_t next_cmd_offset = 0;
442    uint32_t need_delete_fid = 0;
443    SMBFID fid = 0;
444    int add_query = 0;
445    int add_close = 0;
446    uint64_t inode_number = 0;
447    uint32_t inode_number_len;
448    uint32_t create_options = 0;
449
450    /*
451     * For this function, vnode_type is the item's type. The item will be
452     * Opened and the Query Info will be done on the item.
453     */
454
455    /*
456     * This function can do Create/Close, Create/Query, or Create/Query/Close
457     * If SMB2_CREATE_DO_CREATE is set in create_flags, then the Query is
458     * added to get the file ID. If fidp is NULL, then the Close is added.
459     *
460     * ntstatus is needed for DFS code.  smb_usr_check_dir needs to return the
461     * ntstatus up to isReferralPathNotCovered() in user space.
462     */
463
464    if ((create_flags & SMB2_CREATE_DO_CREATE) &&
465        (SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS)) {
466        /* Need the file id, so add a query into the compound request */
467        add_query = 1;
468    }
469
470    if (fidp == NULL) {
471        /* If fidp is null, add the close into the compound request */
472        add_close = 1;
473    }
474
475    if ((add_query == 0) && (add_close == 0)) {
476        /* Just doing a simple create */
477        create_options = smb2fs_smb_get_create_options(share, np,
478                                                       namep, strm_namep,
479                                                       vnode_type, 1);
480        error = smb2fs_smb_ntcreatex(share, np,
481                                     namep, name_len,
482                                     strm_namep, strm_name_len,
483                                     desired_access, vnode_type,
484                                     share_access, disposition,
485                                     create_flags, create_options,
486                                     fidp, fap,
487                                     NULL, NULL,
488                                     create_contextp, context);
489        return error;
490    }
491
492    if (add_query) {
493        SMB_MALLOC(queryp,
494                   struct smb2_query_info_rq *,
495                   sizeof(struct smb2_query_info_rq),
496                   M_SMBTEMP,
497                   M_WAITOK | M_ZERO);
498        if (queryp == NULL) {
499            SMBERROR("SMB_MALLOC failed\n");
500            error = ENOMEM;
501            goto bad;
502        }
503    }
504
505resend:
506    /*
507     * Build the Create call
508     */
509    create_options = smb2fs_smb_get_create_options(share, np,
510                                                   namep, strm_namep,
511                                                   vnode_type, 1);
512    error = smb2fs_smb_ntcreatex(share, np,
513                                 namep, name_len,
514                                 strm_namep, strm_name_len,
515                                 desired_access, vnode_type,
516                                 share_access, disposition,
517                                 create_flags, create_options,
518                                 &fid, fap,
519                                 &create_rqp, &createp,
520                                 create_contextp, context);
521    if (error) {
522        SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error);
523        goto bad;
524    }
525
526    /* Update Create hdr */
527    error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST);
528    if (error) {
529        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
530        goto bad;
531    }
532
533    fid = 0xffffffffffffffff;   /* fid is -1 for compound requests */
534
535    if (add_query) {
536        /*
537         * Build the Query Info request (to get File ID)
538         */
539        inode_number_len = (uint32_t) sizeof(inode_number);
540
541        queryp->info_type = SMB2_0_INFO_FILE;
542        queryp->file_info_class = FileInternalInformation;
543        queryp->add_info = 0;
544        queryp->flags = 0;
545        queryp->output_buffer_len = inode_number_len;
546        queryp->output_buffer = (uint8_t *) &inode_number;
547        queryp->input_buffer_len = 0;
548        queryp->input_buffer = NULL;
549        queryp->ret_buffer_len = 0;
550        queryp->fid = fid;
551
552        error = smb2_smb_query_info(share, queryp, &query_rqp, context);
553        if (error) {
554            SMBERROR("smb2_smb_query_info failed %d\n", error);
555            goto bad;
556        }
557
558        /* Update Query hdr */
559        if (add_close) {
560            error = smb2_rq_update_cmpd_hdr(query_rqp, SMB2_CMPD_MIDDLE);
561        }
562        else {
563            error = smb2_rq_update_cmpd_hdr(query_rqp, SMB2_CMPD_LAST);
564        }
565        if (error) {
566            SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
567            goto bad;
568        }
569
570        /* Chain Query Info to the Create */
571        create_rqp->sr_next_rqp = query_rqp;
572    }
573
574    if (add_close) {
575        /*
576         * Build the Close request
577         */
578        error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context);
579        if (error) {
580            SMBERROR("smb2_smb_close_fid failed %d\n", error);
581            goto bad;
582        }
583
584        /* Update Close hdr */
585        error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST);
586        if (error) {
587            SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
588            goto bad;
589        }
590
591        if (add_query) {
592            /* Chain Close to the Query */
593            query_rqp->sr_next_rqp = close_rqp;
594        }
595        else {
596            /* Chain Close to the Create */
597            create_rqp->sr_next_rqp = close_rqp;
598        }
599    }
600
601    /*
602     * Send the compound request of Create/Query/Close
603     */
604    error = smb_rq_simple(create_rqp);
605
606    if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) {
607        /* Rebuild and try sending again */
608        smb_rq_done(create_rqp);
609        create_rqp = NULL;
610
611        if (query_rqp != NULL) {
612            smb_rq_done(query_rqp);
613            query_rqp = NULL;
614        }
615
616        if (close_rqp != NULL) {
617            smb_rq_done(close_rqp);
618            close_rqp = NULL;
619        }
620
621        SMB_FREE(createp, M_SMBTEMP);
622        createp = NULL;
623
624        if (closep != NULL) {
625            SMB_FREE(closep, M_SMBTEMP);
626            closep = NULL;
627        }
628
629        goto resend;
630    }
631
632    createp->ret_ntstatus = create_rqp->sr_ntstatus;
633    if (ntstatus) {
634        /* Return NT Status error if they want it */
635        *ntstatus = createp->ret_ntstatus;
636    }
637
638    /* Get pointer to response data */
639    smb_rq_getreply(create_rqp, &mdp);
640
641    if (error) {
642        /* Create failed, try parsing the Query */
643        if (error != ENOENT) {
644            SMBDEBUG("smb_rq_simple failed %d id %lld\n",
645                     error, create_rqp->sr_messageid);
646        }
647        goto parse_query;
648    }
649
650    /*
651     * Parse the Create response.
652     */
653    error = smb2_smb_parse_create(share, mdp, createp);
654    if (error) {
655        /* Create parsing failed, try parsing the Query */
656        SMBERROR("smb2_smb_parse_create failed %d id %lld\n",
657                 error, create_rqp->sr_messageid);
658        goto parse_query;
659    }
660
661    /* At this point, fid has been entered into fid table */
662    need_delete_fid = 1;
663
664    /*
665     * Fill in fap and possibly update vnode's meta data caches
666     */
667    error = smb2fs_smb_parse_ntcreatex(share, np, createp,
668                                       fidp, fap, context);
669    if (error) {
670        /* Updating meta data cache failed, try parsing the Close */
671        SMBERROR("smb2fs_smb_parse_ntcreatex failed %d id %lld\n",
672                 error, create_rqp->sr_messageid);
673    }
674
675parse_query:
676    if (query_rqp != NULL) {
677        /* Consume any pad bytes */
678        tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp);
679        if (tmp_error) {
680            /* Failed to find next command, so can't parse rest of the responses */
681            SMBERROR("create smb2_rq_next_command failed %d id %lld\n",
682                     tmp_error, create_rqp->sr_messageid);
683            error = error ? error : tmp_error;
684            goto bad;
685        }
686
687        /*
688         * Parse Query Info SMB 2/3 header
689         */
690        tmp_error = smb2_rq_parse_header(query_rqp, &mdp);
691        queryp->ret_ntstatus = query_rqp->sr_ntstatus;
692        if (tmp_error) {
693            /* Query Info got an error, try parsing the Close */
694            if (!error) {
695                SMBDEBUG("query smb2_rq_parse_header failed %d, id %lld\n",
696                         tmp_error, query_rqp->sr_messageid);
697                error = tmp_error;
698            }
699            goto parse_close;
700        }
701
702        /* Parse the Query Info response */
703        tmp_error = smb2_smb_parse_query_info(mdp, queryp);
704        if (tmp_error) {
705            /* Query Info parsing got an error, try parsing the Close */
706            if (!error) {
707                if (tmp_error != ENOATTR) {
708                    SMBERROR("smb2_smb_parse_query_info failed %d id %lld\n",
709                             tmp_error, query_rqp->sr_messageid);
710                }
711                error = tmp_error;
712            }
713            goto parse_close;
714        }
715        else {
716            /* Query worked, so get the inode number */
717            if (fap) {
718                fap->fa_ino = inode_number;
719                smb2fs_smb_file_id_check(share, fap->fa_ino, NULL, 0);
720            }
721        }
722    }
723
724parse_close:
725    if (close_rqp != NULL) {
726        /* Update closep fid so it gets freed from FID table */
727        closep->fid = createp->ret_fid;
728
729        /* Consume any pad bytes */
730        tmp_error = smb2_rq_next_command(query_rqp != NULL ? query_rqp : create_rqp,
731                                         &next_cmd_offset, mdp);
732        if (tmp_error) {
733            /* Failed to find next command, so can't parse rest of the responses */
734            SMBERROR("create smb2_rq_next_command failed %d id %lld\n",
735                     tmp_error, create_rqp->sr_messageid);
736            error = error ? error : tmp_error;
737            goto bad;
738        }
739
740        /*
741         * Parse Close SMB 2/3 header
742         */
743        tmp_error = smb2_rq_parse_header(close_rqp, &mdp);
744        closep->ret_ntstatus = close_rqp->sr_ntstatus;
745        if (tmp_error) {
746            if (!error) {
747                SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n",
748                         tmp_error, close_rqp->sr_messageid);
749                error = tmp_error;
750
751                if (ntstatus) {
752                    /* Return NT Status error if they want it */
753                    *ntstatus = closep->ret_ntstatus;
754                }
755            }
756            goto bad;
757        }
758
759        /* Parse the Close response */
760        tmp_error = smb2_smb_parse_close(mdp, closep);
761        if (tmp_error) {
762            if (!error) {
763                SMBERROR("smb2_smb_parse_close failed %d id %lld\n",
764                         tmp_error, close_rqp->sr_messageid);
765                error = tmp_error;
766            }
767            goto bad;
768        }
769
770        /* At this point, fid has been removed from fid table */
771        need_delete_fid = 0;
772    }
773    else {
774        /* Not doing a close, so leave it open */
775        need_delete_fid = 0;
776    }
777
778bad:
779    if (need_delete_fid == 1) {
780        /*
781         * Close failed but the Create worked and was successfully parsed.
782         * Try issuing the Close request again.
783         */
784        tmp_error = smb2_smb_close_fid(share, createp->ret_fid,
785                                       NULL, NULL, context);
786        if (tmp_error) {
787            SMBERROR("Second close failed %d\n", tmp_error);
788        }
789    }
790
791    if (create_rqp != NULL) {
792        smb_rq_done(create_rqp);
793    }
794    if (query_rqp != NULL) {
795        smb_rq_done(query_rqp);
796    }
797    if (close_rqp != NULL) {
798        smb_rq_done(close_rqp);
799    }
800
801    if (createp != NULL) {
802        SMB_FREE(createp, M_SMBTEMP);
803    }
804    if (queryp != NULL) {
805        SMB_FREE(queryp, M_SMBTEMP);
806    }
807    if (closep != NULL) {
808        SMB_FREE(closep, M_SMBTEMP);
809    }
810
811	return error;
812}
813
814static int
815smb2fs_smb_cmpd_create_read(struct smb_share *share, struct smbnode *dnp,
816                            const char *namep, size_t name_len,
817                            const char *snamep, size_t sname_len,
818                            uint32_t desired_access, uio_t uio,
819                            size_t *sizep, uint32_t *max_accessp,
820                            SMBFID *fidp, struct timespec *mtime,
821                            vfs_context_t context)
822{
823	int error, tmp_error;
824    uint32_t disposition;
825    uint32_t share_access;
826    SMBFID fid = 0;
827    struct smbfattr *fap = NULL;
828    struct smb2_create_rq *createp = NULL;
829    struct smb2_rw_rq *readp = NULL;
830    struct smb2_close_rq *closep = NULL;
831	struct smb_rq *create_rqp = NULL;
832	struct smb_rq *read_rqp = NULL;
833	struct smb_rq *close_rqp = NULL;
834	struct mdchain *mdp;
835    size_t next_cmd_offset = 0;
836	user_ssize_t len, resid = 0;
837    user_ssize_t rresid = 0;
838    uint64_t create_flags = SMB2_CREATE_GET_MAX_ACCESS;
839    uint32_t need_delete_fid = 0;
840    int add_close = 0;
841    uint32_t create_options = 0;
842    enum vtype vnode_type = VREG;
843
844    /*
845     * We can only read files, so vnode_type is always VREG
846     * Named streams are always files.
847     */
848
849    /*
850     * This function can do Create/Read or Create/Read/Close
851     * If fidp is NULL, then the Close is added.
852     */
853
854    /*
855     * (1) This is used when dealing with readdirattr for Finder Info
856     * It has a parent dnp, child of namep and stream name of snamep.
857     * (2) This is used for dealing with Finder Info which is an xattr
858     * (ie stream) and assumes the read data will all fit in one read request
859     */
860
861    if (fidp == NULL) {
862        /* If fidp is null, add the close into the compound request */
863        add_close = 1;
864    }
865    else {
866        *fidp = 0;  /* indicates create failed */
867    }
868
869    SMB_MALLOC(fap,
870               struct smbfattr *,
871               sizeof(struct smbfattr),
872               M_SMBTEMP,
873               M_WAITOK | M_ZERO);
874    if (fap == NULL) {
875        SMBERROR("SMB_MALLOC failed\n");
876        error = ENOMEM;
877        goto bad;
878    }
879
880    SMB_MALLOC(readp,
881               struct smb2_rw_rq *,
882               sizeof(struct smb2_rw_rq),
883               M_SMBTEMP,
884               M_WAITOK | M_ZERO);
885    if (readp == NULL) {
886        SMBERROR("SMB_MALLOC failed\n");
887        error = ENOMEM;
888        goto bad;
889    }
890
891    /*
892     * Be careful here. The vnode_type is for the actual item that the
893     * Read is being done on. The path to the item is built from
894     * create_np and namep, but only the calling function knows what the
895     * item type is.
896     */
897
898    /*
899     * Set up for the Create call
900     */
901    if (snamep) {
902        create_flags |= SMB2_CREATE_IS_NAMED_STREAM;
903        /* Named streams are always files */
904        vnode_type = VREG;
905    }
906
907    if (desired_access & SMB2_FILE_WRITE_DATA) {
908		share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_DELETE;
909		disposition = FILE_OPEN_IF;
910	}
911    else {
912		share_access = NTCREATEX_SHARE_ACCESS_ALL;
913		disposition = FILE_OPEN;
914	}
915
916resend:
917    /*
918     * Build the Create call
919     */
920    create_options = smb2fs_smb_get_create_options(share, dnp,
921                                                   namep, snamep,
922                                                   vnode_type, 0);
923    error = smb2fs_smb_ntcreatex(share, dnp,
924                                 namep, name_len,
925                                 snamep, sname_len,
926                                 desired_access, vnode_type,
927                                 share_access, disposition,
928                                 create_flags, create_options,
929                                 &fid, fap,
930                                 &create_rqp, &createp,
931                                 NULL, context);
932    if (error) {
933        SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error);
934        goto bad;
935    }
936
937    /* Update Create hdr */
938    error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST);
939    if (error) {
940        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
941        goto bad;
942    }
943
944    /*
945     * Build the Read request
946     */
947    readp->flags = 0;
948    readp->remaining = 0;
949    readp->write_flags = 0;
950    fid = 0xffffffffffffffff;   /* fid is -1 for compound requests */
951    readp->fid = fid;
952    readp->auio = uio;
953
954    /* assume we can read it all in one request */
955	len = uio_resid(readp->auio);
956
957    error = smb2_smb_read_one(share, readp, &len, &resid, &read_rqp, context);
958    if (error) {
959        SMBERROR("smb2_smb_read_one failed %d\n", error);
960        goto bad;
961    }
962
963    /* Update Read hdr */
964    if (add_close) {
965        error = smb2_rq_update_cmpd_hdr(read_rqp, SMB2_CMPD_MIDDLE);
966    }
967    else {
968        error = smb2_rq_update_cmpd_hdr(read_rqp, SMB2_CMPD_LAST);
969    }
970    if (error) {
971        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
972        goto bad;
973    }
974
975    /* Chain Read to the Create */
976    create_rqp->sr_next_rqp = read_rqp;
977
978    if (add_close) {
979        /*
980         * Build the Close request
981         */
982        error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context);
983        if (error) {
984            SMBERROR("smb2_smb_close_fid failed %d\n", error);
985            goto bad;
986        }
987
988        /* Update Close hdr */
989        error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST);
990        if (error) {
991            SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
992            goto bad;
993        }
994
995        /* Chain Close to the Read */
996        read_rqp->sr_next_rqp = close_rqp;
997    }
998
999    /*
1000     * Send the compound request of Create/Read/Close
1001     */
1002    error = smb_rq_simple(create_rqp);
1003
1004    if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) {
1005        /* Rebuild and try sending again */
1006        smb_rq_done(create_rqp);
1007        create_rqp = NULL;
1008
1009        smb_rq_done(read_rqp);
1010        read_rqp = NULL;
1011
1012        if (close_rqp != NULL) {
1013            smb_rq_done(close_rqp);
1014            close_rqp = NULL;
1015        }
1016
1017        SMB_FREE(createp, M_SMBTEMP);
1018        createp = NULL;
1019
1020        if (closep != NULL) {
1021            SMB_FREE(closep, M_SMBTEMP);
1022            closep = NULL;
1023        }
1024
1025        goto resend;
1026    }
1027
1028    createp->ret_ntstatus = create_rqp->sr_ntstatus;
1029
1030    /* Get pointer to response data */
1031    smb_rq_getreply(create_rqp, &mdp);
1032
1033    if (error) {
1034        /* Create failed, try parsing the Read */
1035        if (error != ENOENT) {
1036            SMBDEBUG("smb_rq_simple failed %d id %lld\n",
1037                     error, create_rqp->sr_messageid);
1038        }
1039
1040        if (fidp) {
1041            *fidp = 0;  /* indicate Create failed */
1042        }
1043        goto parse_read;
1044    }
1045
1046    /*
1047     * Parse the Create response.
1048     */
1049    error = smb2_smb_parse_create(share, mdp, createp);
1050    if (error) {
1051        /* Create parsing failed, try parsing the Read */
1052        SMBERROR("smb2_smb_parse_create failed %d id %lld\n",
1053                 error, create_rqp->sr_messageid);
1054
1055        if (fidp) {
1056            *fidp = 0;  /* indicate Create failed */
1057        }
1058        goto parse_read;
1059    }
1060
1061    /* At this point, fid has been entered into fid table */
1062    need_delete_fid = 1;
1063
1064    /*
1065     * Fill in fap and possibly update vnode's meta data caches
1066     */
1067    error = smb2fs_smb_parse_ntcreatex(share, dnp, createp,
1068                                       fidp, fap, context);
1069    if (error) {
1070        /* Updating meta data cache failed, try parsing the Read */
1071        SMBERROR("smb2fs_smb_parse_ntcreatex failed %d id %lld\n",
1072                 error, create_rqp->sr_messageid);
1073    }
1074    else {
1075        /* Return max access if they want it */
1076        if (max_accessp) {
1077            DBG_ASSERT(fap->fa_valid_mask & FA_MAX_ACCESS_VALID)
1078            *max_accessp = fap->fa_max_access;
1079        }
1080        if (mtime) {
1081            *mtime = fap->fa_mtime;
1082        }
1083    }
1084
1085parse_read:
1086    /* Consume any pad bytes */
1087    tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp);
1088    if (tmp_error) {
1089        /* Failed to find next command, so can't parse rest of the responses */
1090        SMBERROR("create smb2_rq_next_command failed %d id %lld\n",
1091                 tmp_error, create_rqp->sr_messageid);
1092        error = error ? error : tmp_error;
1093        goto bad;
1094    }
1095
1096    /*
1097     * Parse Read SMB 2/3 header
1098     */
1099    tmp_error = smb2_rq_parse_header(read_rqp, &mdp);
1100    readp->ret_ntstatus = read_rqp->sr_ntstatus;
1101
1102    if (tmp_error == ENODATA) {
1103        /*
1104         * Ignore EOF and leave error alone as it could contain an error from
1105         * the create, but skip trying to parse the read data
1106         */
1107        goto parse_close;
1108    }
1109
1110    if (tmp_error) {
1111        /* Read got an error, try parsing the Close */
1112        if (!error) {
1113            SMBDEBUG("read smb2_rq_parse_header failed %d, id %lld\n",
1114                     tmp_error, read_rqp->sr_messageid);
1115            error = tmp_error;
1116        }
1117        goto parse_close;
1118    }
1119
1120    /* Parse the Read response */
1121    tmp_error = smb2_smb_parse_read_one(mdp, &rresid, readp);
1122    if (tmp_error) {
1123        /* Read parsing got an error, try parsing the Close */
1124        if (!error) {
1125            SMBERROR("smb2_smb_parse_read_one failed %d id %lld\n",
1126                     tmp_error, read_rqp->sr_messageid);
1127            error = tmp_error;
1128        }
1129        goto parse_close;
1130    }
1131
1132    if (sizep) {
1133        /*
1134         * *sizep contains the logical size of the stream
1135         * The calling routines can only handle size_t
1136         */
1137        *sizep = fap->fa_size;
1138    }
1139
1140parse_close:
1141    if (close_rqp != NULL) {
1142        /* Update closep fid so it gets freed from FID table */
1143        closep->fid = createp->ret_fid;
1144
1145        /* Consume any pad bytes */
1146        tmp_error = smb2_rq_next_command(read_rqp, &next_cmd_offset, mdp);
1147        if (tmp_error) {
1148            /* Failed to find next command, so can't parse rest of the responses */
1149            SMBERROR("read smb2_rq_next_command failed %d id %lld\n",
1150                     tmp_error, read_rqp->sr_messageid);
1151            error = error ? error : tmp_error;
1152            goto bad;
1153        }
1154
1155        /*
1156         * Parse Close SMB 2/3 header
1157         */
1158        tmp_error = smb2_rq_parse_header(close_rqp, &mdp);
1159        closep->ret_ntstatus = close_rqp->sr_ntstatus;
1160        if (tmp_error) {
1161            if (!error) {
1162                SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n",
1163                         tmp_error, close_rqp->sr_messageid);
1164                error = tmp_error;
1165            }
1166            goto bad;
1167        }
1168
1169        /* Parse the Close response */
1170        tmp_error = smb2_smb_parse_close(mdp, closep);
1171        if (tmp_error) {
1172            if (!error) {
1173                SMBERROR("smb2_smb_parse_close failed %d id %lld\n",
1174                         tmp_error, close_rqp->sr_messageid);
1175                error = tmp_error;
1176            }
1177            goto bad;
1178        }
1179
1180        /* At this point, fid has been removed from fid table */
1181        need_delete_fid = 0;
1182    }
1183    else {
1184        /* Not doing a close, so leave it open */
1185        need_delete_fid = 0;
1186    }
1187
1188bad:
1189    if (need_delete_fid == 1) {
1190        /*
1191         * Close failed but the Create worked and was successfully parsed.
1192         * Try issuing the Close request again.
1193         */
1194        tmp_error = smb2_smb_close_fid(share, createp->ret_fid,
1195                                       NULL, NULL, context);
1196        if (tmp_error) {
1197            SMBERROR("Second close failed %d\n", tmp_error);
1198        }
1199    }
1200
1201    if (create_rqp != NULL) {
1202        smb_rq_done(create_rqp);
1203    }
1204    if (read_rqp != NULL) {
1205        smb_rq_done(read_rqp);
1206    }
1207    if (close_rqp != NULL) {
1208        smb_rq_done(close_rqp);
1209    }
1210
1211    if (createp != NULL) {
1212        SMB_FREE(createp, M_SMBTEMP);
1213    }
1214    if (readp != NULL) {
1215        SMB_FREE(readp, M_SMBTEMP);
1216    }
1217    if (closep != NULL) {
1218        SMB_FREE(closep, M_SMBTEMP);
1219    }
1220
1221    if (fap != NULL) {
1222        SMB_FREE(fap, M_SMBTEMP);
1223    }
1224
1225	return error;
1226}
1227
1228int smbfs_smb_cmpd_create_read_close(struct smb_share *share, struct smbnode *dnp,
1229                                     const char *namep, size_t name_len,
1230                                     const char *snamep, size_t sname_len,
1231                                     uio_t uio, size_t *sizep,
1232                                     uint32_t *max_accessp,
1233                                     vfs_context_t context)
1234{
1235    int error;
1236    SMBFID fid = 0;
1237
1238    /*
1239     * This is only used when dealing with readdirattr for Finder Info
1240     */
1241
1242    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
1243        /* Do a Create/Read/Close */
1244        error = smb2fs_smb_cmpd_create_read(share, dnp,
1245                                            namep, name_len,
1246                                            snamep, sname_len,
1247                                            SMB2_FILE_READ_DATA, uio,
1248                                            sizep, max_accessp,
1249                                            NULL, NULL,
1250                                            context);
1251    }
1252    else {
1253        error = smb1fs_smb_open_read(share, dnp,
1254                                     namep, name_len,
1255                                     snamep, sname_len,
1256                                     &fid, uio, sizep,
1257                                     max_accessp,
1258                                     context);
1259        if (fid) {
1260            (void)smbfs_smb_close(share, fid, context);
1261        }
1262    }
1263
1264    return error;
1265}
1266
1267int
1268smb2fs_smb_cmpd_create_write(struct smb_share *share, struct smbnode *dnp,
1269                             const char *namep, size_t name_len,
1270                             const char *snamep, size_t sname_len,
1271                             uint32_t desired_access, struct smbfattr *fap,
1272                             uint64_t create_flags, uio_t uio,
1273                             SMBFID *fidp, int ioflag,
1274                             vfs_context_t context)
1275{
1276#pragma unused(ioflag)
1277    int error, tmp_error;
1278    uint32_t disposition;
1279    uint32_t share_access;
1280    SMBFID fid = 0;
1281    struct smb2_create_rq *createp = NULL;
1282    struct smb2_query_info_rq *queryp = NULL;
1283    struct smb2_rw_rq *writep = NULL;
1284    struct smb2_close_rq *closep = NULL;
1285    struct smb_rq *create_rqp = NULL;
1286    struct smb_rq *query_rqp = NULL;
1287    struct smb_rq *write_rqp = NULL;
1288    struct smb_rq *close_rqp = NULL;
1289    struct mdchain *mdp;
1290    size_t next_cmd_offset = 0;
1291    user_ssize_t len, resid = 0;
1292    user_ssize_t rresid = 0;
1293    uint32_t need_delete_fid = 0;
1294    int add_query = 0;
1295    int add_close = 0;
1296    uint32_t create_options = 0;
1297    uint32_t write_mode = 0;    /* Never supports write through */
1298    uint64_t inode_number = 0;
1299    uint32_t inode_number_len;
1300
1301    /*
1302     * This function can do Create/Write, Create/Query/Write,
1303     * Create/Write/Close or Create/Query/Write/Close.
1304     *
1305     * If SMB2_CREATE_DO_CREATE is set in create_flags, then the Query is
1306     * added to get the file ID
1307     *
1308     * If fidp is NULL, then the Close is added.
1309     */
1310
1311    if ((create_flags & SMB2_CREATE_DO_CREATE) &&
1312        (SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS)) {
1313        /* Need the file id, so add a query into the compound request */
1314        add_query = 1;
1315    }
1316
1317    if (fidp == NULL) {
1318        /* If fidp is null, add the close into the compound request */
1319        add_close = 1;
1320    }
1321    else {
1322        *fidp = 0;  /* indicates create failed */
1323    }
1324
1325    if (add_query) {
1326        SMB_MALLOC(queryp,
1327                   struct smb2_query_info_rq *,
1328                   sizeof(struct smb2_query_info_rq),
1329                   M_SMBTEMP,
1330                   M_WAITOK | M_ZERO);
1331        if (queryp == NULL) {
1332            SMBERROR("SMB_MALLOC failed\n");
1333            error = ENOMEM;
1334            goto bad;
1335        }
1336    }
1337
1338    SMB_MALLOC(writep,
1339               struct smb2_rw_rq *,
1340               sizeof(struct smb2_rw_rq),
1341               M_SMBTEMP,
1342               M_WAITOK | M_ZERO);
1343    if (writep == NULL) {
1344        SMBERROR("SMB_MALLOC failed\n");
1345        error = ENOMEM;
1346        goto bad;
1347    }
1348
1349    /*
1350     * Set up for the Create call
1351     */
1352    if (snamep) {
1353        create_flags |= SMB2_CREATE_IS_NAMED_STREAM;
1354    }
1355
1356    if (desired_access & SMB2_FILE_WRITE_DATA) {
1357        share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_DELETE;
1358        disposition = FILE_OPEN_IF;
1359    }
1360    else {
1361        share_access = NTCREATEX_SHARE_ACCESS_ALL;
1362        disposition = FILE_OPEN;
1363    }
1364
1365resend:
1366    /*
1367     * Build the Create call
1368     */
1369
1370    create_options = smb2fs_smb_get_create_options(share, dnp,
1371                                                   namep, snamep,
1372                                                   VREG, 0);
1373    error = smb2fs_smb_ntcreatex(share, dnp,
1374                                 namep, name_len,
1375                                 snamep, sname_len,
1376                                 desired_access, VREG,
1377                                 share_access, disposition,
1378                                 create_flags, create_options,
1379                                 &fid, fap,
1380                                 &create_rqp, &createp,
1381                                 NULL, context);
1382    if (error) {
1383        SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error);
1384        goto bad;
1385    }
1386
1387    /* Update Create hdr */
1388    error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST);
1389    if (error) {
1390        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
1391        goto bad;
1392    }
1393
1394    fid = 0xffffffffffffffff;   /* fid is -1 for compound requests */
1395
1396    if (add_query) {
1397        /*
1398         * Build the Query Info request (to get File ID)
1399         */
1400        inode_number_len = (uint32_t) sizeof(inode_number);
1401
1402        queryp->info_type = SMB2_0_INFO_FILE;
1403        queryp->file_info_class = FileInternalInformation;
1404        queryp->add_info = 0;
1405        queryp->flags = 0;
1406        queryp->output_buffer_len = inode_number_len;
1407        queryp->output_buffer = (uint8_t *) &inode_number;
1408        queryp->input_buffer_len = 0;
1409        queryp->input_buffer = NULL;
1410        queryp->ret_buffer_len = 0;
1411        queryp->fid = fid;
1412
1413        error = smb2_smb_query_info(share, queryp, &query_rqp, context);
1414        if (error) {
1415            SMBERROR("smb2_smb_query_info failed %d\n", error);
1416            goto bad;
1417        }
1418
1419        /* Update Query hdr */
1420        error = smb2_rq_update_cmpd_hdr(query_rqp, SMB2_CMPD_MIDDLE);
1421        if (error) {
1422            SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
1423            goto bad;
1424        }
1425
1426        /* Chain Query Info to the Create */
1427        create_rqp->sr_next_rqp = query_rqp;
1428    }
1429
1430    /*
1431     * Build the Write request
1432     */
1433    writep->flags = 0;
1434    writep->remaining = 0;
1435    writep->write_flags = write_mode;
1436    writep->fid = fid;
1437    writep->auio = uio;
1438
1439    /* assume we can write it all in one request */
1440    len = uio_resid(writep->auio);
1441
1442    error = smb2_smb_write_one(share, writep, &len, &resid, &write_rqp, context);
1443    if (error) {
1444        SMBERROR("smb2_smb_write_one failed %d\n", error);
1445        goto bad;
1446    }
1447
1448    /* Manually compound align the write here */
1449    smb2_rq_align8(write_rqp);
1450
1451    /* Update Write hdr */
1452    if (add_close) {
1453        error = smb2_rq_update_cmpd_hdr(write_rqp, SMB2_CMPD_MIDDLE);
1454    }
1455    else {
1456        error = smb2_rq_update_cmpd_hdr(write_rqp, SMB2_CMPD_LAST);
1457    }
1458    if (error) {
1459        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
1460        goto bad;
1461    }
1462
1463    if (add_query) {
1464        /* Chain Write to the Query */
1465        query_rqp->sr_next_rqp = write_rqp;
1466    }
1467    else {
1468        /* Chain Write to the Create */
1469        create_rqp->sr_next_rqp = write_rqp;
1470    }
1471
1472    if (add_close) {
1473        /*
1474         * Build the Close request
1475         */
1476        error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context);
1477        if (error) {
1478            SMBERROR("smb2_smb_close_fid failed %d\n", error);
1479            goto bad;
1480        }
1481
1482        /* Update Close hdr */
1483        error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST);
1484        if (error) {
1485            SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
1486            goto bad;
1487        }
1488
1489        /* Chain Close to the Write */
1490        write_rqp->sr_next_rqp = close_rqp;
1491    }
1492
1493    /*
1494     * Send the compound request of Create/Query/Write/Close
1495     */
1496    error = smb_rq_simple(create_rqp);
1497
1498    if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) {
1499        /* Rebuild and try sending again */
1500        smb_rq_done(create_rqp);
1501        create_rqp = NULL;
1502
1503        if (query_rqp != NULL) {
1504            smb_rq_done(query_rqp);
1505            query_rqp = NULL;
1506        }
1507
1508        smb_rq_done(write_rqp);
1509        write_rqp = NULL;
1510
1511        if (close_rqp != NULL) {
1512            smb_rq_done(close_rqp);
1513            close_rqp = NULL;
1514        }
1515
1516        SMB_FREE(createp, M_SMBTEMP);
1517        createp = NULL;
1518
1519        if (closep != NULL) {
1520            SMB_FREE(closep, M_SMBTEMP);
1521            closep = NULL;
1522        }
1523
1524        goto resend;
1525    }
1526
1527    createp->ret_ntstatus = create_rqp->sr_ntstatus;
1528
1529    /* Get pointer to response data */
1530    smb_rq_getreply(create_rqp, &mdp);
1531
1532    if (error) {
1533        /* Create failed, try parsing the Query */
1534        if (error != ENOENT) {
1535            SMBDEBUG("smb_rq_simple failed %d id %lld\n",
1536                     error, create_rqp->sr_messageid);
1537        }
1538
1539        if (fidp) {
1540            *fidp = 0;  /* indicate Create failed */
1541        }
1542        goto parse_query;
1543    }
1544
1545    /*
1546     * Parse the Create response.
1547     */
1548    error = smb2_smb_parse_create(share, mdp, createp);
1549    if (error) {
1550        /* Create parsing failed, try parsing the Query */
1551        SMBERROR("smb2_smb_parse_create failed %d id %lld\n",
1552                 error, create_rqp->sr_messageid);
1553
1554        if (fidp) {
1555            *fidp = 0;  /* indicate Create failed */
1556        }
1557        goto parse_query;
1558    }
1559
1560    /* At this point, fid has been entered into fid table */
1561    need_delete_fid = 1;
1562
1563    /*
1564     * Fill in fap and possibly update vnode's meta data caches
1565     */
1566    error = smb2fs_smb_parse_ntcreatex(share, dnp, createp,
1567                                       fidp, fap, context);
1568    if (error) {
1569        /* Updating meta data cache failed, try parsing the Query */
1570        SMBERROR("smb2fs_smb_parse_ntcreatex failed %d id %lld\n",
1571                 error, create_rqp->sr_messageid);
1572    }
1573
1574parse_query:
1575    if (query_rqp != NULL) {
1576        /* Consume any pad bytes */
1577        tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp);
1578        if (tmp_error) {
1579            /* Failed to find next command, so can't parse rest of the responses */
1580            SMBERROR("create smb2_rq_next_command failed %d id %lld\n",
1581                     tmp_error, create_rqp->sr_messageid);
1582            error = error ? error : tmp_error;
1583            goto bad;
1584        }
1585
1586        /*
1587         * Parse Query Info SMB 2/3 header
1588         */
1589        tmp_error = smb2_rq_parse_header(query_rqp, &mdp);
1590        queryp->ret_ntstatus = query_rqp->sr_ntstatus;
1591        if (tmp_error) {
1592            /* Query Info got an error, try parsing the Close */
1593            if (!error) {
1594                SMBDEBUG("query smb2_rq_parse_header failed %d, id %lld\n",
1595                         tmp_error, query_rqp->sr_messageid);
1596                error = tmp_error;
1597            }
1598            goto parse_write;
1599        }
1600
1601        /* Parse the Query Info response */
1602        tmp_error = smb2_smb_parse_query_info(mdp, queryp);
1603        if (tmp_error) {
1604            /* Query Info parsing got an error, try parsing the Close */
1605            if (!error) {
1606                if (tmp_error != ENOATTR) {
1607                    SMBERROR("smb2_smb_parse_query_info failed %d id %lld\n",
1608                             tmp_error, query_rqp->sr_messageid);
1609                }
1610                error = tmp_error;
1611            }
1612            goto parse_write;
1613        }
1614        else {
1615            /* Query worked, so get the inode number */
1616            if (fap) {
1617                fap->fa_ino = inode_number;
1618                smb2fs_smb_file_id_check(share, fap->fa_ino, NULL, 0);
1619            }
1620        }
1621    }
1622
1623parse_write:
1624    /* Consume any pad bytes */
1625    tmp_error = smb2_rq_next_command(query_rqp != NULL ? query_rqp : create_rqp,
1626                                     &next_cmd_offset, mdp);
1627    if (tmp_error) {
1628        /* Failed to find next command, so can't parse rest of the responses */
1629        SMBERROR("create smb2_rq_next_command failed %d id %lld\n",
1630                 tmp_error, create_rqp->sr_messageid);
1631        error = error ? error : tmp_error;
1632        goto bad;
1633    }
1634
1635    /*
1636     * Parse Write SMB 2/3 header
1637     */
1638    tmp_error = smb2_rq_parse_header(write_rqp, &mdp);
1639    writep->ret_ntstatus = write_rqp->sr_ntstatus;
1640
1641    if (tmp_error) {
1642        /* Write got an error, try parsing the Close */
1643        if (!error) {
1644            SMBDEBUG("write smb2_rq_parse_header failed %d, id %lld\n",
1645                     tmp_error, write_rqp->sr_messageid);
1646            error = tmp_error;
1647        }
1648        goto parse_close;
1649    }
1650
1651    /* Parse the Write response */
1652    tmp_error = smb2_smb_parse_write_one(mdp, &rresid, writep);
1653    if (tmp_error) {
1654        /* Write parsing got an error, try parsing the Close */
1655        if (!error) {
1656            SMBERROR("smb2_smb_parse_write_one failed %d id %lld\n",
1657                     tmp_error, write_rqp->sr_messageid);
1658            error = tmp_error;
1659        }
1660        goto parse_close;
1661    }
1662
1663parse_close:
1664    if (close_rqp != NULL) {
1665        /* Update closep fid so it gets freed from FID table */
1666        closep->fid = createp->ret_fid;
1667
1668        /* Consume any pad bytes */
1669        tmp_error = smb2_rq_next_command(write_rqp, &next_cmd_offset, mdp);
1670        if (tmp_error) {
1671            /* Failed to find next command, so can't parse rest of the responses */
1672            SMBERROR("write smb2_rq_next_command failed %d id %lld\n",
1673                     tmp_error, write_rqp->sr_messageid);
1674            error = error ? error : tmp_error;
1675            goto bad;
1676        }
1677
1678        /*
1679         * Parse Close SMB 2/3 header
1680         */
1681        tmp_error = smb2_rq_parse_header(close_rqp, &mdp);
1682        closep->ret_ntstatus = close_rqp->sr_ntstatus;
1683        if (tmp_error) {
1684            if (!error) {
1685                SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n",
1686                         tmp_error, close_rqp->sr_messageid);
1687                error = tmp_error;
1688            }
1689            goto bad;
1690        }
1691
1692        /* Parse the Close response */
1693        tmp_error = smb2_smb_parse_close(mdp, closep);
1694        if (tmp_error) {
1695            if (!error) {
1696                SMBERROR("smb2_smb_parse_close failed %d id %lld\n",
1697                         tmp_error, close_rqp->sr_messageid);
1698                error = tmp_error;
1699            }
1700            goto bad;
1701        }
1702
1703        /* At this point, fid has been removed from fid table */
1704        need_delete_fid = 0;
1705    }
1706    else {
1707        /* Not doing a close, so leave it open */
1708        need_delete_fid = 0;
1709    }
1710
1711bad:
1712    if (need_delete_fid == 1) {
1713        /*
1714         * Close failed but the Create worked and was successfully parsed.
1715         * Try issuing the Close request again.
1716         */
1717        tmp_error = smb2_smb_close_fid(share, createp->ret_fid,
1718                                       NULL, NULL, context);
1719        if (tmp_error) {
1720            SMBERROR("Second close failed %d\n", tmp_error);
1721        }
1722    }
1723
1724    if (create_rqp != NULL) {
1725        smb_rq_done(create_rqp);
1726    }
1727    if (query_rqp != NULL) {
1728        smb_rq_done(query_rqp);
1729    }
1730    if (write_rqp != NULL) {
1731        smb_rq_done(write_rqp);
1732    }
1733    if (close_rqp != NULL) {
1734        smb_rq_done(close_rqp);
1735    }
1736
1737    if (createp != NULL) {
1738        SMB_FREE(createp, M_SMBTEMP);
1739    }
1740    if (queryp != NULL) {
1741        SMB_FREE(queryp, M_SMBTEMP);
1742    }
1743    if (writep != NULL) {
1744        SMB_FREE(writep, M_SMBTEMP);
1745    }
1746    if (closep != NULL) {
1747        SMB_FREE(closep, M_SMBTEMP);
1748    }
1749
1750    return error;
1751}
1752
1753static int
1754smb2fs_smb_cmpd_query(struct smb_share *share, struct smbnode *create_np, enum vtype vnode_type,
1755                      const char *create_namep, size_t create_name_len,
1756                      uint32_t create_xattr, uint32_t create_desired_access,
1757                      uint8_t query_info_type, uint8_t query_file_info_class,
1758                      uint32_t query_add_info, uint32_t *max_accessp,
1759                      uint32_t *query_output_buffer_len, uint8_t *query_output_buffer,
1760                      vfs_context_t context)
1761{
1762	int error, tmp_error;
1763    SMBFID fid = 0;
1764    struct smbfattr *fap = NULL;
1765    struct smb2_create_rq *createp = NULL;
1766    struct smb2_query_info_rq *queryp = NULL;
1767    struct smb2_close_rq *closep = NULL;
1768	struct smb_rq *create_rqp = NULL;
1769	struct smb_rq *query_rqp = NULL;
1770	struct smb_rq *close_rqp = NULL;
1771	struct mdchain *mdp;
1772    size_t next_cmd_offset = 0;
1773    uint32_t need_delete_fid = 0;
1774    uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL;
1775    uint64_t create_flags = create_xattr ? SMB2_CREATE_IS_NAMED_STREAM : 0;
1776    char *file_namep = NULL, *stream_namep = NULL;
1777    size_t file_name_len = 0, stream_name_len = 0;
1778    int add_submount_path = 0;
1779    uint32_t create_options = 0;
1780    uint32_t disposition = FILE_OPEN;
1781
1782    /*
1783     * For this function, vnode_type is the item's type. The item will be
1784     * Opened and the Query Info will be done on the item.
1785     */
1786
1787    /*
1788     * Note: Be careful as
1789     * (1) share->ss_mount can be null
1790     * (2) create_np can be null
1791     */
1792
1793    SMB_MALLOC(fap,
1794               struct smbfattr *,
1795               sizeof(struct smbfattr),
1796               M_SMBTEMP,
1797               M_WAITOK | M_ZERO);
1798    if (fap == NULL) {
1799        SMBERROR("SMB_MALLOC failed\n");
1800        error = ENOMEM;
1801        goto bad;
1802    }
1803
1804    SMB_MALLOC(queryp,
1805               struct smb2_query_info_rq *,
1806               sizeof(struct smb2_query_info_rq),
1807               M_SMBTEMP,
1808               M_WAITOK | M_ZERO);
1809    if (queryp == NULL) {
1810        SMBERROR("SMB_MALLOC failed\n");
1811        error = ENOMEM;
1812        goto bad;
1813    }
1814
1815    if ((create_np == NULL) && (create_namep != NULL) &&
1816        ((query_file_info_class == FileFsAttributeInformation) ||
1817         (query_file_info_class == FileFsSizeInformation))) {
1818            /*
1819             * Must be during mount time which means we do not have the root
1820             * vnode yet, but we do have a submount path. Submount path is
1821             * inside the create_namep and already in network form.
1822             */
1823            add_submount_path = 1;
1824        }
1825
1826resend:
1827    /*
1828     * Build the Create call
1829     */
1830    create_flags |= SMB2_CREATE_GET_MAX_ACCESS;
1831
1832    if (add_submount_path == 1) {
1833        create_flags |= SMB2_CREATE_NAME_IS_PATH;
1834    }
1835
1836    /* Should we check to see if the server is OS X based? */
1837    if (!(SSTOVC(share)->vc_misc_flags & (SMBV_OSX_SERVER | SMBV_OTHER_SERVER))) {
1838        if ((create_np != NULL) &&
1839            (create_namep == NULL) &&
1840            (create_xattr == 0) &&
1841            (create_np->n_ino == create_np->n_mount->sm_root_ino)) {
1842            SMBDEBUG("Checking for OS X server \n");
1843            create_flags |= SMB2_CREATE_AAPL_QUERY;
1844        }
1845    }
1846
1847    if (!(create_flags & SMB2_CREATE_IS_NAMED_STREAM)) {
1848        file_namep = (char *) create_namep;
1849        file_name_len = create_name_len;
1850    }
1851    else {
1852        /* create_namep is actually the stream name */
1853        stream_namep = (char *) create_namep;
1854        stream_name_len = create_name_len;
1855    }
1856
1857    /*
1858     * Be careful here. The vnode_type is for the actual item that the
1859     * Query Info is being done on. The path to the item is built from
1860     * create_np and file_namep, but only the calling function knows what the
1861     * item type is.
1862     */
1863    create_options = smb2fs_smb_get_create_options(share, create_np,
1864                                                   file_namep, stream_namep,
1865                                                   vnode_type, 1);
1866    error = smb2fs_smb_ntcreatex(share, create_np,
1867                                 file_namep, file_name_len,
1868                                 stream_namep, stream_name_len,
1869                                 create_desired_access, vnode_type,
1870                                 share_access, disposition,
1871                                 create_flags, create_options,
1872                                 &fid, fap,
1873                                 &create_rqp, &createp,
1874                                 NULL, context);
1875    if (error) {
1876        SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error);
1877        goto bad;
1878    }
1879
1880    if (add_submount_path == 1) {
1881        /* Clear DFS Operation flag that got set */
1882        *create_rqp->sr_flagsp &= ~(htolel(SMB2_FLAGS_DFS_OPERATIONS));
1883    }
1884
1885    /* Update Create hdr */
1886    error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST);
1887    if (error) {
1888        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
1889        goto bad;
1890    }
1891
1892    /*
1893     * Build the Query Info request
1894     */
1895    queryp->info_type = query_info_type;
1896    queryp->file_info_class = query_file_info_class;
1897    queryp->add_info = query_add_info;
1898    queryp->flags = 0;
1899    queryp->output_buffer_len = *query_output_buffer_len;
1900    queryp->output_buffer = query_output_buffer;
1901    queryp->input_buffer_len = 0;
1902    queryp->input_buffer = NULL;
1903    queryp->ret_buffer_len = 0;
1904    fid = 0xffffffffffffffff;   /* fid is -1 for compound requests */
1905    queryp->fid = fid;
1906
1907    error = smb2_smb_query_info(share, queryp, &query_rqp, context);
1908    if (error) {
1909        SMBERROR("smb2_smb_query_info failed %d\n", error);
1910        goto bad;
1911    }
1912
1913    /* Update Query hdr */
1914    error = smb2_rq_update_cmpd_hdr(query_rqp, SMB2_CMPD_MIDDLE);
1915    if (error) {
1916        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
1917        goto bad;
1918    }
1919
1920    /* Chain Query Info to the Create */
1921    create_rqp->sr_next_rqp = query_rqp;
1922
1923    /*
1924     * Build the Close request
1925     */
1926    error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context);
1927    if (error) {
1928        SMBERROR("smb2_smb_close_fid failed %d\n", error);
1929        goto bad;
1930    }
1931
1932    /* Update Close hdr */
1933    error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST);
1934    if (error) {
1935        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
1936        goto bad;
1937    }
1938
1939    /* Chain Close to the Query Info */
1940    query_rqp->sr_next_rqp = close_rqp;
1941
1942    /*
1943     * Send the compound request of Create/Query/Close
1944     */
1945    error = smb_rq_simple(create_rqp);
1946
1947    if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) {
1948        /* Rebuild and try sending again */
1949        smb_rq_done(create_rqp);
1950        create_rqp = NULL;
1951
1952        smb_rq_done(query_rqp);
1953        query_rqp = NULL;
1954
1955        smb_rq_done(close_rqp);
1956        close_rqp = NULL;
1957
1958        SMB_FREE(createp, M_SMBTEMP);
1959        createp = NULL;
1960
1961        SMB_FREE(closep, M_SMBTEMP);
1962        closep = NULL;
1963
1964        goto resend;
1965    }
1966
1967    createp->ret_ntstatus = create_rqp->sr_ntstatus;
1968
1969    /* Get pointer to response data */
1970    smb_rq_getreply(create_rqp, &mdp);
1971
1972    if (error) {
1973        /* Create failed, try parsing the Query Info */
1974        if ((error != ENOENT) && (error != EACCES)) {
1975            SMBDEBUG("smb_rq_simple failed %d id %lld\n",
1976                     error, create_rqp->sr_messageid);
1977        }
1978
1979        /*
1980         * Some servers return an error with the AAPL Create context instead
1981         * of just ignoring the context like it says in the MS-SMB doc.
1982         * Obviously must be a non OS X Server.
1983         */
1984        if (createp->flags & SMB2_CREATE_AAPL_QUERY) {
1985            SMBDEBUG("Found a NON OS X server\n");
1986            SSTOVC(share)->vc_misc_flags |= SMBV_OTHER_SERVER;
1987        }
1988
1989        goto parse_query;
1990    }
1991
1992    /*
1993     * Parse the Create response.
1994     */
1995    error = smb2_smb_parse_create(share, mdp, createp);
1996    if (error) {
1997        /* Create parsing failed, try parsing the Query Info */
1998        SMBERROR("smb2_smb_parse_create failed %d id %lld\n",
1999                 error, create_rqp->sr_messageid);
2000        goto parse_query;
2001    }
2002
2003    /* At this point, fid has been entered into fid table */
2004    need_delete_fid = 1;
2005
2006    /*
2007     * Fill in fap and possibly update vnode's meta data caches
2008     */
2009    error = smb2fs_smb_parse_ntcreatex(share, create_np, createp,
2010                                       &fid, fap, context);
2011    if (error) {
2012        /* Updating meta data cache failed, try parsing the Query Info */
2013        SMBERROR("smb2fs_smb_parse_ntcreatex failed %d id %lld\n",
2014                 error, create_rqp->sr_messageid);
2015    }
2016    else {
2017        /* Return max access if they want it */
2018        if (max_accessp) {
2019            DBG_ASSERT(fap->fa_valid_mask & FA_MAX_ACCESS_VALID)
2020            *max_accessp = fap->fa_max_access;
2021        }
2022    }
2023
2024parse_query:
2025    /* Consume any pad bytes */
2026    tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp);
2027    if (tmp_error) {
2028        /* Failed to find next command, so can't parse rest of the responses */
2029        SMBERROR("create smb2_rq_next_command failed %d id %lld\n",
2030                 tmp_error, create_rqp->sr_messageid);
2031        error = error ? error : tmp_error;
2032        goto bad;
2033    }
2034
2035    /*
2036     * Parse Query Info SMB 2/3 header
2037     */
2038    tmp_error = smb2_rq_parse_header(query_rqp, &mdp);
2039    queryp->ret_ntstatus = query_rqp->sr_ntstatus;
2040    if (tmp_error) {
2041        /* Query Info got an error, try parsing the Close */
2042        if (!error) {
2043            SMBDEBUG("query smb2_rq_parse_header failed %d, id %lld\n",
2044                     tmp_error, query_rqp->sr_messageid);
2045            error = tmp_error;
2046        }
2047        goto parse_close;
2048    }
2049
2050    /* Parse the Query Info response */
2051    tmp_error = smb2_smb_parse_query_info(mdp, queryp);
2052    if (tmp_error) {
2053        /* Query Info parsing got an error, try parsing the Close */
2054        if (!error) {
2055            if (tmp_error != ENOATTR) {
2056                SMBERROR("smb2_smb_parse_query_info failed %d id %lld\n",
2057                         tmp_error, query_rqp->sr_messageid);
2058            }
2059            error = tmp_error;
2060        }
2061        goto parse_close;
2062    }
2063    else {
2064        *query_output_buffer_len = queryp->ret_buffer_len;
2065    }
2066
2067parse_close:
2068    /* Update closep fid so it gets freed from FID table */
2069    closep->fid = createp->ret_fid;
2070
2071    /* Consume any pad bytes */
2072    tmp_error = smb2_rq_next_command(query_rqp, &next_cmd_offset, mdp);
2073    if (tmp_error) {
2074        /* Failed to find next command, so can't parse rest of the responses */
2075        SMBERROR("query smb2_rq_next_command failed %d\n", tmp_error);
2076        error = error ? error : tmp_error;
2077        goto bad;
2078    }
2079
2080    /*
2081     * Parse Close SMB 2/3 header
2082     */
2083    tmp_error = smb2_rq_parse_header(close_rqp, &mdp);
2084    closep->ret_ntstatus = close_rqp->sr_ntstatus;
2085    if (tmp_error) {
2086        /* Close got an error */
2087        if (!error) {
2088            SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n",
2089                     tmp_error, close_rqp->sr_messageid);
2090            error = tmp_error;
2091        }
2092        goto bad;
2093    }
2094
2095    /* Parse the Close response */
2096    tmp_error = smb2_smb_parse_close(mdp, closep);
2097    if (tmp_error) {
2098        /* Close parsing got an error */
2099        if (!error) {
2100            SMBERROR("smb2_smb_parse_close failed %d id %lld\n",
2101                     tmp_error, close_rqp->sr_messageid);
2102            error = tmp_error;
2103        }
2104        goto bad;
2105    }
2106
2107    /* At this point, fid has been removed from fid table */
2108    need_delete_fid = 0;
2109
2110bad:
2111    if (need_delete_fid == 1) {
2112        /*
2113         * Close failed but the Create worked and was successfully parsed.
2114         * Try issuing the Close request again.
2115         */
2116        tmp_error = smb2_smb_close_fid(share, createp->ret_fid,
2117                                       NULL, NULL, context);
2118        if (tmp_error) {
2119            SMBERROR("Second close failed %d\n", tmp_error);
2120        }
2121    }
2122
2123    if (create_rqp != NULL) {
2124        smb_rq_done(create_rqp);
2125    }
2126    if (query_rqp != NULL) {
2127        smb_rq_done(query_rqp);
2128    }
2129    if (close_rqp != NULL) {
2130        smb_rq_done(close_rqp);
2131    }
2132
2133    if (createp != NULL) {
2134        SMB_FREE(createp, M_SMBTEMP);
2135    }
2136    if (queryp != NULL) {
2137        SMB_FREE(queryp, M_SMBTEMP);
2138    }
2139    if (closep != NULL) {
2140        SMB_FREE(closep, M_SMBTEMP);
2141    }
2142
2143    if (fap != NULL) {
2144        SMB_FREE(fap, M_SMBTEMP);
2145    }
2146
2147	return error;
2148}
2149
2150static int
2151smb2fs_smb_cmpd_query_dir(struct smbfs_fctx *ctx,
2152                          struct smb2_query_dir_rq *queryp,
2153                          vfs_context_t context)
2154{
2155    int error, tmp_error;
2156	struct mdchain *mdp;
2157    size_t next_cmd_offset = 0;
2158	struct smb_rq *create_rqp = NULL;
2159	struct smb_rq *query_rqp = NULL;
2160    struct smb2_create_rq *createp = NULL;
2161    struct smbnode *create_np;
2162    uint32_t desired_access = SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_LIST_DIRECTORY | SMB2_SYNCHRONIZE;
2163    uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL;
2164    uint64_t create_flags = 0;
2165    uint32_t create_options = 0;
2166    uint32_t disposition = FILE_OPEN;
2167    enum vtype vnode_type = VDIR;
2168    int n_parent_locked = 0;
2169
2170    /*
2171     * For this function, vnode_type is VDIR as the Open will be done on the
2172     * parent dir and then the Query Dir will be done on that directory.
2173     */
2174
2175    /*
2176     * SMB 2/3 searches do not want any paths (ie no '\') in the search
2177     * pattern so we have to open the actual dir that we are going to
2178     * search.
2179     *
2180     * Get the FID for the dir we are going to search
2181     */
2182    if (ctx->f_lookupName == NULL) {
2183        /*
2184         * No name, open the parent of dnp, search pattern will
2185         * be dnp->n_name
2186         */
2187        lck_rw_lock_shared(&ctx->f_dnp->n_parent_rwlock);
2188        n_parent_locked = 1;
2189
2190        if (ctx->f_dnp->n_parent == NULL) {
2191            SMBERROR("Looking for dnp->n_name, but f_dnp->n_parent is NULL\n");
2192            error = ENOENT;
2193            goto bad;
2194        }
2195        create_np = ctx->f_dnp->n_parent;
2196    }
2197    else {
2198        /*
2199         * Have a name, so just open dnp and search pattern will
2200         * be ctx->f_lookupName
2201         */
2202        create_np = ctx->f_dnp;
2203    }
2204
2205resend:
2206    /*
2207     * Build the Create call
2208     */
2209
2210    /* fid is -1 for compound requests */
2211    ctx->f_create_fid = 0xffffffffffffffff;
2212
2213    create_options = smb2fs_smb_get_create_options(ctx->f_share, create_np,
2214                                                   NULL, NULL,
2215                                                   vnode_type, 0);
2216    error = smb2fs_smb_ntcreatex(ctx->f_share, create_np,
2217                                 NULL, 0,
2218                                 NULL, 0,
2219                                 desired_access, vnode_type,
2220                                 share_access, disposition,
2221                                 create_flags, create_options,
2222                                 &ctx->f_create_fid, NULL,
2223                                 &create_rqp, &createp,
2224                                 NULL, context);
2225    if (error) {
2226        SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error);
2227        goto bad;
2228    }
2229
2230    /* Update Create hdr */
2231    error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST);
2232    if (error) {
2233        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
2234        goto bad;
2235    }
2236
2237    /* Create the Query Dir */
2238    error = smb2_smb_query_dir(ctx->f_share, queryp, &query_rqp, context);
2239    if (error) {
2240        SMBERROR("smb2_smb_query_dir failed %d\n", error);
2241        goto bad;
2242    }
2243
2244    /* Update Query Hdr */
2245    error = smb2_rq_update_cmpd_hdr(query_rqp, SMB2_CMPD_LAST);
2246    if (error) {
2247        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
2248        goto bad;
2249    }
2250
2251    /* Chain Query Dir to the Create */
2252    create_rqp->sr_next_rqp = query_rqp;
2253
2254    /*
2255     * Send the compound request of Create/Query Dir
2256     */
2257    error = smb_rq_simple(create_rqp);
2258
2259    if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) {
2260        /* Rebuild and try sending again */
2261        smb_rq_done(create_rqp);
2262        create_rqp = NULL;
2263
2264        smb_rq_done(query_rqp);
2265        query_rqp = NULL;
2266
2267        SMB_FREE(createp, M_SMBTEMP);
2268        createp = NULL;
2269
2270        goto resend;
2271    }
2272
2273    createp->ret_ntstatus = create_rqp->sr_ntstatus;
2274
2275    /* Get pointer to response data */
2276    smb_rq_getreply(create_rqp, &mdp);
2277
2278    if (error) {
2279        /* Create failed, try parsing the Query Dir */
2280        if (error != ENOENT) {
2281            SMBDEBUG("smb_rq_simple failed %d id %lld\n",
2282                     error, create_rqp->sr_messageid);
2283        }
2284        goto parse_query;
2285    }
2286
2287    /*
2288     * Parse the Create response.
2289     */
2290    error = smb2_smb_parse_create(ctx->f_share, mdp, createp);
2291    if (error) {
2292        /* Create parsing failed, try parsing the Query Dir */
2293        SMBERROR("smb2_smb_parse_create failed %d id %lld\n",
2294                 error, create_rqp->sr_messageid);
2295        goto parse_query;
2296    }
2297
2298    /*
2299     * No need to call smb2fs_smb_parse_ntcreatex since this is Query Dir and
2300     * the only vnode we have is the parent dir being searched.
2301     */
2302
2303    /* At this point, the dir was successfully opened */
2304    ctx->f_need_close = TRUE;
2305    ctx->f_create_fid = createp->ret_fid;
2306
2307parse_query:
2308    /* Consume any pad bytes */
2309    tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp);
2310    if (tmp_error) {
2311        /* Failed to find next command, so can't parse rest of the responses */
2312        SMBERROR("create smb2_rq_next_command failed %d id %lld\n",
2313                 tmp_error, create_rqp->sr_messageid);
2314        error = error ? error : tmp_error;
2315        goto bad;
2316    }
2317
2318    /*
2319     * Parse Query Dir SMB 2/3 header
2320     */
2321    tmp_error = smb2_rq_parse_header(query_rqp, &mdp);
2322    queryp->ret_ntstatus = query_rqp->sr_ntstatus;
2323    if (tmp_error) {
2324        /* Query Dir got an error */
2325        if (!error) {
2326            if (tmp_error != ENOENT) {
2327                SMBDEBUG("query smb2_rq_parse_header failed %d, id %lld\n",
2328                         tmp_error, query_rqp->sr_messageid);
2329            }
2330            error = tmp_error;
2331        }
2332        goto bad;
2333    }
2334
2335    /* Parse the Query Dir response */
2336    tmp_error = smb2_smb_parse_query_dir(mdp, queryp);
2337    if (tmp_error) {
2338        /* Query Dir parsing got an error */
2339        if (!error) {
2340            SMBERROR("smb2_smb_parse_query_dir failed %d id %lld\n",
2341                     tmp_error, query_rqp->sr_messageid);
2342            error = tmp_error;
2343        }
2344        goto bad;
2345    }
2346
2347bad:
2348    ctx->f_create_rqp = create_rqp;   /* save rqp so it can be freed later */
2349    ctx->f_query_rqp = query_rqp;     /* save rqp so it can be freed later */
2350
2351    if (n_parent_locked) {
2352        lck_rw_unlock_shared(&ctx->f_dnp->n_parent_rwlock);
2353    }
2354
2355    if (createp != NULL) {
2356        SMB_FREE(createp, M_SMBTEMP);
2357    }
2358
2359    return error;
2360}
2361
2362int
2363smb2fs_smb_cmpd_query_dir_one(struct smb_share *share, struct smbnode *np,
2364                              const char *query_namep, size_t query_name_len,
2365                              struct smbfattr *fap, char **namep, size_t *name_lenp,
2366                              vfs_context_t context)
2367{
2368	int error, tmp_error;
2369    uint16_t info_level;
2370    uint8_t info_class, flags;
2371    SMBFID fid = 0;
2372    struct smb2_create_rq *createp = NULL;
2373    struct smb2_query_dir_rq *queryp = NULL;
2374    struct smb2_close_rq *closep = NULL;
2375	struct smb_rq *create_rqp = NULL;
2376	struct smb_rq *query_rqp = NULL;
2377	struct smb_rq *close_rqp = NULL;
2378	struct mdchain *mdp;
2379    size_t next_cmd_offset = 0;
2380    uint32_t need_delete_fid = 0;
2381    uint32_t desired_access = SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_LIST_DIRECTORY | SMB2_SYNCHRONIZE;
2382    uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL;
2383    uint64_t create_flags = 0;
2384    char *network_name = NULL;
2385    uint32_t network_name_len = 0;
2386    char *local_name = NULL;
2387    size_t local_name_len = 0;
2388    size_t max_network_name_buffer_size = 0;
2389    struct smbmount *smp;
2390    uint32_t create_options = 0;
2391    uint32_t disposition = FILE_OPEN;
2392    enum vtype vnode_type = VDIR;
2393    char *tmp_namep = NULL;
2394    int n_parent_locked = 0;
2395
2396    /*
2397     * For this function, vnode_type is VDIR as the Open will be done on the
2398     * parent dir and then the Query Dir will be done on that directory.
2399     */
2400
2401    smp = np->n_mount;
2402	if ((np->n_ino == smp->sm_root_ino) && (query_namep == NULL)) {
2403        /*
2404         * For the root vnode, we just need limited info, so a Create/Close
2405         * will work. Cant do a Create/Query Dir/Close on the root vnode since
2406         * we have no parent to do the Create on.
2407         */
2408        fap->fa_ino = smp->sm_root_ino; /* default value */
2409
2410        /* Add SMB2_CREATE_DO_CREATE to get the root vnode'd File ID */
2411        create_flags = SMB2_CREATE_GET_MAX_ACCESS | SMB2_CREATE_DO_CREATE;
2412
2413        error = smb2fs_smb_cmpd_create(share, np,
2414                                       NULL, 0,
2415                                       NULL, 0,
2416                                       SMB2_FILE_READ_ATTRIBUTES | SMB2_SYNCHRONIZE, VDIR,
2417                                       NTCREATEX_SHARE_ACCESS_ALL, FILE_OPEN,
2418                                       create_flags, NULL,
2419                                       NULL, fap,
2420                                       NULL, context);
2421        if (!error) {
2422            fap->fa_attr = SMB_EFA_DIRECTORY;
2423            fap->fa_vtype = VDIR;
2424            fap->fa_valid_mask |= FA_VTYPE_VALID;
2425        }
2426
2427        return (error);
2428    }
2429
2430    /*
2431	 * Unicode requires 4 * max file name len, codepage requires 3 * max file
2432	 * name, so lets just always use the unicode size.
2433	 */
2434	max_network_name_buffer_size = share->ss_maxfilenamelen * 4;
2435	SMB_MALLOC(network_name, char *, max_network_name_buffer_size, M_TEMP,
2436               M_WAITOK | M_ZERO);
2437	if (network_name == NULL) {
2438        SMBERROR("network_name malloc failed\n");
2439		error = ENOMEM;
2440        goto bad;
2441    }
2442
2443    fid = 0xffffffffffffffff;   /* fid is -1 for compound requests */
2444
2445    info_level = SMB_FIND_BOTH_DIRECTORY_INFO;
2446
2447    /*
2448     * Set up for the Query Dir call
2449     */
2450    SMB_MALLOC(queryp,
2451               struct smb2_query_dir_rq *,
2452               sizeof(struct smb2_query_dir_rq),
2453               M_SMBTEMP,
2454               M_WAITOK | M_ZERO);
2455    if (queryp == NULL) {
2456        SMBERROR("SMB_MALLOC failed\n");
2457        error = ENOMEM;
2458        goto bad;
2459    }
2460
2461    /* Just want first search entry returned and start from beginning */
2462    flags = SMB2_RETURN_SINGLE_ENTRY | SMB2_RESTART_SCANS;
2463
2464    switch (info_level) {
2465        case SMB_FIND_FULL_DIRECTORY_INFO:
2466            /* For SMB 2/3, get the file/dir IDs too but no short names */
2467            info_class = FileIdFullDirectoryInformation;
2468            break;
2469
2470        case SMB_FIND_BOTH_DIRECTORY_INFO:
2471            /* For SMB 2/3, get the file/dir IDs too */
2472            info_class = FileIdBothDirectoryInformation;
2473            break;
2474
2475        default:
2476            SMBERROR("invalid infolevel %d", info_level);
2477            error = EINVAL;
2478            goto bad;
2479    }
2480
2481    queryp->file_info_class = info_class;
2482    queryp->flags = flags;
2483    queryp->file_index = 0;             /* no FileIndex from prev search */
2484    queryp->fid = fid;
2485    queryp->output_buffer_len = 64 * 1024;  /* 64K should be large enough */
2486
2487    /*
2488     * Not a wildcard, so use UTF_SFM_CONVERSIONS
2489     */
2490    queryp->name_flags = UTF_SFM_CONVERSIONS;
2491
2492    if (query_namep != NULL) {
2493        /* We have a dnp and a name to search for in that dir */
2494        queryp->dnp = np;
2495        queryp->namep = (char*) query_namep;
2496        queryp->name_len = (uint32_t) query_name_len;
2497    }
2498    else {
2499        /*
2500         * We are looking for np, so use np->n_parent and np->n_name
2501         */
2502        lck_rw_lock_shared(&np->n_parent_rwlock);
2503        n_parent_locked = 1;
2504
2505        queryp->dnp = np->n_parent;
2506
2507        if (queryp->dnp == NULL) {
2508            /* This could happen during a forced unmount */
2509            SMBERROR("Looking for np, but np->n_parent is NULL\n");
2510            error = ENOENT;
2511            goto bad;
2512
2513        }
2514
2515        lck_rw_lock_shared(&np->n_name_rwlock);
2516        tmp_namep = smb_strndup(np->n_name, np->n_nmlen);
2517        queryp->namep = tmp_namep;
2518        lck_rw_unlock_shared(&np->n_name_rwlock);
2519
2520        queryp->name_len = (uint32_t) np->n_nmlen;
2521    }
2522
2523resend:
2524    /*
2525     * Build the Create call
2526     */
2527    DBG_ASSERT (vnode_vtype(queryp->dnp->n_vnode) == VDIR);
2528
2529    create_options = smb2fs_smb_get_create_options(share, queryp->dnp,
2530                                                   NULL, NULL,
2531                                                   vnode_type, 0);
2532    error = smb2fs_smb_ntcreatex(share, queryp->dnp,
2533                                 NULL, 0,
2534                                 NULL, 0,
2535                                 desired_access, vnode_type,
2536                                 share_access, disposition,
2537                                 create_flags, create_options,
2538                                 &fid, NULL,
2539                                 &create_rqp, &createp,
2540                                 NULL, context);
2541    if (error) {
2542        SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error);
2543        goto bad;
2544    }
2545
2546    /* Update Create hdr */
2547    error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST);
2548    if (error) {
2549        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
2550        goto bad;
2551    }
2552
2553    /*
2554     * Build the Query Dir request
2555     */
2556    error = smb2_smb_query_dir(share, queryp, &query_rqp, context);
2557    if (error) {
2558        SMBERROR("smb2_smb_query_dir failed %d\n", error);
2559        goto bad;
2560    }
2561
2562    /* Update Query Hdr */
2563    error = smb2_rq_update_cmpd_hdr(query_rqp, SMB2_CMPD_MIDDLE);
2564    if (error) {
2565        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
2566        goto bad;
2567    }
2568
2569    /* Chain Query Dir to the Create */
2570    create_rqp->sr_next_rqp = query_rqp;
2571
2572    /*
2573     * Build the Close request
2574     */
2575    error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context);
2576    if (error) {
2577        SMBERROR("smb2_smb_close_fid failed %d\n", error);
2578        goto bad;
2579    }
2580
2581    /* Update Close hdr */
2582    error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST);
2583    if (error) {
2584        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
2585        goto bad;
2586    }
2587
2588    /* Chain Close to the Query Info */
2589    query_rqp->sr_next_rqp = close_rqp;
2590
2591    /*
2592     * Send the compound request of Create/QueryDir/Close
2593     */
2594    error = smb_rq_simple(create_rqp);
2595
2596    if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) {
2597        /* Rebuild and try sending again */
2598        smb_rq_done(create_rqp);
2599        create_rqp = NULL;
2600
2601        smb_rq_done(query_rqp);
2602        query_rqp = NULL;
2603
2604        smb_rq_done(close_rqp);
2605        close_rqp = NULL;
2606
2607        SMB_FREE(createp, M_SMBTEMP);
2608        createp = NULL;
2609
2610        SMB_FREE(closep, M_SMBTEMP);
2611        closep = NULL;
2612
2613        goto resend;
2614    }
2615
2616    createp->ret_ntstatus = create_rqp->sr_ntstatus;
2617
2618    /* Get pointer to response data */
2619    smb_rq_getreply(create_rqp, &mdp);
2620
2621    if (error) {
2622        /* Create failed, try parsing the Query Dir */
2623        if ((error != ENOENT) && (error != EACCES)) {
2624            SMBDEBUG("smb_rq_simple failed %d id %lld\n",
2625                     error, create_rqp->sr_messageid);
2626        }
2627        goto parse_query;
2628    }
2629
2630    /*
2631     * Parse the Create response.
2632     */
2633    error = smb2_smb_parse_create(share, mdp, createp);
2634    if (error) {
2635        /* Create parsing failed, try parsing the Query Dir */
2636        SMBERROR("smb2_smb_parse_create failed %d id %lld\n",
2637                 error, create_rqp->sr_messageid);
2638        goto parse_query;
2639    }
2640
2641    /* At this point, fid has been entered into fid table */
2642    need_delete_fid = 1;
2643
2644    /*
2645     * No need to call smb2fs_smb_parse_ntcreatex since this is Query Dir and
2646     * the only vnode we have is the parent dir being searched.
2647     */
2648
2649parse_query:
2650    /* Consume any pad bytes */
2651    tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp);
2652    if (tmp_error) {
2653        /* Failed to find next command, so can't parse rest of the responses */
2654        SMBERROR("create smb2_rq_next_command failed %d id %lld\n",
2655                 tmp_error, create_rqp->sr_messageid);
2656        error = error ? error : tmp_error;
2657        goto bad;
2658    }
2659
2660    /*
2661     * Parse Query Dir SMB 2/3 header
2662     */
2663    tmp_error = smb2_rq_parse_header(query_rqp, &mdp);
2664    queryp->ret_ntstatus = query_rqp->sr_ntstatus;
2665    if (tmp_error) {
2666        /* Query Dir got an error */
2667        if (!error) {
2668            if (tmp_error != ENOENT) {
2669                SMBDEBUG("query smb2_rq_parse_header failed %d, id %lld\n",
2670                         tmp_error, query_rqp->sr_messageid);
2671            }
2672            error = tmp_error;
2673        }
2674        goto parse_close;
2675    }
2676
2677    /* Parse the Query Dir response */
2678    tmp_error = smb2_smb_parse_query_dir(mdp, queryp);
2679    if (tmp_error) {
2680        /* Query Dir parsing got an error */
2681        if (!error) {
2682            SMBERROR("smb2_smb_parse_query_dir failed %d id %lld\n",
2683                     tmp_error, query_rqp->sr_messageid);
2684            error = tmp_error;
2685        }
2686        goto parse_close;
2687    }
2688
2689    /*
2690     * Parse the only entry out of the output buffer
2691     */
2692	switch (queryp->file_info_class) {
2693        case FileIdFullDirectoryInformation:
2694        case FileIdBothDirectoryInformation:
2695            /* Call the parsing function */
2696            tmp_error = smb2_smb_parse_query_dir_both_dir_info(share, mdp,
2697                                                               info_level,
2698                                                               NULL, fap,
2699                                                               network_name, &network_name_len,
2700                                                               max_network_name_buffer_size);
2701            if (tmp_error) {
2702                /* Query Dir parsing got an error */
2703                if (!error) {
2704                    SMBERROR("smb2_smb_parse_query_dir_both_dir_info failed %d id %lld\n",
2705                             tmp_error, query_rqp->sr_messageid);
2706                    error = tmp_error;
2707                }
2708                goto parse_close;
2709            }
2710
2711            /*
2712             * Convert network name to a malloc'd local name and return
2713             * that name
2714             */
2715            local_name_len = network_name_len;
2716            local_name = smbfs_ntwrkname_tolocal(network_name, &local_name_len,
2717                                                 SMB_UNICODE_STRINGS(SSTOVC(share)));
2718
2719            if (!(SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS)) {
2720                /* Server does not support File IDs */
2721                fap->fa_ino = smbfs_getino(np, local_name, local_name_len);
2722            }
2723
2724            /* Return the malloc'd name from the server */
2725            if (namep) {
2726                *namep = local_name;
2727                local_name = NULL;
2728            }
2729
2730            if (name_lenp) {
2731                *name_lenp = local_name_len;
2732            }
2733
2734            break;
2735
2736        default:
2737            if (!error) {
2738                SMBERROR("unexpected info level %d\n", queryp->file_info_class);
2739                error = EINVAL;
2740            }
2741            goto parse_close;
2742	}
2743
2744parse_close:
2745    /* Update closep fid so it gets freed from FID table */
2746    closep->fid = createp->ret_fid;
2747
2748    /* Consume any pad bytes */
2749    tmp_error = smb2_rq_next_command(query_rqp, &next_cmd_offset, mdp);
2750    if (tmp_error) {
2751        /* Failed to find next command, so can't parse rest of the responses */
2752        SMBERROR("query smb2_rq_next_command failed %d\n", tmp_error);
2753        error = error ? error : tmp_error;
2754        goto bad;
2755    }
2756
2757    /*
2758     * Parse Close SMB 2/3 header
2759     */
2760    tmp_error = smb2_rq_parse_header(close_rqp, &mdp);
2761    closep->ret_ntstatus = close_rqp->sr_ntstatus;
2762    if (tmp_error) {
2763        /* Close got an error */
2764        if (!error) {
2765            SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n",
2766                     tmp_error, close_rqp->sr_messageid);
2767            error = tmp_error;
2768        }
2769        goto bad;
2770    }
2771
2772    /* Parse the Close response */
2773    tmp_error = smb2_smb_parse_close(mdp, closep);
2774    if (tmp_error) {
2775        /* Close parsing got an error */
2776        if (!error) {
2777            SMBERROR("smb2_smb_parse_close failed %d id %lld\n",
2778                     tmp_error, close_rqp->sr_messageid);
2779            error = tmp_error;
2780        }
2781        goto bad;
2782    }
2783
2784    /* At this point, fid has been removed from fid table */
2785    need_delete_fid = 0;
2786
2787bad:
2788    if (need_delete_fid == 1) {
2789        /*
2790         * Close failed but the Create worked and was successfully parsed.
2791         * Try issuing the Close request again.
2792         */
2793        tmp_error = smb2_smb_close_fid(share, createp->ret_fid,
2794                                       NULL, NULL, context);
2795        if (tmp_error) {
2796            SMBERROR("Second close failed %d\n", tmp_error);
2797        }
2798    }
2799
2800    if (tmp_namep) {
2801        SMB_FREE(tmp_namep, M_SMBSTR);
2802    }
2803
2804    if (n_parent_locked) {
2805        lck_rw_unlock_shared(&np->n_parent_rwlock);
2806    }
2807
2808    if (create_rqp != NULL) {
2809        smb_rq_done(create_rqp);
2810    }
2811    if (query_rqp != NULL) {
2812        smb_rq_done(query_rqp);
2813    }
2814    if (close_rqp != NULL) {
2815        smb_rq_done(close_rqp);
2816    }
2817
2818    if (createp != NULL) {
2819        SMB_FREE(createp, M_SMBTEMP);
2820    }
2821    if (queryp != NULL) {
2822        SMB_FREE(queryp, M_SMBTEMP);
2823    }
2824    if (closep != NULL) {
2825        SMB_FREE(closep, M_SMBTEMP);
2826    }
2827
2828    if (network_name != NULL) {
2829        SMB_FREE(network_name, M_SMBTEMP);
2830    }
2831    if (local_name != NULL) {
2832        SMB_FREE(local_name, M_SMBTEMP);
2833    }
2834
2835	return error;
2836}
2837
2838static int
2839smb2fs_smb_cmpd_reparse_point_get(struct smb_share *share,
2840                                  struct smbnode *create_np,
2841                                  struct uio *ioctl_uiop,
2842                                  vfs_context_t context)
2843{
2844	int error, tmp_error;
2845    SMBFID fid = 0;
2846    struct smbfattr *fap = NULL;
2847    struct smb2_create_rq *createp = NULL;
2848    struct smb2_ioctl_rq *ioctlp = NULL;
2849    struct smb2_close_rq *closep = NULL;
2850	struct smb_rq *create_rqp = NULL;
2851	struct smb_rq *ioctl_rqp = NULL;
2852	struct smb_rq *close_rqp = NULL;
2853	struct mdchain *mdp;
2854    size_t next_cmd_offset = 0;
2855    uint32_t need_delete_fid = 0;
2856    uint32_t create_desired_access = SMB2_FILE_READ_DATA |
2857                                     SMB2_FILE_READ_ATTRIBUTES;
2858    uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL;
2859    uint64_t create_flags = SMB2_CREATE_GET_MAX_ACCESS;
2860    uint32_t create_options = 0;
2861    uint32_t disposition = FILE_OPEN;
2862    enum vtype vnode_type = VREG;
2863
2864    /*
2865     * For this function, vnode_type is VREG as the Open will be done on the
2866     * reparse point and then the Ioctl will be done on the reparse point.
2867     */
2868
2869    SMB_MALLOC(fap,
2870               struct smbfattr *,
2871               sizeof(struct smbfattr),
2872               M_SMBTEMP,
2873               M_WAITOK | M_ZERO);
2874    if (fap == NULL) {
2875        SMBERROR("SMB_MALLOC failed\n");
2876        error = ENOMEM;
2877        goto bad;
2878    }
2879
2880    SMB_MALLOC(ioctlp,
2881               struct smb2_ioctl_rq *,
2882               sizeof(struct smb2_ioctl_rq),
2883               M_SMBTEMP,
2884               M_WAITOK | M_ZERO);
2885    if (ioctlp == NULL) {
2886		SMBERROR("SMB_MALLOC failed\n");
2887        error = ENOMEM;
2888        goto bad;
2889    }
2890
2891resend:
2892    /*
2893     * Build the Create call
2894     */
2895    create_options = smb2fs_smb_get_create_options(share, create_np,
2896                                                   NULL, NULL,
2897                                                   vnode_type, 1);
2898    error = smb2fs_smb_ntcreatex(share, create_np,
2899                                 NULL, 0,
2900                                 NULL, 0,
2901                                 create_desired_access, vnode_type,
2902                                 share_access, disposition,
2903                                 create_flags, create_options,
2904                                 &fid, NULL,
2905                                 &create_rqp, &createp,
2906                                 NULL, context);
2907    if (error) {
2908        SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error);
2909        goto bad;
2910    }
2911
2912    /* Update Create hdr */
2913    error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST);
2914    if (error) {
2915        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
2916        goto bad;
2917    }
2918
2919    /*
2920     * Build the IOCTL request
2921     */
2922    ioctlp->share = share;
2923    ioctlp->ctl_code = FSCTL_GET_REPARSE_POINT;
2924    fid = 0xffffffffffffffff;   /* fid is -1 for compound requests */
2925    ioctlp->fid = fid;
2926
2927	ioctlp->snd_input_len = 0;
2928	ioctlp->snd_output_len = 0;
2929	ioctlp->rcv_input_len = 0;
2930    /* reparse points should not need more than 16K of data */
2931	ioctlp->rcv_output_len = 16 * 1024;
2932
2933    error = smb2_smb_ioctl(share, ioctlp, &ioctl_rqp, context);
2934    if (error) {
2935        SMBERROR("smb2_smb_ioctl failed %d\n", error);
2936        goto bad;
2937    }
2938
2939    /* Update IOCTL hdr */
2940    error = smb2_rq_update_cmpd_hdr(ioctl_rqp, SMB2_CMPD_MIDDLE);
2941    if (error) {
2942        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
2943        goto bad;
2944    }
2945
2946    /* Chain IOCTL to the Create */
2947    create_rqp->sr_next_rqp = ioctl_rqp;
2948
2949    /*
2950     * Build the Close request
2951     */
2952    error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context);
2953    if (error) {
2954        SMBERROR("smb2_smb_close_fid failed %d\n", error);
2955        goto bad;
2956    }
2957
2958    /* Update Close hdr */
2959    error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST);
2960    if (error) {
2961        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
2962        goto bad;
2963    }
2964
2965    /* Chain Close to the IOCTL */
2966    ioctl_rqp->sr_next_rqp = close_rqp;
2967
2968    /*
2969     * Send the compound request of Create/IOCTL/Close
2970     */
2971    error = smb_rq_simple(create_rqp);
2972
2973    if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) {
2974        /* Rebuild and try sending again */
2975        smb_rq_done(create_rqp);
2976        create_rqp = NULL;
2977
2978        smb_rq_done(ioctl_rqp);
2979        ioctl_rqp = NULL;
2980
2981        smb_rq_done(close_rqp);
2982        close_rqp = NULL;
2983
2984        SMB_FREE(createp, M_SMBTEMP);
2985        createp = NULL;
2986
2987        SMB_FREE(closep, M_SMBTEMP);
2988        closep = NULL;
2989
2990        goto resend;
2991    }
2992
2993    createp->ret_ntstatus = create_rqp->sr_ntstatus;
2994
2995    /* Get pointer to response data */
2996    smb_rq_getreply(create_rqp, &mdp);
2997
2998    if (error) {
2999        /* Create failed, try parsing the IOCTL */
3000        SMBDEBUG("smb_rq_simple failed %d id %lld\n",
3001                 error, create_rqp->sr_messageid);
3002        goto parse_ioctl;
3003    }
3004
3005    /*
3006     * Parse the Create response.
3007     */
3008    error = smb2_smb_parse_create(share, mdp, createp);
3009    if (error) {
3010        /* Create parsing failed, try parsing the IOCTL */
3011        SMBERROR("smb2_smb_parse_create failed %d id %lld\n",
3012                 error, create_rqp->sr_messageid);
3013        goto parse_ioctl;
3014    }
3015
3016    /* At this point, fid has been entered into fid table */
3017    need_delete_fid = 1;
3018
3019    /*
3020     * Fill in fap and possibly update vnode's meta data caches
3021     */
3022    error = smb2fs_smb_parse_ntcreatex(share, create_np, createp,
3023                                       &fid, fap, context);
3024    if (error) {
3025        /* Updating meta data cache failed, try parsing the Ioctl */
3026        SMBERROR("smb2fs_smb_parse_ntcreatex failed %d id %lld\n",
3027                 error, create_rqp->sr_messageid);
3028    }
3029
3030parse_ioctl:
3031    /* Consume any pad bytes */
3032    tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp);
3033    if (tmp_error) {
3034        /* Failed to find next command, so can't parse rest of the responses */
3035        SMBERROR("create smb2_rq_next_command failed %d id %lld\n",
3036                 tmp_error, create_rqp->sr_messageid);
3037        goto bad;
3038    }
3039
3040    /*
3041     * Parse IOCTL SMB 2/3 header
3042     */
3043    tmp_error = smb2_rq_parse_header(ioctl_rqp, &mdp);
3044    ioctlp->ret_ntstatus = ioctl_rqp->sr_ntstatus;
3045    if (tmp_error) {
3046        /* IOCTL got an error, try parsing the Close */
3047        if (!error) {
3048            SMBDEBUG("ioctl smb2_rq_parse_header failed %d, id %lld\n",
3049                     tmp_error, ioctl_rqp->sr_messageid);
3050            error = tmp_error;
3051        }
3052        goto parse_close;
3053    }
3054
3055    /* Parse the IOCTL response */
3056    tmp_error = smb2_smb_parse_ioctl(mdp, ioctlp);
3057    if (tmp_error) {
3058        /* IOCTL parsing got an error, try parsing the Close */
3059        if (!error) {
3060            SMBERROR("smb2_smb_parse_ioctl failed %d id %lld\n",
3061                     tmp_error, ioctl_rqp->sr_messageid);
3062            error = tmp_error;
3063        }
3064        goto parse_close;
3065    }
3066
3067    /*
3068     * At this point, we know the IOCTL worked.
3069     * The IOCTL will return the path in rcv_output_buffer and rcv_output_len
3070     * Update the create_np with the symlink info.
3071     * smbfs_update_symlink_cache will deal with any null pointers
3072     */
3073	smbfs_update_symlink_cache(create_np, (char *) ioctlp->rcv_output_buffer,
3074                               ioctlp->rcv_output_len);
3075	tmp_error = uiomove((char *) ioctlp->rcv_output_buffer,
3076                        (int) ioctlp->rcv_output_len,
3077                        ioctl_uiop);
3078    if (tmp_error) {
3079        /* uiomove failed */
3080        if (!error) {
3081            SMBERROR("uiomove failed %d id %lld\n",
3082                     tmp_error, ioctl_rqp->sr_messageid);
3083            error = tmp_error;
3084        }
3085        goto parse_close;
3086    }
3087
3088parse_close:
3089    /* Update closep fid so it gets freed from FID table */
3090    closep->fid = createp->ret_fid;
3091
3092    /* Consume any pad bytes */
3093    tmp_error = smb2_rq_next_command(ioctl_rqp, &next_cmd_offset, mdp);
3094    if (tmp_error) {
3095        /* Failed to find next command, so can't parse rest of the responses */
3096        SMBERROR("ioctl smb2_rq_next_command failed %d\n", tmp_error);
3097        error = error ? error : tmp_error;
3098        goto bad;
3099    }
3100
3101    /*
3102     * Parse Close SMB 2/3 header
3103     */
3104    tmp_error = smb2_rq_parse_header(close_rqp, &mdp);
3105    closep->ret_ntstatus = close_rqp->sr_ntstatus;
3106    if (tmp_error) {
3107        if (!error) {
3108            SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n",
3109                     tmp_error, close_rqp->sr_messageid);
3110            error = tmp_error;
3111        }
3112        goto bad;
3113    }
3114
3115    /* Parse the Close response */
3116    tmp_error = smb2_smb_parse_close(mdp, closep);
3117    if (tmp_error) {
3118        if (!error) {
3119            SMBERROR("smb2_smb_parse_close failed %d id %lld\n",
3120                     tmp_error, close_rqp->sr_messageid);
3121            error = tmp_error;
3122        }
3123        goto bad;
3124    }
3125
3126    /* At this point, fid has been removed from fid table */
3127    need_delete_fid = 0;
3128
3129bad:
3130    if (need_delete_fid == 1) {
3131        /*
3132         * Close failed but the Create worked and was successfully parsed.
3133         * Try issuing the Close request again.
3134         */
3135        tmp_error = smb2_smb_close_fid(share, createp->ret_fid,
3136                                       NULL, NULL, context);
3137        if (tmp_error) {
3138            SMBERROR("Second close failed %d\n", tmp_error);
3139        }
3140    }
3141
3142    if (create_rqp != NULL) {
3143        smb_rq_done(create_rqp);
3144    }
3145    if (ioctl_rqp != NULL) {
3146        smb_rq_done(ioctl_rqp);
3147    }
3148    if (close_rqp != NULL) {
3149        smb_rq_done(close_rqp);
3150    }
3151
3152    if (createp != NULL) {
3153        SMB_FREE(createp, M_SMBTEMP);
3154    }
3155    if (ioctlp != NULL) {
3156        SMB_FREE(ioctlp, M_SMBTEMP);
3157    }
3158    if (closep != NULL) {
3159        SMB_FREE(closep, M_SMBTEMP);
3160    }
3161
3162    if (fap != NULL) {
3163        SMB_FREE(fap, M_SMBTEMP);
3164    }
3165
3166	return error;
3167}
3168
3169static int
3170smb2fs_smb_cmpd_reparse_point_set(struct smb_share *share, struct smbnode *create_np,
3171                                  const char *namep, size_t name_len,
3172                                  char *targetp, size_t target_len,
3173                                  struct smbfattr *fap, vfs_context_t context)
3174{
3175	int error, tmp_error;
3176    int ioctl_error= EINVAL;    /* assume IOCTL failed */
3177    SMBFID fid = 0;
3178    struct smb2_create_rq *createp = NULL;
3179    struct smb2_query_info_rq *queryp = NULL;
3180    struct smb2_ioctl_rq *ioctlp = NULL;
3181    struct smb2_close_rq *closep = NULL;
3182	struct smb_rq *create_rqp = NULL;
3183	struct smb_rq *query_rqp = NULL;
3184	struct smb_rq *ioctl_rqp = NULL;
3185	struct smb_rq *close_rqp = NULL;
3186	struct mdchain *mdp;
3187    size_t next_cmd_offset = 0;
3188    uint32_t need_delete_fid = 0, create_worked = 0;
3189    uint32_t create_desired_access = SMB2_FILE_WRITE_DATA |
3190                                     SMB2_FILE_WRITE_ATTRIBUTES |
3191                                     SMB2_DELETE;
3192    uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL;
3193    uint64_t create_flags = SMB2_CREATE_DO_CREATE | SMB2_CREATE_GET_MAX_ACCESS;
3194	size_t path_len;
3195	char *pathp = NULL;
3196	struct smbmount *smp = create_np->n_mount;
3197    int add_query = 0;
3198    uint64_t inode_number = 0;
3199    uint32_t inode_number_len;
3200    uint32_t create_options = 0;
3201    uint32_t disposition = FILE_CREATE;
3202    enum vtype vnode_type = VREG;
3203
3204    /*
3205     * For this function, vnode_type is VREG as the Open will be done on the
3206     * reparse point and then the Ioctl will be done on the reparse point.
3207     */
3208
3209    if (fap == NULL) {
3210        /* This should never happen */
3211        SMBERROR("fap is NULL \n");
3212		error = EINVAL;
3213		goto bad;
3214    }
3215
3216    /*
3217     * This function can do Create/Query/Ioctl/Close, or Create/Ioctl/Close
3218     * If File IDs are supported, then the Query is added to get the file ID.
3219     */
3220
3221    if (SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS) {
3222        /* Need the file id, so add a query into the compound request */
3223        add_query = 1;
3224    }
3225
3226    /* Convert target to a network style path */
3227	path_len = (target_len * 2) + 2;	/* Start with the max possible size */
3228	SMB_MALLOC(pathp, char *, path_len, M_TEMP, M_WAITOK | M_ZERO);
3229	if (pathp == NULL) {
3230		error = ENOMEM;
3231		goto bad;
3232	}
3233
3234	error = smb_convert_path_to_network(targetp, target_len, pathp, &path_len,
3235										'\\', SMB_UTF_SFM_CONVERSIONS,
3236										SMB_UNICODE_STRINGS(SSTOVC(share)));
3237	if (error) {
3238		goto bad;
3239	}
3240
3241    if (add_query) {
3242        SMB_MALLOC(queryp,
3243                   struct smb2_query_info_rq *,
3244                   sizeof(struct smb2_query_info_rq),
3245                   M_SMBTEMP,
3246                   M_WAITOK | M_ZERO);
3247        if (queryp == NULL) {
3248            SMBERROR("SMB_MALLOC failed\n");
3249            error = ENOMEM;
3250            goto bad;
3251        }
3252    }
3253
3254    SMB_MALLOC(ioctlp,
3255               struct smb2_ioctl_rq *,
3256               sizeof(struct smb2_ioctl_rq),
3257               M_SMBTEMP,
3258               M_WAITOK | M_ZERO);
3259    if (ioctlp == NULL) {
3260		SMBERROR("SMB_MALLOC failed\n");
3261        error = ENOMEM;
3262        goto bad;
3263    }
3264
3265resend:
3266    /*
3267     * Build the Create call
3268     */
3269    create_options = smb2fs_smb_get_create_options(share, create_np,
3270                                                   namep, NULL,
3271                                                   vnode_type, 1);
3272    error = smb2fs_smb_ntcreatex(share, create_np,
3273                                 namep, name_len,
3274                                 NULL, 0,
3275                                 create_desired_access, vnode_type,
3276                                 share_access, disposition,
3277                                 create_flags, create_options,
3278                                 &fid, fap,
3279                                 &create_rqp, &createp,
3280                                 NULL, context);
3281    if (error) {
3282        SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error);
3283        goto bad;
3284    }
3285
3286    /* Update Create hdr */
3287    error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST);
3288    if (error) {
3289        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
3290        goto bad;
3291    }
3292
3293    fid = 0xffffffffffffffff;   /* fid is -1 for compound requests */
3294
3295    if (add_query) {
3296        /*
3297         * Build the Query Info request (to get File ID)
3298         */
3299        inode_number_len = (uint32_t) sizeof(inode_number);
3300
3301        queryp->info_type = SMB2_0_INFO_FILE;
3302        queryp->file_info_class = FileInternalInformation;
3303        queryp->add_info = 0;
3304        queryp->flags = 0;
3305        queryp->output_buffer_len = inode_number_len;
3306        queryp->output_buffer = (uint8_t *) &inode_number;
3307        queryp->input_buffer_len = 0;
3308        queryp->input_buffer = NULL;
3309        queryp->ret_buffer_len = 0;
3310        queryp->fid = fid;
3311
3312        error = smb2_smb_query_info(share, queryp, &query_rqp, context);
3313        if (error) {
3314            SMBERROR("smb2_smb_query_info failed %d\n", error);
3315            goto bad;
3316        }
3317
3318        /* Update Query hdr */
3319        error = smb2_rq_update_cmpd_hdr(query_rqp, SMB2_CMPD_MIDDLE);
3320        if (error) {
3321            SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
3322            goto bad;
3323        }
3324
3325        /* Chain Query Info to the Create */
3326        create_rqp->sr_next_rqp = query_rqp;
3327    }
3328
3329    /*
3330     * Build the IOCTL request
3331     * path and path len is passed in via snd_input_buffer and snd_input_len
3332     */
3333    ioctlp->share = share;
3334    ioctlp->ctl_code = FSCTL_SET_REPARSE_POINT;
3335    ioctlp->fid = fid;
3336
3337	ioctlp->snd_input_len = (uint32_t) path_len;
3338	ioctlp->snd_output_len = 0;
3339	ioctlp->rcv_input_len = 0;
3340	ioctlp->rcv_output_len = 0;
3341    ioctlp->snd_input_buffer = (uint8_t *) pathp;
3342
3343    error = smb2_smb_ioctl(share, ioctlp, &ioctl_rqp, context);
3344    if (error) {
3345        SMBERROR("smb2_smb_ioctl failed %d\n", error);
3346        goto bad;
3347    }
3348
3349    /* Update IOCTL hdr */
3350    error = smb2_rq_update_cmpd_hdr(ioctl_rqp, SMB2_CMPD_MIDDLE);
3351    if (error) {
3352        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
3353        goto bad;
3354    }
3355
3356    if (add_query) {
3357        /* Chain IOCTL to the Query */
3358        query_rqp->sr_next_rqp = ioctl_rqp;
3359    }
3360    else {
3361        /* Chain IOCTL to the Create */
3362        create_rqp->sr_next_rqp = ioctl_rqp;
3363    }
3364
3365    /*
3366     * Build the Close request
3367     */
3368    error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context);
3369    if (error) {
3370        SMBERROR("smb2_smb_close_fid failed %d\n", error);
3371        goto bad;
3372    }
3373
3374    /* Update Close hdr */
3375    error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST);
3376    if (error) {
3377        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
3378        goto bad;
3379    }
3380
3381    /* Chain Close to the IOCTL */
3382    ioctl_rqp->sr_next_rqp = close_rqp;
3383
3384    /*
3385     * Send the compound request of Create/IOCTL/Close
3386     */
3387    error = smb_rq_simple(create_rqp);
3388
3389    if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) {
3390        /* Rebuild and try sending again */
3391        smb_rq_done(create_rqp);
3392        create_rqp = NULL;
3393
3394        if (query_rqp) {
3395            smb_rq_done(query_rqp);
3396            query_rqp = NULL;
3397        }
3398
3399        smb_rq_done(ioctl_rqp);
3400        ioctl_rqp = NULL;
3401
3402        smb_rq_done(close_rqp);
3403        close_rqp = NULL;
3404
3405        SMB_FREE(createp, M_SMBTEMP);
3406        createp = NULL;
3407
3408        SMB_FREE(closep, M_SMBTEMP);
3409        closep = NULL;
3410
3411        goto resend;
3412    }
3413
3414    createp->ret_ntstatus = create_rqp->sr_ntstatus;
3415
3416    /* Get pointer to response data */
3417    smb_rq_getreply(create_rqp, &mdp);
3418
3419    if (error) {
3420        /* Create failed, try parsing the IOCTL */
3421        SMBDEBUG("smb_rq_simple failed %d id %lld\n",
3422                 error, create_rqp->sr_messageid);
3423        goto parse_query;
3424    }
3425
3426    /*
3427     * Parse the Create response.
3428     */
3429    error = smb2_smb_parse_create(share, mdp, createp);
3430    if (error) {
3431        /* Create parsing failed, try parsing the IOCTL */
3432        SMBERROR("smb2_smb_parse_create failed %d id %lld\n",
3433                 error, create_rqp->sr_messageid);
3434        goto parse_query;
3435    }
3436
3437    /* At this point, fid has been entered into fid table */
3438    need_delete_fid = 1;
3439    create_worked = 1;
3440
3441    /*
3442     * Fill in fap and possibly update vnode's meta data caches
3443     */
3444    error = smb2fs_smb_parse_ntcreatex(share, create_np, createp,
3445                                       &fid, fap, context);
3446    if (error) {
3447        /* Updating meta data cache failed, try parsing the IOCTL */
3448        SMBERROR("smb2fs_smb_parse_ntcreatex failed %d id %lld\n",
3449                 error, create_rqp->sr_messageid);
3450    }
3451
3452parse_query:
3453    if (query_rqp != NULL) {
3454        /* Consume any pad bytes */
3455        tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp);
3456        if (tmp_error) {
3457            /* Failed to find next command, so can't parse rest of the responses */
3458            SMBERROR("create smb2_rq_next_command failed %d id %lld\n",
3459                     tmp_error, create_rqp->sr_messageid);
3460            error = error ? error : tmp_error;
3461            goto bad;
3462        }
3463
3464        /*
3465         * Parse Query Info SMB 2/3 header
3466         */
3467        tmp_error = smb2_rq_parse_header(query_rqp, &mdp);
3468        queryp->ret_ntstatus = query_rqp->sr_ntstatus;
3469        if (tmp_error) {
3470            /* Query Info got an error, try parsing the Close */
3471            if (!error) {
3472                SMBDEBUG("query smb2_rq_parse_header failed %d, id %lld\n",
3473                         tmp_error, query_rqp->sr_messageid);
3474                error = tmp_error;
3475            }
3476            goto parse_ioctl;
3477        }
3478
3479        /* Parse the Query Info response */
3480        tmp_error = smb2_smb_parse_query_info(mdp, queryp);
3481        if (tmp_error) {
3482            /* Query Info parsing got an error, try parsing the Close */
3483            if (!error) {
3484                if (tmp_error != ENOATTR) {
3485                    SMBERROR("smb2_smb_parse_query_info failed %d id %lld\n",
3486                             tmp_error, query_rqp->sr_messageid);
3487                }
3488                error = tmp_error;
3489            }
3490            goto parse_ioctl;
3491        }
3492        else {
3493            /* Query worked, so get the inode number */
3494            if (fap) {
3495                fap->fa_ino = inode_number;
3496                smb2fs_smb_file_id_check(share, fap->fa_ino, NULL, 0);
3497            }
3498        }
3499    }
3500
3501parse_ioctl:
3502    /* Consume any pad bytes */
3503    tmp_error = smb2_rq_next_command(query_rqp != NULL ? query_rqp : create_rqp,
3504                                     &next_cmd_offset, mdp);
3505    if (tmp_error) {
3506        /* Failed to find next command, so can't parse rest of the responses */
3507        SMBERROR("create smb2_rq_next_command failed %d id %lld\n",
3508                 tmp_error, create_rqp->sr_messageid);
3509        goto bad;
3510    }
3511
3512    /*
3513     * Parse IOCTL SMB 2/3 header
3514     */
3515    tmp_error = smb2_rq_parse_header(ioctl_rqp, &mdp);
3516    ioctlp->ret_ntstatus = ioctl_rqp->sr_ntstatus;
3517    ioctl_error = tmp_error;
3518    if (tmp_error) {
3519        /* IOCTL got an error, try parsing the Close */
3520        if (!error) {
3521            SMBDEBUG("ioctl smb2_rq_parse_header failed %d, id %lld\n",
3522                     tmp_error, ioctl_rqp->sr_messageid);
3523            error = tmp_error;
3524        }
3525        goto parse_close;
3526    }
3527
3528    /* Parse the IOCTL response */
3529    tmp_error = smb2_smb_parse_ioctl(mdp, ioctlp);
3530    if (tmp_error) {
3531        /* IOCTL parsing got an error, try parsing the Close */
3532        if (!error) {
3533            SMBERROR("smb2_smb_parse_ioctl failed %d id %lld\n",
3534                     tmp_error, ioctl_rqp->sr_messageid);
3535            error = tmp_error;
3536        }
3537        goto parse_close;
3538    }
3539
3540parse_close:
3541    /* Update closep fid so it gets freed from FID table */
3542    closep->fid = createp->ret_fid;
3543
3544    /* Consume any pad bytes */
3545    tmp_error = smb2_rq_next_command(ioctl_rqp, &next_cmd_offset, mdp);
3546    if (tmp_error) {
3547        /* Failed to find next command, so can't parse rest of the responses */
3548        SMBERROR("ioctl smb2_rq_next_command failed %d\n", tmp_error);
3549        error = error ? error : tmp_error;
3550        goto bad;
3551    }
3552
3553    /*
3554     * Parse Close SMB 2/3 header
3555     */
3556    tmp_error = smb2_rq_parse_header(close_rqp, &mdp);
3557    closep->ret_ntstatus = close_rqp->sr_ntstatus;
3558    if (tmp_error) {
3559        if (!error) {
3560            SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n",
3561                     tmp_error, close_rqp->sr_messageid);
3562            error = tmp_error;
3563        }
3564        goto bad;
3565    }
3566
3567    /* Parse the Close response */
3568    tmp_error = smb2_smb_parse_close(mdp, closep);
3569    if (tmp_error) {
3570        if (!error) {
3571            SMBERROR("smb2_smb_parse_close failed %d id %lld\n",
3572                     tmp_error, close_rqp->sr_messageid);
3573            error = tmp_error;
3574        }
3575        goto bad;
3576    }
3577
3578    /* At this point, fid has been removed from fid table */
3579    need_delete_fid = 0;
3580
3581bad:
3582    if (need_delete_fid == 1) {
3583        /*
3584         * Close failed but the Create worked and was successfully parsed.
3585         * Try issuing the Close request again.
3586         */
3587        tmp_error = smb2_smb_close_fid(share, createp->ret_fid,
3588                                       NULL, NULL, context);
3589        if (tmp_error) {
3590            SMBERROR("Second close failed %d\n", tmp_error);
3591        }
3592    }
3593
3594    /* Only check for IOCTL errors if the create worked */
3595    if (create_worked == 1) {
3596        if (ioctl_error) {
3597            SMBDEBUG("smb2_smb_ioctl failed %d ntstatus %d\n",
3598                     ioctl_error, ioctlp->ret_ntstatus);
3599
3600            /* Failed to create the symlink, remove the file */
3601            (void) smb2fs_smb_delete(share, create_np, VREG,
3602                                     namep, name_len,
3603                                     0, context);
3604        }
3605        else {
3606            /* IOCTL worked, reset any other fap information */
3607            fap->fa_size = target_len;
3608            /* FSCTL_SET_REPARSE_POINT succeeded, so mark it as a reparse point */
3609            fap->fa_attr |= SMB_EFA_REPARSE_POINT;
3610            fap->fa_valid_mask |= FA_REPARSE_TAG_VALID;
3611            fap->fa_reparse_tag = IO_REPARSE_TAG_SYMLINK;
3612            fap->fa_valid_mask |= FA_VTYPE_VALID;
3613            fap->fa_vtype = VLNK;
3614        }
3615
3616        /*
3617         * Windows systems requires special user access to create a reparse symlinks.
3618         * They default to only allow administrator symlink create access. This can
3619         * be changed on the server, but we are going to run into this issue. So if
3620         * we get an access error on the fsctl then we assume this user doesn't have
3621         * create symlink rights and we need to fallback to the old Conrad/Steve
3622         * symlinks. Since the create worked, we know the user has access to the file
3623         * system, they just don't have create symlink rights. We never fallback if
3624         * the server is running darwin.
3625         */
3626        if ((ioctl_error) && !(UNIX_SERVER(SSTOVC(share)))) {
3627            /*
3628             * <14281932> Could be NetApp server not supporting reparse
3629             * points and returning STATUS_INVALID_DEVICE_REQUEST.
3630             */
3631            if ((ioctl_error == EACCES) ||
3632                (ioctlp->ret_ntstatus == STATUS_INVALID_DEVICE_REQUEST)) {
3633                smp->sm_flags &= ~MNT_SUPPORTS_REPARSE_SYMLINKS;
3634
3635                error = smbfs_smb_create_windows_symlink(share, create_np,
3636                                                         namep, name_len,
3637                                                         targetp, target_len,
3638                                                         fap, context);
3639                if (!error) {
3640                    SMBDEBUG("smbfs_smb_create_windows_symlink failed %d\n", error);
3641                }
3642            }
3643        }
3644    }
3645
3646    if (create_rqp != NULL) {
3647        smb_rq_done(create_rqp);
3648    }
3649    if (query_rqp != NULL) {
3650        smb_rq_done(query_rqp);
3651    }
3652    if (ioctl_rqp != NULL) {
3653        smb_rq_done(ioctl_rqp);
3654    }
3655    if (close_rqp != NULL) {
3656        smb_rq_done(close_rqp);
3657    }
3658
3659    if (createp != NULL) {
3660        SMB_FREE(createp, M_SMBTEMP);
3661    }
3662    if (queryp != NULL) {
3663        SMB_FREE(queryp, M_SMBTEMP);
3664    }
3665    if (ioctlp != NULL) {
3666        SMB_FREE(ioctlp, M_SMBTEMP);
3667    }
3668    if (closep != NULL) {
3669        SMB_FREE(closep, M_SMBTEMP);
3670    }
3671
3672    if (pathp != NULL) {
3673        SMB_FREE(pathp, M_TEMP);
3674    }
3675
3676	return error;
3677}
3678
3679int
3680smb2fs_smb_cmpd_resolve_id(struct smb_share *share, struct smbnode *np,
3681                           uint64_t ino, uint32_t *resolve_errorp, char **pathp,
3682                           vfs_context_t context)
3683{
3684	int error, tmp_error;
3685    struct smbfattr *fap = NULL;
3686    struct smb2_create_rq *createp = NULL;
3687    struct smb2_close_rq *closep = NULL;
3688	struct smb_rq *create_rqp = NULL;
3689	struct smb_rq *close_rqp = NULL;
3690	struct mdchain *mdp;
3691    size_t next_cmd_offset = 0;
3692    uint32_t need_delete_fid = 0;
3693    SMBFID fid = 0;
3694    struct smb2_create_ctx_resolve_id resolve_id;
3695    uint32_t create_options = 0;
3696    uint32_t disposition = FILE_OPEN;
3697    enum vtype vnode_type = VDIR;
3698
3699    /*
3700     * For this function, vnode_type is VDIR we always do the Resolve ID on the
3701     * root node.  The item will be Opened and the Resolve ID will be done on
3702     * it.
3703     */
3704
3705    SMB_MALLOC(fap,
3706               struct smbfattr *,
3707               sizeof(struct smbfattr),
3708               M_SMBTEMP,
3709               M_WAITOK | M_ZERO);
3710    if (fap == NULL) {
3711        SMBERROR("SMB_MALLOC failed\n");
3712        error = ENOMEM;
3713        goto bad;
3714    }
3715
3716    /* Fill in Resolve ID context */
3717    resolve_id.file_id = ino;
3718    resolve_id.ret_errorp = resolve_errorp;
3719    resolve_id.ret_pathp = pathp;
3720
3721resend:
3722    /*
3723     * Build the Create call
3724     */
3725    create_options = smb2fs_smb_get_create_options(share, np,
3726                                                   NULL, NULL,
3727                                                   vnode_type, 0);
3728    error = smb2fs_smb_ntcreatex(share, np,
3729                                 NULL, 0,
3730                                 NULL, 0,
3731                                 SMB2_FILE_READ_ATTRIBUTES | SMB2_SYNCHRONIZE, vnode_type,
3732                                 NTCREATEX_SHARE_ACCESS_ALL, disposition,
3733                                 SMB2_CREATE_AAPL_RESOLVE_ID, create_options,
3734                                 &fid, fap,
3735                                 &create_rqp, &createp,
3736                                 &resolve_id, context);
3737    if (error) {
3738        SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error);
3739        goto bad;
3740    }
3741
3742    /* Update Create hdr */
3743    error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST);
3744    if (error) {
3745        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
3746        goto bad;
3747    }
3748
3749    fid = 0xffffffffffffffff;   /* fid is -1 for compound requests */
3750
3751    /*
3752     * Build the Close request
3753     */
3754    error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context);
3755    if (error) {
3756        SMBERROR("smb2_smb_close_fid failed %d\n", error);
3757        goto bad;
3758    }
3759
3760    /* Update Close hdr */
3761    error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST);
3762    if (error) {
3763        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
3764        goto bad;
3765    }
3766
3767    /* Chain Close to the Create */
3768    create_rqp->sr_next_rqp = close_rqp;
3769
3770    /*
3771     * Send the compound request of Create/Close
3772     */
3773    error = smb_rq_simple(create_rqp);
3774
3775    if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) {
3776        /* Rebuild and try sending again */
3777        smb_rq_done(create_rqp);
3778        create_rqp = NULL;
3779
3780        smb_rq_done(close_rqp);
3781        close_rqp = NULL;
3782
3783        SMB_FREE(createp, M_SMBTEMP);
3784        createp = NULL;
3785
3786        SMB_FREE(closep, M_SMBTEMP);
3787        closep = NULL;
3788
3789        goto resend;
3790    }
3791
3792    createp->ret_ntstatus = create_rqp->sr_ntstatus;
3793
3794    /* Get pointer to response data */
3795    smb_rq_getreply(create_rqp, &mdp);
3796
3797    if (error) {
3798        /* Create failed, try parsing the Close */
3799        if (error != ENOENT) {
3800            SMBDEBUG("smb_rq_simple failed %d id %lld\n",
3801                     error, create_rqp->sr_messageid);
3802        }
3803        goto parse_close;
3804    }
3805
3806    /*
3807     * Parse the Create response.
3808     */
3809    error = smb2_smb_parse_create(share, mdp, createp);
3810    if (error) {
3811        /* Create parsing failed, try parsing the Close */
3812        SMBERROR("smb2_smb_parse_create failed %d id %lld\n",
3813                 error, create_rqp->sr_messageid);
3814        goto parse_close;
3815    }
3816
3817    /* At this point, fid has been entered into fid table */
3818    need_delete_fid = 1;
3819
3820parse_close:
3821    /* Update closep fid so it gets freed from FID table */
3822    closep->fid = createp->ret_fid;
3823
3824    /* Consume any pad bytes */
3825    tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp);
3826    if (tmp_error) {
3827        /* Failed to find next command, so can't parse rest of the responses */
3828        SMBERROR("create smb2_rq_next_command failed %d id %lld\n",
3829                 tmp_error, create_rqp->sr_messageid);
3830        error = error ? error : tmp_error;
3831        goto bad;
3832    }
3833
3834    /*
3835     * Parse Close SMB 2/3 header
3836     */
3837    tmp_error = smb2_rq_parse_header(close_rqp, &mdp);
3838    closep->ret_ntstatus = close_rqp->sr_ntstatus;
3839    if (tmp_error) {
3840        if (!error) {
3841            SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n",
3842                     tmp_error, close_rqp->sr_messageid);
3843            error = tmp_error;
3844        }
3845        goto bad;
3846    }
3847
3848    /* Parse the Close response */
3849    tmp_error = smb2_smb_parse_close(mdp, closep);
3850    if (tmp_error) {
3851        if (!error) {
3852            SMBERROR("smb2_smb_parse_close failed %d id %lld\n",
3853                     tmp_error, close_rqp->sr_messageid);
3854            error = tmp_error;
3855        }
3856        goto bad;
3857    }
3858
3859    /* At this point, fid has been removed from fid table */
3860    need_delete_fid = 0;
3861
3862bad:
3863    if (need_delete_fid == 1) {
3864        /*
3865         * Close failed but the Create worked and was successfully parsed.
3866         * Try issuing the Close request again.
3867         */
3868        tmp_error = smb2_smb_close_fid(share, createp->ret_fid,
3869                                       NULL, NULL, context);
3870        if (tmp_error) {
3871            SMBERROR("Second close failed %d\n", tmp_error);
3872        }
3873    }
3874
3875    if (create_rqp != NULL) {
3876        smb_rq_done(create_rqp);
3877    }
3878    if (close_rqp != NULL) {
3879        smb_rq_done(close_rqp);
3880    }
3881
3882    if (createp != NULL) {
3883        SMB_FREE(createp, M_SMBTEMP);
3884    }
3885    if (closep != NULL) {
3886        SMB_FREE(closep, M_SMBTEMP);
3887    }
3888
3889    if (fap != NULL) {
3890        SMB_FREE(fap, M_SMBTEMP);
3891    }
3892
3893	return error;
3894}
3895
3896static int
3897smb2fs_smb_cmpd_set_info(struct smb_share *share, struct smbnode *create_np, enum vtype vnode_type,
3898                         const char *create_namep, size_t create_name_len,
3899                         uint32_t create_xattr, uint32_t create_desired_access,
3900                         uint8_t setinfo_info_type, uint8_t setinfo_file_info_class,
3901                         uint32_t setinfo_add_info,
3902                         uint32_t setinfo_input_buffer_len, uint8_t *setinfo_input_buffer,
3903                         uint32_t *setinfo_ntstatus,
3904                         vfs_context_t context)
3905{
3906#pragma unused(setinfo_input_buffer_len)
3907	int error, tmp_error;
3908    SMBFID fid = 0;
3909    struct smbfattr *fap = NULL;
3910    struct smb2_create_rq *createp = NULL;
3911    struct smb2_set_info_rq *infop = NULL;
3912    struct smb2_close_rq *closep = NULL;
3913	struct smb_rq *create_rqp = NULL;
3914	struct smb_rq *setinfo_rqp = NULL;
3915	struct smb_rq *close_rqp = NULL;
3916	struct mdchain *mdp;
3917    size_t next_cmd_offset = 0;
3918    uint32_t need_delete_fid = 0;
3919    uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL;
3920    uint64_t create_flags = create_xattr ? SMB2_CREATE_IS_NAMED_STREAM : 0;
3921    char *file_namep = NULL, *stream_namep = NULL;
3922    size_t file_name_len = 0, stream_name_len = 0;
3923    uint32_t create_options = 0;
3924    uint32_t disposition = FILE_OPEN;
3925
3926    /*
3927     * For this function, vnode_type is the item's type. The item will be
3928     * Opened and the Set Info will be done on the item.
3929     */
3930
3931    if ((setinfo_info_type == SMB2_0_INFO_FILE) &&
3932        (setinfo_file_info_class == FileDispositionInformation)) {
3933        /*
3934         * <17346821> Must be a Delete. Set share_access to
3935         * NTCREATEX_SHARE_ACCESS_NONE so that we can attempt to delete the
3936         * item right now.
3937         */
3938        share_access = NTCREATEX_SHARE_ACCESS_NONE;
3939    }
3940
3941    *setinfo_ntstatus = 0;
3942
3943    SMB_MALLOC(fap,
3944               struct smbfattr *,
3945               sizeof(struct smbfattr),
3946               M_SMBTEMP,
3947               M_WAITOK | M_ZERO);
3948    if (fap == NULL) {
3949        SMBERROR("SMB_MALLOC failed\n");
3950        error = ENOMEM;
3951        goto bad;
3952    }
3953
3954    SMB_MALLOC(infop,
3955               struct smb2_set_info_rq *,
3956               sizeof(struct smb2_set_info_rq),
3957               M_SMBTEMP,
3958               M_WAITOK | M_ZERO);
3959    if (infop == NULL) {
3960        SMBERROR("SMB_MALLOC failed\n");
3961        error = ENOMEM;
3962        goto bad;
3963    }
3964
3965resend:
3966    /*
3967     * Build the Create call
3968     */
3969    create_flags |= SMB2_CREATE_GET_MAX_ACCESS;
3970
3971    if (!(create_flags & SMB2_CREATE_IS_NAMED_STREAM)) {
3972        file_namep = (char *) create_namep;
3973        file_name_len = create_name_len;
3974    }
3975    else {
3976        /* create_namep is actually the stream name */
3977        stream_namep = (char *) create_namep;
3978        stream_name_len = create_name_len;
3979    }
3980
3981    create_options = smb2fs_smb_get_create_options(share, create_np,
3982                                                   file_namep, stream_namep,
3983                                                   vnode_type, 1);
3984    error = smb2fs_smb_ntcreatex(share, create_np,
3985                                 file_namep, file_name_len,
3986                                 stream_namep, stream_name_len,
3987                                 create_desired_access, vnode_type,
3988                                 share_access, disposition,
3989                                 create_flags, create_options,
3990                                 &fid, fap,
3991                                 &create_rqp, &createp,
3992                                 NULL, context);
3993
3994    if (error) {
3995        SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error);
3996        goto bad;
3997    }
3998
3999    /* Update Create hdr */
4000    error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST);
4001    if (error) {
4002        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
4003        goto bad;
4004    }
4005
4006    /*
4007     * Build the Set Info request
4008     */
4009    infop->info_type = setinfo_info_type;
4010    infop->file_info_class = setinfo_file_info_class;
4011    infop->add_info = setinfo_add_info;
4012    fid = 0xffffffffffffffff;   /* fid is -1 for compound requests */
4013    infop->fid = fid;
4014    infop->input_buffer = setinfo_input_buffer;
4015
4016    error = smb2_smb_set_info(share, infop, &setinfo_rqp, context);
4017    if (error) {
4018        SMBERROR("smb2_smb_set_info failed %d\n", error);
4019        goto bad;
4020    }
4021
4022    /* Update Set Info hdr */
4023    error = smb2_rq_update_cmpd_hdr(setinfo_rqp, SMB2_CMPD_MIDDLE);
4024    if (error) {
4025        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
4026        goto bad;
4027    }
4028
4029    /* Chain Set Info to the Create */
4030    create_rqp->sr_next_rqp = setinfo_rqp;
4031
4032    /*
4033     * Build the Close request
4034     */
4035    error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context);
4036    if (error) {
4037        SMBERROR("smb2_smb_close_fid failed %d\n", error);
4038        goto bad;
4039    }
4040
4041    /* Update Close hdr */
4042    error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST);
4043    if (error) {
4044        SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error);
4045        goto bad;
4046    }
4047
4048    /* Chain Close to the Query Info */
4049    setinfo_rqp->sr_next_rqp = close_rqp;
4050
4051    /*
4052     * Send the compound request of Create/SetInfo/Close
4053     */
4054    error = smb_rq_simple(create_rqp);
4055
4056    if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) {
4057        /* Rebuild and try sending again */
4058        smb_rq_done(create_rqp);
4059        create_rqp = NULL;
4060
4061        smb_rq_done(setinfo_rqp);
4062        setinfo_rqp = NULL;
4063
4064        smb_rq_done(close_rqp);
4065        close_rqp = NULL;
4066
4067        SMB_FREE(createp, M_SMBTEMP);
4068        createp = NULL;
4069
4070        SMB_FREE(closep, M_SMBTEMP);
4071        closep = NULL;
4072
4073        goto resend;
4074    }
4075
4076    createp->ret_ntstatus = create_rqp->sr_ntstatus;
4077
4078    /* Get pointer to response data */
4079    smb_rq_getreply(create_rqp, &mdp);
4080
4081    if (error) {
4082        /* Create failed, try parsing the Set Info */
4083        if (error != ENOENT) {
4084            SMBDEBUG("smb_rq_simple failed %d id %lld\n",
4085                     error, create_rqp->sr_messageid);
4086        }
4087        goto parse_setinfo;
4088    }
4089
4090    /*
4091     * Parse the Create response.
4092     */
4093    error = smb2_smb_parse_create(share, mdp, createp);
4094    if (error) {
4095        /* Create parsing failed, try parsing the Set Info */
4096        SMBERROR("smb2_smb_parse_create failed %d id %lld\n",
4097                 error, create_rqp->sr_messageid);
4098        goto parse_setinfo;
4099    }
4100
4101    /* At this point, fid has been entered into fid table */
4102    need_delete_fid = 1;
4103
4104    /*
4105     * Fill in fap and possibly update vnode's meta data caches
4106     */
4107    error = smb2fs_smb_parse_ntcreatex(share, create_np, createp,
4108                                       &fid, fap, context);
4109    if (error) {
4110        /* Updating meta data cache failed, try parsing the IOCTL */
4111        SMBERROR("smb2fs_smb_parse_ntcreatex failed %d id %lld\n",
4112                 error, create_rqp->sr_messageid);
4113    }
4114
4115parse_setinfo:
4116    /* Consume any pad bytes */
4117    tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp);
4118    if (tmp_error) {
4119        /* Failed to find next command, so can't parse rest of the responses */
4120        SMBERROR("create smb2_rq_next_command failed %d id %lld\n",
4121                 tmp_error, create_rqp->sr_messageid);
4122        goto bad;
4123    }
4124
4125    /*
4126     * Parse Set Info SMB 2/3 header
4127     */
4128    tmp_error = smb2_rq_parse_header(setinfo_rqp, &mdp);
4129    infop->ret_ntstatus = setinfo_rqp->sr_ntstatus;
4130    *setinfo_ntstatus = setinfo_rqp->sr_ntstatus;
4131    if (tmp_error) {
4132        /* Set Info got an error, try parsing the Close */
4133        if (!error) {
4134            if ((tmp_error != EACCES) && (tmp_error != ENOTEMPTY)) {
4135                SMBDEBUG("setinfo smb2_rq_parse_header failed %d, id %lld\n",
4136                         tmp_error, setinfo_rqp->sr_messageid);
4137            }
4138            error = tmp_error;
4139        }
4140        goto parse_close;
4141    }
4142
4143    /* Parse the Set Info response */
4144    tmp_error = smb2_smb_parse_set_info(mdp, infop);
4145    if (tmp_error) {
4146        /* Query Info parsing got an error, try parsing the Close */
4147        if (!error) {
4148            if (tmp_error != EACCES) {
4149                SMBERROR("smb2_smb_parse_set_info failed %d id %lld\n",
4150                         tmp_error, setinfo_rqp->sr_messageid);
4151            }
4152            error = tmp_error;
4153        }
4154        goto parse_close;
4155    }
4156
4157parse_close:
4158    /* Update closep fid so it gets freed from FID table */
4159    closep->fid = createp->ret_fid;
4160
4161    /* Consume any pad bytes */
4162    tmp_error = smb2_rq_next_command(setinfo_rqp, &next_cmd_offset, mdp);
4163    if (tmp_error) {
4164        /* Failed to find next command, so can't parse rest of the responses */
4165        SMBERROR("setinfo smb2_rq_next_command failed %d\n", tmp_error);
4166        error = error ? error : tmp_error;
4167        goto bad;
4168    }
4169
4170    /*
4171     * Parse Close SMB 2/3 header
4172     */
4173    tmp_error = smb2_rq_parse_header(close_rqp, &mdp);
4174    closep->ret_ntstatus = close_rqp->sr_ntstatus;
4175    if (tmp_error) {
4176        if (!error) {
4177            SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n",
4178                     tmp_error, close_rqp->sr_messageid);
4179            error = tmp_error;
4180        }
4181        goto bad;
4182    }
4183
4184    /* Parse the Close response */
4185    tmp_error = smb2_smb_parse_close(mdp, closep);
4186    if (tmp_error) {
4187        if (!error) {
4188            SMBERROR("smb2_smb_parse_close failed %d id %lld\n",
4189                     tmp_error, close_rqp->sr_messageid);
4190            error = tmp_error;
4191        }
4192        goto bad;
4193    }
4194
4195    /* At this point, fid has been removed from fid table */
4196    need_delete_fid = 0;
4197
4198bad:
4199    if (need_delete_fid == 1) {
4200        /*
4201         * Close failed but the Create worked and was successfully parsed.
4202         * Try issuing the Close request again.
4203         */
4204        tmp_error = smb2_smb_close_fid(share, createp->ret_fid,
4205                                       NULL, NULL, context);
4206        if (tmp_error) {
4207            SMBERROR("Second close failed %d\n", tmp_error);
4208        }
4209    }
4210
4211    if (create_rqp != NULL) {
4212        smb_rq_done(create_rqp);
4213    }
4214    if (setinfo_rqp != NULL) {
4215        smb_rq_done(setinfo_rqp);
4216    }
4217    if (close_rqp != NULL) {
4218        smb_rq_done(close_rqp);
4219    }
4220
4221    if (createp != NULL) {
4222        SMB_FREE(createp, M_SMBTEMP);
4223    }
4224    if (infop != NULL) {
4225        SMB_FREE(infop, M_SMBTEMP);
4226    }
4227    if (closep != NULL) {
4228        SMB_FREE(closep, M_SMBTEMP);
4229    }
4230
4231    if (fap != NULL) {
4232        SMB_FREE(fap, M_SMBTEMP);
4233    }
4234
4235	return error;
4236}
4237
4238int
4239smb2fs_smb_change_notify(struct smb_share *share, uint32_t output_buffer_len,
4240                         uint32_t completion_filter,
4241                         void *fn_callback, void *fn_callback_args,
4242                         vfs_context_t context)
4243{
4244    int error;
4245    struct watch_item *watch_item = fn_callback_args;
4246    struct smb2_change_notify_rq *changep = NULL;
4247    uint32_t flags = 0;
4248
4249    SMB_MALLOC(changep,
4250               struct smb2_change_notify_rq *,
4251               sizeof(struct smb2_change_notify_rq),
4252               M_SMBTEMP,
4253               M_WAITOK | M_ZERO);
4254    if (changep == NULL) {
4255        SMBERROR("SMB_MALLOC failed\n");
4256        error = ENOMEM;
4257        goto bad;
4258    }
4259
4260    /*
4261     * Set up for the Change Notify call
4262     */
4263    if (watch_item->watchTree) {
4264        flags |= SMB2_WATCH_TREE;
4265    }
4266    changep->flags = flags;
4267    if (watch_item->isServerMsg) {
4268        /* special FID to let server know this is a
4269         * Mac-to-Mac srvmsg notify
4270         */
4271        changep->fid = 0xffffffffffffffff;
4272    } else {
4273        changep->fid = watch_item->np->d_fid;
4274    }
4275    changep->output_buffer_len = output_buffer_len;
4276    changep->filter = completion_filter;
4277    changep->fn_callback = fn_callback;
4278    changep->fn_callback_args = fn_callback_args;
4279
4280    /*
4281     * Do the Change Notify call
4282     * Save the rqp into watch_item->rqp
4283     */
4284    error = smb2_smb_change_notify(share, changep, &watch_item->rqp, context);
4285    if (error) {
4286        SMBERROR("smb2_smb_change_notify failed %d\n", error);
4287        goto bad;
4288    }
4289
4290bad:
4291    if (changep != NULL) {
4292        SMB_FREE(changep, M_SMBTEMP);
4293    }
4294
4295    return error;
4296}
4297
4298int
4299smbfs_smb_close(struct smb_share *share, SMBFID fid, vfs_context_t context)
4300{
4301	int error;
4302
4303    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
4304        error = smb2_smb_close_fid(share, fid, NULL, NULL, context);
4305    }
4306    else {
4307        error = smb1fs_smb_close(share, fid, context);
4308    }
4309
4310    /*
4311     * ENOTCONN isn't interesting - if the connection is closed,
4312     * so are all our FIDs - and ENXIO is also not interesting,
4313     * as it means a forced unmount was done.
4314     *
4315     * EBADF means the fid is no longer good. Reconnect will make this happen.
4316     * Should we check to see if the open was broken on the reconnect or does it
4317     * really matter?
4318     *
4319     * Don't clog up the system log with warnings about those failures
4320     * on closes.
4321     */
4322    if ((error == ENOTCONN) || (error == ENXIO) || (error == EBADF)) {
4323        error = 0;
4324    }
4325
4326	return error;
4327}
4328
4329/*
4330 * This routine is used for both Mac-to-Mac and Mac-to-Windows copyfile
4331 * operations.  For Mac-to-Mac, the FSCTL_SRV_COPYCHUNK ioctl is sent with
4332 * a chunk count of zero, because the server uses copyfile(3) and doesn't need
4333 * a list of chunks from the client.  To specify Mac-to-Mac semantics, the
4334 * mac_to_mac parameter should be set to TRUE.
4335 */
4336static int
4337smb2fs_smb_copychunks(struct smb_share *share, SMBFID src_fid,
4338                      SMBFID targ_fid, uint64_t src_file_len,
4339                      int mac_to_mac, vfs_context_t context)
4340{
4341    struct smb2_ioctl_rq            *ioctlp = NULL;
4342    struct smb2_copychunk           *copychunk_hdr;
4343    struct smb2_copychunk_chunk     *copychunk_element;
4344    struct smb2_copychunk_result    *copychunk_result;
4345    char                            *sendbuf = NULL;
4346    uint32_t                        sendbuf_len, src_offset, chunk_count;
4347    uint32_t                        max_chunk_len, retry;
4348    uint64_t                        remaining_len, this_len;
4349    u_char                          resume_key[SMB2_RESUME_KEY_LEN];
4350    int error = 0;
4351
4352    /* Allocate a copychunk header with an array of chunk elements */
4353    sendbuf_len = sizeof(struct smb2_copychunk) +
4354    (sizeof(struct smb2_copychunk_chunk) * SMB2_COPYCHUNK_ARR_SIZE);
4355
4356    /* setup a send buffer for the copychunk headers */
4357    SMB_MALLOC(sendbuf,
4358               char *,
4359               sendbuf_len,
4360               M_SMBTEMP,
4361               M_WAITOK | M_ZERO);
4362    if (sendbuf == NULL) {
4363		SMBERROR("SMB_MALLOC failed\n");
4364        error = ENOMEM;
4365        goto out;
4366    }
4367
4368    /* Begin by getting a resume key from the source */
4369    error = smb2fs_smb_request_resume_key(share, src_fid, resume_key, context);
4370
4371    if (error) {
4372        SMBERROR("Failed to get resume key, error: %d\n", error);
4373        goto out;
4374    }
4375
4376    /*
4377     * Build the IOCTL request
4378     */
4379    SMB_MALLOC(ioctlp,
4380               struct smb2_ioctl_rq *,
4381               sizeof(struct smb2_ioctl_rq),
4382               M_SMBTEMP,
4383               M_WAITOK | M_ZERO);
4384    if (ioctlp == NULL) {
4385		SMBERROR("SMB_MALLOC failed\n");
4386        error = ENOMEM;
4387        goto out;
4388    }
4389
4390    /* We will initialize ioctlp->snd_input_len later */
4391    ioctlp->share = share;
4392    ioctlp->ctl_code = FSCTL_SRV_COPYCHUNK;
4393    ioctlp->fid = targ_fid;
4394    ioctlp->snd_input_buffer = (uint8_t *)sendbuf;
4395    ioctlp->rcv_output_len = sizeof(struct smb2_copychunk_result);
4396
4397    copychunk_hdr = (struct smb2_copychunk *)sendbuf;
4398
4399    /* setup copy chunk hdr */
4400    memcpy(copychunk_hdr->source_key, resume_key, SMB2_RESUME_KEY_LEN);
4401    copychunk_hdr->reserved = 0;
4402
4403    if (mac_to_mac == TRUE) {
4404        /* Mac-to-Mac case */
4405
4406        /* Just a header, no chunks */
4407        ioctlp->snd_input_len = sizeof(struct smb2_copychunk);
4408
4409        copychunk_hdr->chunk_count = 0;
4410
4411        error = smb2_smb_ioctl(share, ioctlp, NULL, context);
4412
4413        if (error) {
4414            SMBDEBUG("smb2_smb_ioctl error: %d\n", error);
4415            goto out;
4416        }
4417
4418        /* sanity check */
4419        if (ioctlp->rcv_output_len < sizeof(struct smb2_copychunk_result)) {
4420            /* big problem, response too small, nothing we can do */
4421            SMBERROR("rcv_output_buffer too small, expected: %lu, got: %u\n",
4422                     sizeof(struct smb2_copychunk_result), ioctlp->rcv_output_len);
4423            error = EINVAL;
4424            goto out;
4425        }
4426
4427        // Check results
4428        if (ioctlp->ret_ntstatus != STATUS_SUCCESS) {
4429            SMBDEBUG("copychunk result: nt_stat: 0x%0x\n", ioctlp->ret_ntstatus);
4430
4431            /* map the nt_status to an errno */
4432            error = smb_ntstatus_to_errno(ioctlp->ret_ntstatus);
4433            goto out;
4434        }
4435    } else {
4436        /* Non Mac-to-Mac case */
4437
4438        retry = 0;
4439        copychunk_element = (struct smb2_copychunk_chunk *)(sendbuf + sizeof(struct smb2_copychunk));
4440        max_chunk_len = SMB2_COPYCHUNK_MAX_CHUNK_LEN;
4441
4442again:
4443        remaining_len = src_file_len;
4444        src_offset = 0;
4445        while (remaining_len) {
4446
4447            /* Fillup the chunk array */
4448            error = smb2fs_smb_fillchunk_arr(copychunk_element,
4449                                    SMB2_COPYCHUNK_ARR_SIZE,
4450                                    remaining_len, max_chunk_len,
4451                                    src_offset, src_offset,
4452                                     &chunk_count, &this_len);
4453            if (error) {
4454                goto out;
4455            }
4456
4457            remaining_len -= this_len;
4458            src_offset += this_len;
4459            copychunk_hdr->chunk_count = chunk_count;
4460
4461            /* snd_input_len depends on how many chunks we're sending */
4462            ioctlp->snd_input_len = sizeof(struct smb2_copychunk) +
4463                (sizeof(struct smb2_copychunk_chunk) * chunk_count);
4464
4465            error = smb2_smb_ioctl(share, ioctlp, NULL, context);
4466
4467            if (error) {
4468                SMBDEBUG("smb2_smb_ioctl error: %d, remain: %llu, max_chunk: %u, count: %u, this_len: %llu\n",
4469                         error, remaining_len, max_chunk_len, chunk_count, this_len);
4470
4471                if (ioctlp->ret_ntstatus != STATUS_INVALID_PARAMETER) {
4472                    goto out;
4473                }
4474            }
4475
4476            /* sanity check */
4477            if ( (ioctlp->rcv_output_len < sizeof(struct smb2_copychunk_result)) ||
4478                (ioctlp->rcv_output_buffer == NULL) ) {
4479                /* big problem, response too small, nothing we can do */
4480                SMBERROR("rcv_output_buffer too small, expected: %lu, got: %u\n",
4481                     sizeof(struct smb2_copychunk_result), ioctlp->rcv_output_len);
4482                error = EINVAL;
4483                goto out;
4484            }
4485
4486            // Check results
4487            copychunk_result = (struct smb2_copychunk_result *)ioctlp->rcv_output_buffer;
4488
4489            if (ioctlp->ret_ntstatus == STATUS_INVALID_PARAMETER && !retry) {
4490                /*
4491                 * Exceeded server's maximum chunk length.  We will try
4492                 * once more using the server's value, which is
4493                 * returned by the server in chunk_bytes_written.
4494                 * See <rdar://problem/14750992>.
4495                 */
4496
4497                if (copychunk_result->chunk_bytes_written < max_chunk_len) {
4498                    max_chunk_len = copychunk_result->chunk_bytes_written;
4499                    retry = 1;
4500
4501                    SMB_FREE(ioctlp->rcv_output_buffer, M_SMBTEMP);
4502                    goto again;
4503                }
4504            }
4505
4506            if (ioctlp->ret_ntstatus != STATUS_SUCCESS) {
4507                SMBDEBUG("smb2_smb_ioctl result: nt_stat: 0x%0x\n", ioctlp->ret_ntstatus);
4508
4509                /* map the nt_status to an errno */
4510                error = smb_ntstatus_to_errno(ioctlp->ret_ntstatus);
4511                goto out;
4512            }
4513
4514            if (copychunk_result->chunks_written != copychunk_hdr->chunk_count) {
4515                SMBERROR("copychunk error: chunks_written: %u, expected: %u\n",
4516                         copychunk_result->chunks_written, copychunk_hdr->chunk_count);
4517                error = EIO;
4518                goto out;
4519            }
4520
4521            if (copychunk_result->total_bytes_written != this_len) {
4522                SMBERROR("copychunk error: total_bytes_written: %u, expected: %llu\n",
4523                         copychunk_result->total_bytes_written, this_len);
4524                error = EIO;
4525                goto out;
4526            }
4527
4528            SMB_FREE(ioctlp->rcv_output_buffer, M_SMBTEMP);
4529        }
4530    }
4531out:
4532    // clean house
4533    if (sendbuf != NULL) {
4534        SMB_FREE(sendbuf, M_SMBTEMP);
4535    }
4536
4537    if (ioctlp != NULL) {
4538        if (ioctlp->rcv_output_buffer != NULL) {
4539            SMB_FREE(ioctlp->rcv_output_buffer, M_SMBTEMP);
4540        }
4541
4542        SMB_FREE(ioctlp, M_SMBTEMP);
4543    }
4544
4545    return (error);
4546}
4547
4548int
4549smb2fs_smb_copyfile(struct smb_share *share, struct smbnode *src_np,
4550                    struct smbnode *tdnp, const char *tnamep,
4551                    size_t tname_len, vfs_context_t context)
4552{
4553    struct smbfattr *sfap = NULL, *tfap = NULL;
4554    char            *xattr_list = NULL, *xattrp = NULL;
4555    SMBFID          src_fid = 0, targ_fid = 0, src_xattr_fid = 0, targ_xattr_fid = 0;
4556    size_t          xattrlist_len = 0, remaining_len = 0, this_len;
4557    uint32_t        desired_access, share_access, disp;
4558    boolean_t       src_is_open = FALSE, targ_is_open = FALSE;
4559    boolean_t       srcxattr_is_open = FALSE, targxattr_is_open = FALSE;
4560    uint64_t        create_flags, src_file_len;
4561    struct timespec mtime;
4562    int             error = 0;
4563    uint32_t        ntstatus = 0;
4564    uint32_t        target_created = 0;
4565    uint32_t create_options = 0;
4566    enum vtype vnode_type = VREG;
4567
4568    if ((SSTOVC(share)->vc_misc_flags & SMBV_OSX_SERVER) &&
4569        (SSTOVC(share)->vc_server_caps & kAAPL_SUPPORTS_OSX_COPYFILE)) {
4570        /* Mac-to-Mac copyfile */
4571        return smb2fs_smb_copyfile_mac(share, src_np,
4572                                       tdnp, tnamep,
4573                                       tname_len, context);
4574    }
4575
4576    /* We'll need a couple of fattrs */
4577    SMB_MALLOC(sfap,
4578               struct smbfattr *,
4579               sizeof(struct smbfattr),
4580               M_SMBTEMP,
4581               M_WAITOK | M_ZERO);
4582    if (sfap == NULL) {
4583        SMBERROR("SMB_MALLOC failed, sfap\n");
4584        error = ENOMEM;
4585        goto out;
4586    }
4587
4588    SMB_MALLOC(tfap,
4589               struct smbfattr *,
4590               sizeof(struct smbfattr),
4591               M_SMBTEMP,
4592               M_WAITOK | M_ZERO);
4593    if (tfap == NULL) {
4594        SMBERROR("SMB_MALLOC failed, tfap\n");
4595        error = ENOMEM;
4596        goto out;
4597    }
4598
4599    /*******************************/
4600    /* Get list of src file xattrs */
4601    /*******************************/
4602    if (share->ss_attributes & FILE_NAMED_STREAMS) {
4603        error = smb2fs_smb_listxattrs(share, src_np, &xattr_list,
4604                                      &xattrlist_len, context);
4605        if (error) {
4606            SMBDEBUG("listxattrs failed, error: %d\n", error);
4607            goto out;
4608        }
4609    }
4610
4611    /********************/
4612    /* Open source file */
4613    /********************/
4614    desired_access = SMB2_FILE_READ_DATA | SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_READ_EA;
4615    share_access = NTCREATEX_SHARE_ACCESS_READ;
4616    disp = FILE_OPEN;
4617    create_flags = 0;
4618
4619    create_options = smb2fs_smb_get_create_options(share, src_np,
4620                                                   NULL, NULL,
4621                                                   vnode_type, 0);
4622    error = smb2fs_smb_ntcreatex(share, src_np,
4623                                 NULL, 0,
4624                                 NULL, 0,
4625                                 desired_access, vnode_type,
4626                                 share_access, disp,
4627                                 create_flags, create_options,
4628                                 &src_fid, sfap,
4629                                 NULL, NULL,
4630                                 NULL, context);
4631
4632    if (error) {
4633        SMBDEBUG("smb2fs_smb_ntcreatex failed (src file) %d\n", error);
4634        goto out;
4635    }
4636
4637    src_is_open = TRUE;
4638    src_file_len = sfap->fa_size;
4639
4640    /***************************/
4641    /* Open/Create target file */
4642    /***************************/
4643    desired_access = SMB2_FILE_READ_DATA | SMB2_FILE_WRITE_DATA | SMB2_FILE_APPEND_DATA |
4644    SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_WRITE_ATTRIBUTES | SMB2_FILE_WRITE_EA;
4645    disp = FILE_OVERWRITE_IF;
4646    create_flags = SMB2_CREATE_DO_CREATE;
4647    share_access = 0; /* No Access */
4648
4649    /* Do a Create */
4650    error = smb2fs_smb_cmpd_create(share, tdnp,
4651                                   tnamep, tname_len,
4652                                   NULL, 0,
4653                                   desired_access, VREG,
4654                                   share_access, disp,
4655                                   create_flags, &ntstatus,
4656                                   &targ_fid, tfap,
4657                                   NULL, context);
4658
4659    if (error) {
4660        SMBDEBUG("smb2fs_smb_ntcreatex failed (targ file) %d\n", error);
4661        goto out;
4662    }
4663
4664    targ_is_open = TRUE;
4665    target_created = 1;
4666
4667    /*************************************/
4668    /* Now initiate the server-side copy */
4669    /*************************************/
4670    error = smb2fs_smb_copychunks(share, src_fid,
4671                                  targ_fid, src_file_len,
4672                                  FALSE, context);
4673
4674    if (error) {
4675        SMBDEBUG("smb2fs_smb_copychunks failed (file data) %d\n", error);
4676        goto out;
4677    }
4678
4679    /********************************/
4680    /* Set metadata of target file. */
4681    /********************************/
4682
4683    /* Set EOF of target file */
4684    error = smb2fs_smb_set_eof(share, targ_fid, src_file_len, context);
4685    if (error) {
4686        SMBDEBUG("failed setting target eof, error: %d\n", error);
4687        goto out;
4688    }
4689
4690    /*
4691     * Set LastWriteTime timestamp of target file.
4692     *
4693     * Note: Windows clients will also set LastChangeTime here,
4694     * but we don't allow anyone to set the change time.
4695     */
4696    nanotime(&mtime);
4697    error = smbfs_smb_setfattrNT(share, 0, targ_fid, NULL, &mtime, NULL, context);
4698    if (error) {
4699        SMBDEBUG("failed setting mtime: %d\n", error);
4700        goto out;
4701    }
4702
4703    /*********************************/
4704    /* Close source and target files */
4705    /*********************************/
4706    smb2_smb_close_fid(share, src_fid, NULL, NULL, context);
4707    smb2_smb_close_fid(share, targ_fid, NULL, NULL, context);
4708    src_is_open = FALSE;
4709    targ_is_open = FALSE;
4710
4711    /*******************************/
4712    /* Copy named streams (if any) */
4713    /*******************************/
4714    xattrp = xattr_list;
4715    remaining_len = xattrlist_len;
4716    while (remaining_len) {
4717        this_len = strnlen(xattrp, xattrlist_len);
4718
4719        /********************************************/
4720        /* Open src_xattr, Open/Create target xattr */
4721        /********************************************/
4722        desired_access = SMB2_FILE_READ_DATA | SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_READ_EA;
4723        share_access = NTCREATEX_SHARE_ACCESS_READ;
4724        disp = FILE_OPEN;
4725        create_flags = SMB2_CREATE_IS_NAMED_STREAM;
4726
4727        create_options = smb2fs_smb_get_create_options(share, src_np,
4728                                                       NULL, xattrp,
4729                                                       vnode_type, 0);
4730        error = smb2fs_smb_ntcreatex(share, src_np,
4731                                     NULL, 0,
4732                                     xattrp, this_len,
4733                                     desired_access, vnode_type,
4734                                     share_access, disp,
4735                                     create_flags, create_options,
4736                                     &src_xattr_fid, sfap,
4737                                     NULL, NULL,
4738                                     NULL, context);
4739        if (error) {
4740            SMBDEBUG("smb2fs_smb_ntcreatex failed (src xattr), error: %d\n", error);
4741            goto out;
4742        }
4743
4744        srcxattr_is_open = TRUE;
4745        src_file_len = sfap->fa_size;
4746
4747        /* Open/Create target file xattr */
4748        desired_access = SMB2_FILE_READ_DATA | SMB2_FILE_WRITE_DATA | SMB2_FILE_APPEND_DATA |
4749        SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_WRITE_ATTRIBUTES | SMB2_FILE_WRITE_EA;
4750        disp = FILE_OVERWRITE_IF;
4751        create_flags = SMB2_CREATE_IS_NAMED_STREAM | SMB2_CREATE_DO_CREATE;
4752        share_access = 0; /* No Access */
4753
4754        /* Do a Create */
4755        error = smb2fs_smb_cmpd_create(share, tdnp,
4756                                       tnamep, tname_len,
4757                                       xattrp, this_len,
4758                                       desired_access, VREG,
4759                                       share_access, disp,
4760                                       create_flags, &ntstatus,
4761                                       &targ_xattr_fid, tfap,
4762                                       NULL, context);
4763
4764        if (error) {
4765            SMBDEBUG("smb2fs_smb_ntcreatex failed (targ xattr), error: %d\n", error);
4766            goto out;
4767        }
4768
4769        targxattr_is_open = TRUE;
4770
4771        /*************************************/
4772        /* Now initiate the server-side copy */
4773        /*************************************/
4774        error = smb2fs_smb_copychunks(share, src_xattr_fid,
4775                                      targ_xattr_fid, src_file_len,
4776                                      FALSE, context);
4777
4778        if (error) {
4779            SMBDEBUG("smb2fs_smb_copychunks failed (xattr), error: %d\n", error);
4780            goto out;
4781        }
4782
4783        /*********************************/
4784        /* Set metadata of target xattr. */
4785        /*********************************/
4786
4787        /* Set EOF */
4788        error = smb2fs_smb_set_eof(share, targ_xattr_fid, src_file_len, context);
4789        if (error) {
4790            SMBDEBUG("failed setting target xattr eof, error: %d\n", error);
4791            goto out;
4792        }
4793
4794        /*
4795         * Set LastWriteTime timestamp of target file.
4796         *
4797         * Note: Windows clients will also set LastChangeTime here,
4798         * but we don't allow anyone to set the change time.
4799         */
4800        nanotime(&mtime);
4801        error = smbfs_smb_setfattrNT(share, 0, targ_xattr_fid, NULL, &mtime, NULL, context);
4802        if (error) {
4803            SMBDEBUG("failed setting xattr mtime: %d\n", error);
4804            goto out;
4805        }
4806
4807        /**********************************/
4808        /* Close source and target xattrs */
4809        /**********************************/
4810        smb2_smb_close_fid(share, src_xattr_fid, NULL, NULL, context);
4811        smb2_smb_close_fid(share, targ_xattr_fid, NULL, NULL, context);
4812        srcxattr_is_open = FALSE;
4813        targxattr_is_open = FALSE;
4814
4815        /* Skip over terminating NULL, advance to next xattr name */
4816        this_len += 1;
4817        remaining_len -= this_len;
4818        if (xattrlist_len) {
4819            xattrp += this_len;
4820        }
4821    }
4822
4823out:
4824    /* Clean house */
4825    if (src_is_open == TRUE) {
4826        smb2_smb_close_fid(share, src_fid, NULL, NULL, context);
4827    }
4828
4829    if (srcxattr_is_open == TRUE) {
4830        smb2_smb_close_fid(share, src_xattr_fid, NULL, NULL, context);
4831    }
4832
4833    if (targ_is_open == TRUE) {
4834        smb2_smb_close_fid(share, targ_fid, NULL, NULL, context);
4835    }
4836
4837    if (targxattr_is_open == TRUE) {
4838        smb2_smb_close_fid(share, targ_xattr_fid, NULL, NULL, context);
4839    }
4840
4841    if (xattr_list != NULL) {
4842        SMB_FREE(xattr_list, M_SMBTEMP);
4843    }
4844
4845    if (sfap != NULL) {
4846        SMB_FREE(sfap, M_SMBTEMP);
4847    }
4848
4849    if (tfap != NULL) {
4850        SMB_FREE(tfap, M_SMBTEMP);
4851    }
4852
4853    if ((error) && (target_created == 1)) {
4854        /* Try to delete the target file we created */
4855        smbfs_smb_delete(share, tdnp, VREG,
4856                         tnamep, tname_len,
4857                         0, context);
4858    }
4859
4860    return error;
4861}
4862
4863static int
4864smb2fs_smb_copyfile_mac(struct smb_share *share, struct smbnode *src_np,
4865                        struct smbnode *tdnp, const char *tnamep, size_t tname_len,
4866                        vfs_context_t context)
4867{
4868    struct smbfattr *sfap = NULL, *tfap = NULL;
4869    SMBFID          src_fid = 0, targ_fid = 0;
4870    uint32_t        desired_access, share_access, disp;
4871    boolean_t       src_is_open = FALSE, targ_is_open = FALSE;
4872    uint64_t        create_flags;
4873    int             error = 0;
4874    uint32_t        ntstatus = 0;
4875    uint32_t        target_created = 0;
4876    uint32_t create_options = 0;
4877    enum vtype vnode_type = VREG;
4878
4879    /* We'll need a couple of fattrs */
4880    SMB_MALLOC(sfap,
4881               struct smbfattr *,
4882               sizeof(struct smbfattr),
4883               M_SMBTEMP,
4884               M_WAITOK | M_ZERO);
4885    if (sfap == NULL) {
4886        SMBERROR("SMB_MALLOC failed, sfap\n");
4887        error = ENOMEM;
4888        goto out;
4889    }
4890
4891    SMB_MALLOC(tfap,
4892               struct smbfattr *,
4893               sizeof(struct smbfattr),
4894               M_SMBTEMP,
4895               M_WAITOK | M_ZERO);
4896    if (tfap == NULL) {
4897        SMBERROR("SMB_MALLOC failed, tfap\n");
4898        error = ENOMEM;
4899        goto out;
4900    }
4901
4902    /*********************************************/
4903    /* Open source file, Open/Create target file */
4904    /*********************************************/
4905    desired_access = SMB2_FILE_READ_DATA | SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_READ_EA;
4906    share_access = NTCREATEX_SHARE_ACCESS_READ;
4907    disp = FILE_OPEN;
4908    create_flags = 0;
4909
4910    create_options = smb2fs_smb_get_create_options(share, src_np,
4911                                                   NULL, NULL,
4912                                                   vnode_type, 0);
4913    error = smb2fs_smb_ntcreatex(share, src_np,
4914                                 NULL, 0,
4915                                 NULL, 0,
4916                                 desired_access, vnode_type,
4917                                 share_access, disp,
4918                                 create_flags, create_options,
4919                                 &src_fid, sfap,
4920                                 NULL, NULL,
4921                                 NULL, context);
4922
4923    if (error) {
4924        SMBDEBUG("smb2fs_smb_ntcreatex failed (src file) %d\n", error);
4925        goto out;
4926    }
4927
4928    src_is_open = TRUE;
4929
4930    /***************************/
4931    /* Open/Create target file */
4932    /***************************/
4933    desired_access = SMB2_FILE_READ_DATA | SMB2_FILE_WRITE_DATA | SMB2_FILE_APPEND_DATA |
4934    SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_WRITE_ATTRIBUTES | SMB2_FILE_WRITE_EA;
4935    disp = FILE_OVERWRITE_IF;
4936    create_flags = SMB2_CREATE_DO_CREATE;
4937    share_access = 0; /* No Access */
4938
4939    /* Do a Create */
4940    error = smb2fs_smb_cmpd_create(share, tdnp,
4941                                   tnamep, tname_len,
4942                                   NULL, 0,
4943                                   desired_access, VREG,
4944                                   share_access, disp,
4945                                   create_flags, &ntstatus,
4946                                   &targ_fid, tfap,
4947                                   NULL, context);
4948
4949    if (error) {
4950        SMBDEBUG("smb2fs_smb_ntcreatex failed (targ file) %d\n", error);
4951        goto out;
4952    }
4953
4954    targ_is_open = TRUE;
4955    target_created = 1;
4956
4957    /*************************************/
4958    /* Now initiate the server-side copy */
4959    /*************************************/
4960    error = smb2fs_smb_copychunks(share, src_fid,
4961                                  targ_fid, 0,
4962                                  TRUE, context);
4963
4964    if (error) {
4965        SMBDEBUG("smb2fs_smb_copychunks_mac failed (file data) %d\n", error);
4966        goto out;
4967    }
4968
4969    /*********************************/
4970    /* Close source and target files */
4971    /*********************************/
4972    smb2_smb_close_fid(share, src_fid, NULL, NULL, context);
4973    smb2_smb_close_fid(share, targ_fid, NULL, NULL, context);
4974    src_is_open = FALSE;
4975    targ_is_open = FALSE;
4976
4977out:
4978    /* Clean house */
4979    if (src_is_open == TRUE) {
4980        smb2_smb_close_fid(share, src_fid, NULL, NULL, context);
4981    }
4982
4983    if (targ_is_open == TRUE) {
4984        smb2_smb_close_fid(share, targ_fid, NULL, NULL, context);
4985    }
4986
4987    if (sfap != NULL) {
4988        SMB_FREE(sfap, M_SMBTEMP);
4989    }
4990
4991    if (tfap != NULL) {
4992        SMB_FREE(tfap, M_SMBTEMP);
4993    }
4994
4995    if ((error) && (target_created == 1)) {
4996        /* Try to delete the target file we created */
4997        smbfs_smb_delete(share, tdnp, VREG,
4998                         tnamep, tname_len,
4999                         0, context);
5000    }
5001
5002    return error;
5003}
5004
5005int
5006smbfs_smb_create_reparse_symlink(struct smb_share *share, struct smbnode *dnp,
5007                                 const char *namep, size_t name_len,
5008                                 char *targetp, size_t target_len,
5009                                 struct smbfattr *fap, vfs_context_t context)
5010{
5011    int error;
5012
5013    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
5014        error = smb2fs_smb_cmpd_reparse_point_set(share, dnp,
5015                                                  namep, name_len,
5016                                                  targetp, target_len,
5017                                                  fap, context);
5018    }
5019    else {
5020        error = smb1fs_smb_create_reparse_symlink(share, dnp,
5021                                                  namep, name_len,
5022                                                  targetp, target_len,
5023                                                  fap, context);
5024    }
5025
5026    return error;
5027
5028}
5029
5030static int
5031smb2fs_smb_delete(struct smb_share *share, struct smbnode *np, enum vtype vnode_type,
5032                  const char *namep, size_t name_len,
5033                  int xattr, vfs_context_t context)
5034{
5035    int error;
5036    uint32_t setinfo_ntstatus;
5037    uint8_t delete_byte = 1;
5038
5039    /*
5040     * Looking at Win <-> Win with SMB 2/3, delete is handled by opening the file
5041     * with Delete and "Read Attributes", then a Set Info is done to set
5042     * "Delete on close", then a Close is sent.
5043     */
5044
5045    /*
5046     * Do the Compound Create/SetInfo/Close call
5047     */
5048    error = smb2fs_smb_cmpd_set_info(share, np, vnode_type,
5049                                     namep, name_len,
5050                                     xattr, SMB2_FILE_READ_ATTRIBUTES | SMB2_STD_ACCESS_DELETE | SMB2_SYNCHRONIZE,
5051                                     SMB2_0_INFO_FILE, FileDispositionInformation,
5052                                     0,
5053                                     sizeof (delete_byte), (uint8_t *) &delete_byte,
5054                                     &setinfo_ntstatus,
5055                                     context);
5056    if (error) {
5057        if (error != ENOTEMPTY) {
5058            SMBDEBUG_LOCK(np, "smb2fs_smb_cmpd_set_info failed %d %s:%s\n", error, np->n_name, namep);
5059        }
5060        goto bad;
5061    }
5062
5063bad:
5064    return error;
5065}
5066
5067/*
5068 * The calling routine must hold a reference on the share
5069 */
5070int
5071smbfs_smb_delete(struct smb_share *share, struct smbnode *np, enum vtype vnode_type,
5072				 const char *name, size_t nmlen,
5073                 int xattr, vfs_context_t context)
5074{
5075    int error;
5076
5077    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
5078        error = smb2fs_smb_delete (share, np, vnode_type,
5079                                   name, nmlen,
5080                                   xattr, context);
5081    }
5082    else {
5083        error = smb1fs_smb_delete (share, np, name, nmlen, xattr, context);
5084    }
5085
5086    return error;
5087}
5088
5089static uint32_t
5090smb2fs_smb_fillchunk_arr(struct smb2_copychunk_chunk *chunk_arr,
5091                         uint32_t chunk_arr_size,
5092                         uint64_t total_len, uint32_t max_chunk_len,
5093                         uint64_t src_offset, uint64_t trg_offset,
5094                         uint32_t *chunk_count_out, uint64_t *total_len_out)
5095{
5096    uint64_t len_remaining = total_len;
5097    uint64_t total_chunk_len, src_off, trg_off;
5098    uint32_t i, chunk_count, this_chunk_len;
5099
5100    src_off = src_offset;
5101    trg_off = trg_offset;
5102
5103    chunk_count = 0;
5104    total_chunk_len = 0;
5105    for (i = 0; i < chunk_arr_size; i++) {
5106        if (!len_remaining) {
5107            // all done
5108            break;
5109        }
5110
5111        if (len_remaining > max_chunk_len) {
5112            this_chunk_len = max_chunk_len;
5113        }
5114        else {
5115            /* Cast is fine, here */
5116            this_chunk_len = (uint32_t)len_remaining;
5117        }
5118
5119        chunk_arr[i].length = this_chunk_len;
5120        chunk_arr[i].reserved = 0;
5121        chunk_arr[i].source_offset = src_off;
5122        chunk_arr[i].target_offset = trg_off;
5123
5124        total_chunk_len += this_chunk_len;
5125        len_remaining -= this_chunk_len;
5126        chunk_count++;
5127        src_off += this_chunk_len;
5128        trg_off += this_chunk_len;
5129    }
5130
5131    *chunk_count_out = chunk_count;
5132    *total_len_out = total_chunk_len;
5133    return (0);
5134}
5135
5136int
5137smbfs_smb_findclose(struct smbfs_fctx *ctx, vfs_context_t context)
5138{
5139    int error;
5140
5141    if (SSTOVC(ctx->f_share)->vc_flags & SMBV_SMB2) {
5142        if (ctx->f_create_rqp) {
5143            smb_rq_done(ctx->f_create_rqp);
5144            ctx->f_create_rqp = NULL;
5145        }
5146        if (ctx->f_query_rqp) {
5147            smb_rq_done(ctx->f_query_rqp);
5148            ctx->f_query_rqp = NULL;
5149        }
5150
5151        /* Close Create FID if we need to */
5152        if (ctx->f_need_close == TRUE) {
5153            error = smb2_smb_close_fid(ctx->f_share, ctx->f_create_fid,
5154                                       NULL, NULL, context);
5155            if (error) {
5156                SMBDEBUG("smb2_smb_close_fid failed %d\n", error);
5157            }
5158            ctx->f_need_close = FALSE;
5159        }
5160
5161        /* We are done with the share release our reference */
5162        smb_share_rele(ctx->f_share, context);
5163
5164        if (ctx->f_LocalName) {
5165            SMB_FREE(ctx->f_LocalName, M_SMBFSDATA);
5166        }
5167
5168        if (ctx->f_NetworkNameBuffer) {
5169            SMB_FREE(ctx->f_NetworkNameBuffer, M_SMBFSDATA);
5170        }
5171
5172        if (ctx->f_rname) {
5173            SMB_FREE(ctx->f_rname, M_SMBFSDATA);
5174        }
5175
5176        SMB_FREE(ctx, M_SMBFSDATA);
5177        return 0;
5178    }
5179    else {
5180        error = smb1fs_smb_findclose(ctx, context);
5181        return (error);
5182    }
5183
5184}
5185
5186static int
5187smb2fs_smb_findnext(struct smbfs_fctx *ctx, vfs_context_t context)
5188{
5189	struct timespec ts;
5190    int error = EINVAL;
5191	struct mdchain *mdp;
5192    struct smb2_query_dir_rq *queryp = NULL;
5193    uint8_t info_class, flags;
5194    uint32_t file_index;
5195    int attempts = 0;
5196
5197    SMB_MALLOC(queryp,
5198               struct smb2_query_dir_rq *,
5199               sizeof(struct smb2_query_dir_rq),
5200               M_SMBTEMP,
5201               M_WAITOK | M_ZERO);
5202    if (queryp == NULL) {
5203        SMBERROR("SMB_MALLOC failed\n");
5204        error = ENOMEM;
5205        goto bad;
5206    }
5207
5208	if (ctx->f_output_buf_len == 0) {
5209        /*
5210         * if no more output buffer bytes to parse, then we have finished
5211         * parsing out all the entries from this search.
5212         */
5213		if (ctx->f_flags & SMBFS_RDD_EOF) {
5214            error = ENOENT;
5215            goto bad;
5216        }
5217
5218		nanouptime(&ts);
5219
5220        /* free any previous search requests */
5221        if (ctx->f_create_rqp) {
5222            smb_rq_done(ctx->f_create_rqp);
5223            ctx->f_create_rqp = NULL;
5224        }
5225        if (ctx->f_query_rqp) {
5226            smb_rq_done(ctx->f_query_rqp);
5227            ctx->f_query_rqp = NULL;
5228        }
5229
5230        /* Clear resume file name */
5231        ctx->f_flags &= ~SMBFS_RDD_GOTRNAME;
5232
5233        /* Is the dir already open? */
5234        if (ctx->f_need_close == FALSE) {
5235            /*
5236             * Dir needs to be opened first so do a Create/Query Dir
5237             * fid is -1 for compound requests
5238             */
5239            ctx->f_create_fid = 0xffffffffffffffff;
5240        }
5241
5242        /*
5243         * Set up for the Query Dir call
5244         */
5245
5246        /* If not a wildcard search, then want first search entry returned */
5247        flags = 0;
5248        if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
5249            flags |= SMB2_RETURN_SINGLE_ENTRY;
5250        }
5251
5252        /* Resuming a search happens by default, no need to use File Index */
5253        file_index = 0;
5254
5255        if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
5256            /* Because this is first search, set some flags */
5257            flags |= SMB2_RESTART_SCANS;    /* start search from beginning */
5258            file_index = 0;                 /* no FileIndex from prev search */
5259        }
5260
5261        switch (ctx->f_infolevel) {
5262            case SMB_FIND_FULL_DIRECTORY_INFO:
5263                /* For SMB 2/3, get the file/dir IDs too but no short names */
5264                info_class = FileIdFullDirectoryInformation;
5265                break;
5266
5267            case SMB_FIND_BOTH_DIRECTORY_INFO:
5268                /* For SMB 2/3, get the file/dir IDs too */
5269                info_class = FileIdBothDirectoryInformation;
5270                break;
5271
5272            default:
5273                SMBERROR("invalid infolevel %d", ctx->f_infolevel);
5274                error = EINVAL;
5275                goto bad;
5276        }
5277
5278again:
5279        queryp->file_info_class = info_class;
5280        queryp->flags = flags;
5281        queryp->file_index = file_index;
5282        queryp->fid = ctx->f_create_fid;
5283
5284        /* handle servers that dislike large output buffer lens */
5285        if (SSTOVC(ctx->f_share)->vc_misc_flags & SMBV_64K_QUERY_DIR) {
5286            queryp->output_buffer_len = kSMB_64K;
5287        }
5288        else {
5289            queryp->output_buffer_len = MIN(SSTOVC(ctx->f_share)->vc_txmax,
5290                                            kSMB_MAX_TX);
5291        }
5292
5293        /*
5294         * Copy in whether to use UTF_SFM_CONVERSIONS or not
5295         * Seems like if NOT a wildcard, then use UTF_SFM_CONVERSIONS
5296         */
5297        queryp->name_flags = ctx->f_sfm_conversion;
5298
5299        queryp->dnp = ctx->f_dnp;
5300        queryp->namep = (char*) ctx->f_lookupName;
5301        queryp->name_len = (uint32_t) ctx->f_lookupNameLen;
5302
5303        if (ctx->f_need_close == FALSE) {
5304            /* Build and send a Create/Query dir */
5305            error = smb2fs_smb_cmpd_query_dir(ctx, queryp, context);
5306        }
5307        else {
5308            /* Just send a single Query Dir */
5309            error = smb2_smb_query_dir(ctx->f_share, queryp, NULL, context);
5310
5311            /* save f_query_rqp so it can be freed later */
5312            ctx->f_query_rqp = queryp->ret_rqp;
5313        }
5314
5315        if (error) {
5316            if (error == ENOENT) {
5317                ctx->f_flags |= SMBFS_RDD_EOF;
5318            }
5319
5320            /* handle servers that dislike large output buffer lens */
5321            if ((error == EINVAL) &&
5322                (queryp->ret_ntstatus == STATUS_INVALID_PARAMETER) &&
5323                !((SSTOVC(ctx->f_share)->vc_misc_flags) & SMBV_64K_QUERY_DIR) &&
5324                (attempts == 0)) {
5325                SMBWARNING("SMB 2/3 server cant handle large OutputBufferLength in Query_Dir. Reducing to 64Kb.\n");
5326                SSTOVC(ctx->f_share)->vc_misc_flags |= SMBV_64K_QUERY_DIR;
5327                attempts += 1;
5328
5329                if (ctx->f_create_rqp) {
5330                    smb_rq_done(ctx->f_create_rqp);
5331                    ctx->f_create_rqp = NULL;
5332                }
5333                if (ctx->f_query_rqp) {
5334                    smb_rq_done(ctx->f_query_rqp);
5335                    ctx->f_query_rqp = NULL;
5336                }
5337                goto again;
5338            }
5339
5340            goto bad;
5341        }
5342
5343        ctx->f_output_buf_len = queryp->ret_buffer_len;
5344
5345        if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
5346            /* next find will be a Find Next */
5347            ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
5348        }
5349
5350        ctx->f_eofs = 0;
5351        ctx->f_attr.fa_reqtime = ts;
5352	}
5353
5354    /*
5355     * Either we did a new search and we are parsing the first entry out or
5356     * we are just parsing more names out of a previous search.
5357     */
5358    ctx->f_NetworkNameLen = 0;
5359
5360    /* at this point, mdp is pointing to output buffer */
5361    if (ctx->f_create_rqp != NULL) {
5362        /*
5363         * <14227703> Check to see if server is using non compound replies.
5364         * If SMB2_RESPONSE is set in queyr_rqp, then server is not using
5365         * compound replies and thusreply is in the query_rqp
5366         */
5367        if (!(ctx->f_query_rqp->sr_extflags & SMB2_RESPONSE)) {
5368            /* Did a compound request so data is in create_rqp */
5369            smb_rq_getreply(ctx->f_create_rqp, &mdp);
5370        }
5371        else {
5372            /* Server does not support compound replies */
5373            smb_rq_getreply(ctx->f_query_rqp, &mdp);
5374        }
5375    }
5376    else {
5377        /* Only a Query Dir, so data is in query_rqp */
5378        smb_rq_getreply(ctx->f_query_rqp, &mdp);
5379    }
5380
5381    /*
5382     * Parse one entry out of the output buffer and store results into ctx
5383     */
5384	switch (ctx->f_infolevel) {
5385        case SMB_FIND_FULL_DIRECTORY_INFO:
5386        case SMB_FIND_BOTH_DIRECTORY_INFO:
5387            /* Call the parsing function */
5388            error = smb2_smb_parse_query_dir_both_dir_info(ctx->f_share, mdp,
5389                                                           ctx->f_infolevel,
5390                                                           ctx, &ctx->f_attr,
5391                                                           ctx->f_NetworkNameBuffer, &ctx->f_NetworkNameLen,
5392                                                           ctx->f_MaxNetworkNameBufferSize);
5393            if (error) {
5394                goto bad;
5395            }
5396            break;
5397        default:
5398            SMBERROR("unexpected info level %d\n", ctx->f_infolevel);
5399            return EINVAL;
5400	}
5401
5402bad:
5403    if (queryp != NULL) {
5404        SMB_FREE(queryp, M_SMBTEMP);
5405    }
5406
5407    return error;
5408}
5409
5410int
5411smbfs_smb_findnext(struct smbfs_fctx *ctx, vfs_context_t context)
5412{
5413   	struct smb_vc *vcp = SSTOVC(ctx->f_share);
5414	int error;
5415
5416    if (vcp->vc_flags & SMBV_SMB2) {
5417        error = smb2fs_smb_findnext(ctx, context);
5418    }
5419    else {
5420        error = smb1fs_smb_findnext(ctx, context);
5421    }
5422
5423    return error;
5424}
5425
5426/*
5427 * This routine will send a flush across the wire to the server. This is an expensive
5428 * operation that should only be done when the user request it.
5429 *
5430 * The calling routine must hold a reference on the share
5431 *
5432 */
5433int
5434smbfs_smb_flush(struct smb_share *share, SMBFID fid, vfs_context_t context)
5435{
5436    int error;
5437
5438    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
5439        error = smb2_smb_flush(share, fid, context);
5440    }
5441    else {
5442        error = smb1fs_smb_flush(share, fid, context);
5443    }
5444    return error;
5445}
5446
5447uint32_t
5448smb2fs_smb_get_create_options(struct smb_share *share, struct smbnode *np,
5449                              const char *namep, const char *strm_namep,
5450                              enum vtype vnode_type, uint32_t check_reparse)
5451{
5452    uint32_t create_options = 0;
5453
5454    /*
5455     * smb2fs_smb_get_create_options() has various ways it can be called
5456     * 1) np - open item (np)
5457     * 2) np, namep - open the child (namep) in parent dir (np)
5458     * 3) np, strm_namep - open named stream (strm_namep) of item (np)
5459     * 4) np, namep, strm_namep - open named stream of (strm_namep) of
5460     * child (namep) in parent dir (np)
5461     */
5462
5463    /* If its a dir, then set the dir option */
5464    if (vnode_type == VDIR) {
5465        create_options |= NTCREATEX_OPTIONS_DIRECTORY;
5466    }
5467
5468    /*
5469     * If it a reparse point, then we have to be careful on whether to set
5470     * NTCREATEX_OPTIONS_OPEN_REPARSE_POINT or not.
5471     *
5472     * Most of the time we do not to set the reparse bit. This allows the
5473     * reparse point to go ahead and trigger a mount if needed.  For example,
5474     * if the reparse point is a folder that is really an NTFS mount.
5475     *
5476     * If we are doing Create/QueryInfo or Create/SetInfo on the reparse point,
5477     * then set the reparse bit so we change the reparse point itself and not
5478     * its target.
5479     */
5480    if (check_reparse == 0) {
5481        /* Go ahead and trigger the reparse point */
5482        goto done;
5483    }
5484
5485    if ((share) && !(share->ss_attributes & FILE_SUPPORTS_REPARSE_POINTS)) {
5486        /* No reparse points, so no need to set reparse point bit */
5487        goto done;
5488    }
5489
5490    /* Case (1) */
5491    if ((np) &&
5492        (namep == NULL) &&
5493        (strm_namep == NULL)) {
5494        /*
5495         * If its some type of reparse point and it has not been moved to
5496         * offline storage, open the reparse point itself.
5497         */
5498        if ((np->n_dosattr & SMB_EFA_REPARSE_POINT) &&
5499            !(np->n_dosattr & SMB_EFA_OFFLINE)){
5500            create_options |= NTCREATEX_OPTIONS_OPEN_REPARSE_POINT;
5501        }
5502    }
5503
5504    /*
5505     * For cases (2) - (4), the Create will be on a parent dir or opening a
5506     * named stream. In either case we should not need to set the
5507     * NTCREATEX_OPTIONS_OPEN_REPARSE_POINT bit.
5508     */
5509
5510done:
5511    return(create_options);
5512}
5513
5514static int
5515smb2fs_smb_listxattrs(struct smb_share *share, struct smbnode *np, char **xattrlist,
5516                      size_t *xattrlist_len, vfs_context_t context)
5517{
5518    uio_t   xuio = NULL;
5519    size_t  xattr_len = 0;
5520    char    *xattrb = NULL;
5521    uint32_t flags = 0, max_access = 0;
5522    int     error = 0;
5523    enum vtype vnode_type = VREG;
5524
5525    if (np == NULL) {
5526        SMBERROR("Missing vnode\n");
5527        error = EINVAL;
5528        goto out;
5529    }
5530
5531    if ((np) && (np->n_vnode)) {
5532        /* Use vnode to determine type */
5533        vnode_type = vnode_isdir(np->n_vnode) ? VDIR : VREG;
5534    }
5535
5536    /* Only pass stream_buf_sizep, so we can determine the size of the list */
5537    error = smb2fs_smb_qstreaminfo(share, np, vnode_type,
5538                                   NULL, 0,
5539                                   NULL,
5540                                   NULL, &xattr_len,
5541                                   NULL, NULL,
5542                                   &flags, &max_access,
5543                                   context);
5544    if (error) {
5545        if (error !=ENOATTR) {
5546            SMBERROR("qstreaminfo error: %d\n", error);
5547            goto out;
5548        }
5549        error = 0;
5550    }
5551
5552    if (!xattr_len) {
5553        /* np does not have any xattrs */
5554        goto out;
5555    }
5556
5557    /* Setup a uio and buffer for the xattr list */
5558    SMB_MALLOC(xattrb,
5559               char *,
5560               xattr_len,
5561               M_SMBTEMP,
5562               M_WAITOK | M_ZERO);
5563    if (xattrb == NULL) {
5564        SMBERROR("SMB_MALLOC failed\n");
5565        error = ENOMEM;
5566        goto out;
5567    }
5568
5569    xuio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
5570    if (xuio == NULL) {
5571        SMBERROR("uio_create failed\n");
5572        error = ENOMEM;
5573        goto out;
5574    }
5575
5576    error = uio_addiov(xuio, xattrb, xattr_len);
5577
5578    if (error) {
5579        SMBERROR("uio_addiov failed, error: %d", error);
5580        goto out;
5581    }
5582
5583    uio_setoffset(xuio, 0);
5584
5585    /* Only pass a uio and stream_buf_sizep, to get the entire list of xattrs */
5586    flags = SMB_NO_TRANSLATE_NAMES;  /* Do not translate AFP_Resource & AFP_AfpInfo */
5587    error = smb2fs_smb_qstreaminfo(share, np, vnode_type,
5588                                   NULL, 0,
5589                                   NULL,
5590                                   xuio, &xattr_len,
5591                                   NULL, NULL,
5592                                   &flags, &max_access,
5593                                   context);
5594
5595    if (error) {
5596        SMBDEBUG("qstream failed, error: %d", error);
5597        goto out;
5598    }
5599
5600    /* Return the results */
5601    *xattrlist = xattrb;
5602    *xattrlist_len = xattr_len;
5603
5604    /* Clean up */
5605    uio_free(xuio);
5606
5607    return (0);
5608
5609out:
5610    if (xuio != NULL) {
5611        uio_free(xuio);
5612    }
5613    if (xattrb != NULL) {
5614        SMB_FREE(xattrb, M_SMBTEMP);
5615    }
5616
5617    *xattrlist = NULL;
5618    *xattrlist_len = 0;
5619
5620    return (error);
5621}
5622
5623int
5624smbfs_smb_lock(struct smb_share *share, int op, SMBFID fid, uint32_t pid,
5625               off_t start, uint64_t len, uint32_t timo, vfs_context_t context)
5626{
5627    int error;
5628
5629    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
5630        error = smb2_smb_lock(share, op, fid, start, len, context);
5631    }
5632    else {
5633        error = smb1fs_smb_lock(share, op, fid, pid, start, len, timo, context);
5634    }
5635    return error;
5636}
5637
5638static int
5639smb2fs_smb_markfordelete(struct smb_share *share, SMBFID fid, vfs_context_t context)
5640{
5641    int error;
5642    struct smb2_set_info_rq *infop = NULL;
5643    uint8_t delete_byte = 1;
5644
5645    SMB_MALLOC(infop,
5646               struct smb2_set_info_rq *,
5647               sizeof(struct smb2_set_info_rq),
5648               M_SMBTEMP,
5649               M_WAITOK | M_ZERO);
5650    if (infop == NULL) {
5651        SMBERROR("SMB_MALLOC failed\n");
5652        error = ENOMEM;
5653        goto bad;
5654    }
5655
5656    /*
5657     * Set up for the Set Info call
5658     */
5659    infop->info_type = SMB2_0_INFO_FILE;
5660    infop->file_info_class = FileDispositionInformation;
5661    infop->add_info = 0;
5662    infop->fid = fid;
5663    infop->input_buffer = (uint8_t *) &delete_byte;
5664
5665    error = smb2_smb_set_info(share, infop, NULL, context);
5666    if (error) {
5667        SMBDEBUG("smb2_smb_set_info failed %d ntstatus %d\n",
5668                 error,
5669                 infop->ret_ntstatus);
5670        goto bad;
5671    }
5672
5673bad:
5674    if (infop != NULL) {
5675        SMB_FREE(infop, M_SMBTEMP);
5676    }
5677
5678    return error;
5679}
5680
5681/*
5682 * smbfs_smb_markfordelete
5683 *
5684 * We have an open file that they want to delete. This call will tell the
5685 * server to delete the file when the last close happens. Currenly we know that
5686 * XP, Windows 2000 and Windows 2003 support this call. SAMBA does support the
5687 * call, but currently has a bug that prevents it from working.
5688 *
5689 * The calling routine must hold a reference on the share
5690 *
5691 */
5692int
5693smbfs_smb_markfordelete(struct smb_share *share, SMBFID fid, vfs_context_t context)
5694{
5695    int error;
5696
5697    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
5698        error = smb2fs_smb_markfordelete(share, fid, context);
5699    }
5700    else {
5701        error = smb1fs_smb_markfordelete(share, fid, context);
5702    }
5703    return error;
5704}
5705
5706int
5707smb2fs_smb_ntcreatex(struct smb_share *share, struct smbnode *np,
5708                     const char *namep, size_t in_nmlen,
5709                     const char *strm_namep, size_t in_strm_nmlen,
5710                     uint32_t desired_access, enum vtype vnode_type,
5711                     uint32_t share_access, uint32_t disposition,
5712                     uint64_t create_flags, uint32_t create_options,
5713                     SMBFID *fidp, struct smbfattr *fap,
5714                     struct smb_rq **compound_rqp, struct smb2_create_rq **in_createp,
5715                     void *create_contextp, vfs_context_t context)
5716{
5717	uint32_t file_attributes;
5718	int error;
5719	size_t name_len = in_nmlen;
5720	size_t strm_name_len = in_strm_nmlen;
5721    /* Don't change the input name length, we need it for making the ino number */
5722    struct smb2_create_rq *createp = NULL;
5723    uint32_t impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
5724    uint8_t oplock_level = SMB2_OPLOCK_LEVEL_NONE;
5725    char *snamep = NULL;
5726
5727    /*
5728     * smb2fs_smb_ntcreatex() has various ways it can be called
5729     * 1) np - open item (np)
5730     * 2) np, namep - open the child (namep) in parent dir (np)
5731     * 3) np, strm_namep - open named stream (strm_namep) of item (np)
5732     * 4) np, namep, strm_namep - open named stream of (strm_namep) of
5733     * child (namep) in parent dir (np)
5734     */
5735
5736    if (fap) {
5737        bzero(fap, sizeof(*fap));
5738        nanouptime(&fap->fa_reqtime);
5739    }
5740
5741    SMB_MALLOC(createp,
5742               struct smb2_create_rq *,
5743               sizeof(struct smb2_create_rq),
5744               M_SMBTEMP,
5745               M_WAITOK | M_ZERO);
5746    if (createp == NULL) {
5747        SMBERROR("SMB_MALLOC failed\n");
5748        error = ENOMEM;
5749        goto bad;
5750    }
5751
5752    /* determine file attributes */
5753    if (vnode_type == VDIR) {
5754        file_attributes = SMB_EFA_DIRECTORY;
5755    }
5756    else {
5757        file_attributes = SMB_EFA_NORMAL;
5758    }
5759	if ((disposition != FILE_OPEN) &&
5760        (!(create_flags & SMB2_CREATE_IS_NAMED_STREAM))) {
5761		if (file_attributes == SMB_EFA_NORMAL) {
5762			file_attributes |= SMB_EFA_ARCHIVE;
5763        }
5764		if ((namep) && (*namep == '.')) {
5765			file_attributes |= SMB_EFA_HIDDEN;
5766        }
5767	}
5768
5769    /* start wth the passed in flag settings */
5770    createp->flags |= create_flags;
5771
5772    /* Do they want to open the resource fork? */
5773    if ((np) && (np->n_vnode) &&
5774        (vnode_isnamedstream(np->n_vnode)) &&
5775        (!strm_namep) && (!(create_flags & SMB2_CREATE_IS_NAMED_STREAM))) {
5776        lck_rw_lock_shared(&np->n_name_rwlock);
5777        snamep = smb_strndup(np->n_sname, np->n_snmlen);
5778        strm_namep = snamep;
5779        lck_rw_unlock_shared(&np->n_name_rwlock);
5780
5781        strm_name_len = np->n_snmlen;
5782        createp->flags |= SMB2_CREATE_IS_NAMED_STREAM;
5783    }
5784
5785    if (create_flags & SMB2_CREATE_DUR_HANDLE_RECONNECT) {
5786        impersonation_level = 0;
5787        file_attributes = 0;
5788        create_options = 0;
5789        createp->create_contextp = create_contextp;
5790        oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
5791    }
5792    else {
5793        if (create_flags & SMB2_CREATE_DUR_HANDLE) {
5794            createp->create_contextp = create_contextp;
5795            oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
5796        }
5797    }
5798
5799    if (create_flags & SMB2_CREATE_AAPL_RESOLVE_ID) {
5800        createp->create_contextp = create_contextp;
5801    }
5802
5803    /*
5804     * Set up for the Create call
5805     */
5806    createp->oplock_level = oplock_level;
5807    createp->impersonate_level = impersonation_level;
5808
5809    createp->desired_access = desired_access;
5810    if (create_flags & SMB2_CREATE_GET_MAX_ACCESS) {
5811        /* since getting max access, make sure SMB2_FILE_READ_ATTRIBUTES set */
5812        createp->desired_access |= SMB2_FILE_READ_ATTRIBUTES;
5813    }
5814    createp->file_attributes = file_attributes;
5815    createp->share_access = share_access;
5816    createp->disposition = disposition;
5817    createp->create_options = create_options;
5818    createp->name_len = (uint32_t) name_len;
5819    createp->namep = (char *) namep;
5820    createp->strm_name_len = (uint32_t) strm_name_len;
5821    createp->strm_namep = (char *) strm_namep;
5822    createp->dnp = np;
5823
5824    /*
5825     * Do the Create call
5826     */
5827    error = smb2_smb_create(share, createp, compound_rqp, context);
5828    if (error) {
5829        if ((error != ENOENT) && (error != EEXIST) && (error != EBUSY)) {
5830            SMBDEBUG("smb2_smb_create failed %d ntstatus 0x%x\n",
5831                     error,
5832                     createp->ret_ntstatus);
5833        }
5834        goto bad;
5835    }
5836
5837    /* Building a compound requests */
5838    if (in_createp != NULL) {
5839        *in_createp = createp;
5840        return (0);
5841    }
5842
5843	if (fidp) {
5844		*fidp = createp->ret_fid;
5845    }
5846
5847    /*
5848     * Fill in fap and possibly update vnode's meta data caches
5849     */
5850    error = smb2fs_smb_parse_ntcreatex(share, np, createp,
5851                                       fidp, fap, context);
5852bad:
5853    if (createp != NULL) {
5854        SMB_FREE(createp, M_SMBTEMP);
5855    }
5856
5857    if (snamep) {
5858        SMB_FREE(snamep, M_SMBSTR);
5859    }
5860
5861	return error;
5862}
5863
5864/*
5865 * Modern create/open of file or directory.
5866 *
5867 * If disp is FILE_OPEN then this is an open attempt, and:
5868 *   If xattr then name is the stream to be opened at np,
5869 *   Else np should be opened.
5870 *   ...we won't touch *fidp,
5871 * Else this is a creation attempt, and:
5872 *   If xattr then name is the stream to create at np,
5873 *   Else name is the thing to create under directory np.
5874 *   ...we will return *fidp,
5875 *
5876 * The calling routine must hold a reference on the share
5877 *
5878 * Either pass in np which is the file/dir to open OR
5879 * pass in dnp and a name
5880 *
5881 */
5882int
5883smbfs_smb_ntcreatex(struct smb_share *share, struct smbnode *np,
5884                    uint32_t rights, uint32_t shareMode, enum vtype vt,
5885                    SMBFID *fidp, const char *name, size_t in_nmlen,
5886                    uint32_t disp, int xattr, struct smbfattr *fap,
5887                    int do_create, struct smb2_durable_handle *dur_handlep, vfs_context_t context)
5888{
5889    int error;
5890    uint64_t create_flags = 0;
5891    char *file_namep = NULL, *stream_namep = NULL;
5892    size_t file_name_len = 0, stream_name_len = 0;
5893
5894    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
5895        create_flags = SMB2_CREATE_GET_MAX_ACCESS;   /* Always set want_max_access */
5896
5897        if (do_create)
5898            create_flags |= SMB2_CREATE_DO_CREATE;
5899
5900        if (dur_handlep) {
5901            if (dur_handlep->flags & SMB2_DURABLE_HANDLE_RECONNECT) {
5902                create_flags = SMB2_CREATE_DUR_HANDLE_RECONNECT;
5903            }
5904            else {
5905                if (dur_handlep->flags & SMB2_DURABLE_HANDLE_REQUEST) {
5906                    create_flags = SMB2_CREATE_DUR_HANDLE;
5907                }
5908            }
5909        }
5910
5911        if (!xattr) {
5912            file_namep = (char *) name;
5913            file_name_len = in_nmlen;
5914        }
5915        else {
5916            /* name is actually the stream name */
5917            create_flags |= SMB2_CREATE_IS_NAMED_STREAM;
5918
5919            stream_namep = (char *) name;
5920            stream_name_len = in_nmlen;
5921        }
5922
5923        error = smb2fs_smb_cmpd_create(share, np,
5924                                       file_namep, file_name_len,
5925                                       stream_namep, stream_name_len,
5926                                       rights, vt,
5927                                       shareMode, disp,
5928                                       create_flags, NULL,
5929                                       fidp, fap,
5930                                       dur_handlep, context);
5931    }
5932    else {
5933        error = smb1fs_smb_ntcreatex(share, np, rights, shareMode, vt, fidp,
5934                                     name, in_nmlen, disp, xattr, fap,
5935                                     do_create, context);
5936    }
5937
5938    return error;
5939}
5940
5941/*
5942 * This routine chains the open and read into one message. This routine is used
5943 * only for reading data out of a stream. If we decided to use it for something
5944 * else then we will need to make some changes.
5945 *
5946 * The calling routine must hold a reference on the share
5947 *
5948 */
5949int
5950smbfs_smb_openread(struct smb_share *share, struct smbnode *np,
5951                   SMBFID *fidp, uint32_t desired_access,
5952                   uio_t uio, size_t *sizep, const char *stream_namep,
5953				   struct timespec *mtimep, vfs_context_t context)
5954{
5955    int error;
5956	size_t stream_name_len = strnlen(stream_namep,
5957                                     share->ss_maxfilenamelen + 1);
5958    uint32_t max_access;
5959
5960    /* This is only used when dealing with xattr calls */
5961
5962    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
5963        /*
5964         * Do a Create/Read or Create/Read/Close. The Close is added if
5965         * fidp is NULL
5966         */
5967        error = smb2fs_smb_cmpd_create_read(share, np,
5968                                            NULL, 0,
5969                                            stream_namep, stream_name_len,
5970                                            desired_access, uio,
5971                                            sizep, &max_access,
5972                                            fidp, mtimep,
5973                                            context);
5974    }
5975    else {
5976        error = smb1fs_smb_openread(share, np, fidp, desired_access, uio, sizep,
5977                                    stream_namep, mtimep, context);
5978    }
5979
5980    return error;
5981}
5982
5983static int
5984smb2fs_smb_parse_ntcreatex(struct smb_share *share, struct smbnode *np,
5985                           struct smb2_create_rq *createp,
5986                           SMBFID *fidp, struct smbfattr *fap,
5987                           vfs_context_t context)
5988{
5989    /*
5990     * smb2fs_smb_ntcreatex() has various ways it can be called
5991     * (1) np - open item (np)
5992     * (2) np, namep - open the child (namep) in parent dir (np)
5993     * (3) np, strm_namep - open named stream (strm_namep) of item (np)
5994     * (4) np, namep, strm_namep - open named stream of (strm_namep) of
5995     *    child (namep) in parent dir (np)
5996     *
5997     * If there is a namep, then do not update the vnode np as that will
5998     * be the parent vnode.
5999     */
6000
6001    DBG_ASSERT(fap != NULL);
6002
6003    /*
6004     * Copy results out into fap
6005     */
6006    fap->fa_created_disp = createp->ret_create_action;
6007    smb_time_NT2local(createp->ret_create_time, &fap->fa_crtime);
6008    smb_time_NT2local(createp->ret_access_time, &fap->fa_atime);
6009    smb_time_NT2local(createp->ret_write_time, &fap->fa_mtime);
6010    smb_time_NT2local(createp->ret_change_time, &fap->fa_chtime);
6011
6012    /*
6013     * Because of the Steve/Conrad Symlinks we can never be completely
6014     * sure that we have the correct vnode type if its a file. For
6015     * directories we always know the correct information.
6016     */
6017    fap->fa_attr = createp->ret_attributes;
6018    if (fap->fa_attr & SMB_EFA_DIRECTORY) {
6019        fap->fa_valid_mask |= FA_VTYPE_VALID;
6020    }
6021    fap->fa_vtype = (fap->fa_attr & SMB_EFA_DIRECTORY) ? VDIR : VREG;
6022
6023    fap->fa_data_alloc = createp->ret_alloc_size;
6024    fap->fa_size = createp->ret_eof;
6025
6026    if (createp->flags & SMB2_CREATE_GET_MAX_ACCESS) {
6027        fap->fa_max_access = createp->ret_max_access;
6028        fap->fa_valid_mask |= FA_MAX_ACCESS_VALID;
6029
6030        /* Special case the root vnode */
6031        if (createp->namep == NULL) {
6032            /* Must be (1) or (3) and could be the root vnode */
6033            if ((np) && (np->n_vnode) && (vnode_isvroot(np->n_vnode))) {
6034                /*
6035                 * its the root folder, if no Execute, but share grants
6036                 * Execute then grant Execute to root folder
6037                 */
6038                if ((!(np->maxAccessRights & SMB2_FILE_EXECUTE)) &&
6039                    (share->maxAccessRights & SMB2_FILE_EXECUTE)) {
6040                    fap->fa_max_access |= SMB2_FILE_EXECUTE;
6041                }
6042
6043                /*
6044                 * its the root, if no ReadAttr, but share grants
6045                 * ReadAttr then grant ReadAttr to root
6046                 */
6047                if ((!(np->maxAccessRights & SMB2_FILE_READ_ATTRIBUTES)) &&
6048                    (share->maxAccessRights & SMB2_FILE_READ_ATTRIBUTES)) {
6049                    fap->fa_max_access |= SMB2_FILE_READ_ATTRIBUTES;
6050                }
6051            }
6052        }
6053    }
6054
6055	if (fidp) {
6056		*fidp = createp->ret_fid;
6057    }
6058
6059    /*
6060     * If not a directory, check if node needs to be reopened,
6061     * if so, then don't update anything at this point.
6062     * See <rdar://problem/11366143>.
6063     */
6064    if ((np) && (np->n_vnode) && !(vnode_isdir(np->n_vnode))) {
6065        lck_mtx_lock(&np->f_openStateLock);
6066        if (np->f_openState & kInReopen) {
6067            lck_mtx_unlock(&np->f_openStateLock);
6068            goto done;
6069        }
6070        lck_mtx_unlock(&np->f_openStateLock);
6071    }
6072
6073    if (createp->flags & SMB2_CREATE_IS_NAMED_STREAM) {
6074		/*
6075         * Must be (3) or (4).
6076         * If an EA or Stream then we are done. We dont update that main
6077         * data vnode with information from a stream. Possibly we could since
6078         * the data should be valid...
6079         */
6080		goto done;
6081	}
6082
6083    if ((np) && (createp->flags & SMB2_CREATE_DO_CREATE)) {
6084        if (!(SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS)) {
6085            /*
6086             * File server does not support File IDs
6087             */
6088
6089            /*
6090             * Must be (2). We are creating the item so create the ino number.
6091             * Since its a create, it must be the data fork and thus
6092             * createp->name_len is the same as the orig in_nmlen.
6093             */
6094
6095            /* This is a create so better have a name, but root does not have a name */
6096            fap->fa_ino = smbfs_getino(np, createp->namep, createp->name_len);
6097            goto done;
6098        }
6099    }
6100
6101    if (createp->namep) {
6102        /*
6103         * SMB2_CREATE_DO_CREATE is not set, but still have a name, so
6104         * must be (2)
6105         */
6106        goto done;
6107    }
6108
6109	/* If this is a SYMLINK, then n_vnode could be set to NULL */
6110	if ((np) && (np->n_vnode == NULL)) {
6111		goto done;
6112	}
6113
6114	/*
6115 	 * At this point, it must be (1).
6116     * We have all the meta data attributes so update the cache. If the
6117	 * calling routine is setting an attribute it should not change the
6118	 * smb node value until after the open has completed. NOTE: The old
6119	 * code would only update the cache if the mtime, attributes and size
6120	 * haven't changed.
6121 	 */
6122    if (np) {
6123        smbfs_attr_cacheenter(share, np->n_vnode, fap, TRUE, context);
6124    }
6125
6126done:
6127	return 0;
6128}
6129
6130static int
6131smb2fs_smb_qfsattr(struct smbmount *smp,
6132                   struct FILE_FS_ATTRIBUTE_INFORMATION *fs_attrs,
6133                   vfs_context_t context)
6134{
6135    struct smb_share *share = smp->sm_share;
6136	int error;
6137    uint32_t output_buffer_len;
6138
6139    output_buffer_len = sizeof(struct FILE_FS_ATTRIBUTE_INFORMATION);
6140    output_buffer_len += PATH_MAX;
6141
6142    /*
6143     * Do the Compound Create/Query Info/Close call
6144     * Query results are passed back in *fs_attrs
6145     *
6146     * Have to pass in submount path if it exists because we have no root vnode,
6147     * and smbmount and smb_share may not be fully set up yet.
6148     *
6149     * This is always done on the root of the share
6150     */
6151    error = smb2fs_smb_cmpd_query(share, NULL, VDIR,
6152                                  (smp->sm_args.path_len == 0 ? NULL : smp->sm_args.path),
6153                                  smp->sm_args.path_len,
6154                                  0, SMB2_FILE_READ_ATTRIBUTES | SMB2_SYNCHRONIZE,
6155                                  SMB2_0_INFO_FILESYSTEM, FileFsAttributeInformation,
6156                                  0, NULL,
6157                                  &output_buffer_len, (uint8_t *) fs_attrs,
6158                                  context);
6159
6160	return error;
6161}
6162
6163/*
6164 * Since the first thing we do is set the default values there is no longer
6165 * any reason to return an error for this routine. Some servers may not support
6166 * this call. We should not fail the mount just because they do not support this
6167 * call.
6168 *
6169 * The calling routine must hold a reference on the share
6170 *
6171 */
6172void
6173smbfs_smb_qfsattr(struct smbmount *smp, vfs_context_t context)
6174{
6175    struct smb_share *share = smp->sm_share;
6176   	struct smb_vc *vcp = SSTOVC(share);
6177    struct FILE_FS_ATTRIBUTE_INFORMATION fs_attrs;
6178	int error;
6179	size_t fs_nmlen;	/* The sized malloced for fs_name */
6180	char *fsname = NULL;
6181
6182	/* Start with the default values */
6183	share->ss_fstype = SMB_FS_FAT;	/* default to FAT File System */
6184	share->ss_attributes = 0;
6185	share->ss_maxfilenamelen = 255;
6186
6187    bzero(&fs_attrs, sizeof(fs_attrs));
6188
6189    if (vcp->vc_flags & SMBV_SMB2) {
6190        error = smb2fs_smb_qfsattr(smp, &fs_attrs, context);
6191    }
6192    else {
6193        /*
6194         * Goal is to leave the SMB 1 code unchanged as much as possible
6195         * to minimize the risk.  That is why there is duplicate code here
6196         * for the SMB 2/3 path and also in SMB 1 code path.
6197         */
6198        smb1fs_qfsattr(share, context);
6199        return;
6200    }
6201
6202    if (error) {
6203		/* This is a very bad server */
6204		SMBWARNING("Server returned a bad SMB_QFS_ATTRIBUTE_INFO message\n");
6205		/* Don't believe them when they say they are unix */
6206		SSTOVC(share)->vc_sopt.sv_caps &= ~SMB_CAP_UNIX;
6207        return;
6208    }
6209
6210    share->ss_attributes = fs_attrs.file_system_attrs;
6211    share->ss_maxfilenamelen = fs_attrs.max_component_name_len;
6212
6213    if (!SMB_UNICODE_STRINGS(SSTOVC(share))) {
6214        SMBERROR("Unicode must be supported\n");
6215        goto done;
6216    }
6217
6218    /* If have a file system name, determine what it is */
6219	if (fs_attrs.file_system_namep != NULL) {
6220        /* Convert Unicode string */
6221        fs_nmlen = fs_attrs.file_system_name_len;
6222        fsname = smbfs_ntwrkname_tolocal(fs_attrs.file_system_namep,
6223                                         &fs_nmlen,
6224                                         SMB_UNICODE_STRINGS(SSTOVC(share)));
6225        if (fsname == NULL) {
6226            SMBERROR("fs_attr name failed to convert\n");
6227            goto done;	/* Should never happen, but just to be safe */
6228        }
6229
6230		fs_nmlen += 1; /* Include the null byte for the compare */
6231
6232		/*
6233		 * Let's start keeping track of the file system type. Most
6234		 * things we need to do differently really depend on the
6235		 * file system type. As an example we know that FAT file systems
6236		 * do not update the modify time on directories.
6237		 */
6238		if (strncmp(fsname, "FAT", fs_nmlen) == 0)
6239			share->ss_fstype = SMB_FS_FAT;
6240		else if (strncmp(fsname, "FAT12", fs_nmlen) == 0)
6241			share->ss_fstype = SMB_FS_FAT;
6242		else if (strncmp(fsname, "FAT16", fs_nmlen) == 0)
6243			share->ss_fstype = SMB_FS_FAT;
6244		else if (strncmp(fsname, "FAT32", fs_nmlen) == 0)
6245			share->ss_fstype = SMB_FS_FAT;
6246		else if (strncmp(fsname, "CDFS", fs_nmlen) == 0)
6247			share->ss_fstype = SMB_FS_CDFS;
6248		else if (strncmp(fsname, "UDF", fs_nmlen) == 0)
6249			share->ss_fstype = SMB_FS_UDF;
6250		else if (strncmp(fsname, "NTFS", fs_nmlen) == 0)
6251			share->ss_fstype = SMB_FS_NTFS_UNKNOWN;	/* Could be lying */
6252
6253		SMBWARNING("%s/%s type '%s', attr 0x%x, maxfilename %d\n",
6254				   SSTOVC(share)->vc_srvname, share->ss_name, fsname,
6255				   share->ss_attributes, share->ss_maxfilenamelen);
6256
6257        /*
6258		 * NT4 will not return the FILE_NAMED_STREAMS bit in the ss_attributes
6259		 * even though they support streams. So if its a NT4 server and a
6260		 * NTFS file format then turn on the streams flag.
6261		 */
6262        if ((SSTOVC(share)->vc_flags & SMBV_NT4) &&
6263            (share->ss_fstype & SMB_FS_NTFS_UNKNOWN)) {
6264            share->ss_attributes |= FILE_NAMED_STREAMS;
6265        }
6266        /*
6267         * The server says they support streams and they say they are NTFS. So mark
6268         * the subtype as NTFS. Remember a lot of non Windows servers pretend
6269         * their NTFS so they can support ACLs, but they aren't really because they have
6270         * no stream support. This allows us to tell the difference.
6271         */
6272        if ((share->ss_fstype == SMB_FS_NTFS_UNKNOWN) &&
6273            (share->ss_attributes & FILE_NAMED_STREAMS)) {
6274            share->ss_fstype = SMB_FS_NTFS;	/* Real NTFS Volume */
6275        }
6276        else if ((share->ss_fstype == SMB_FS_NTFS_UNKNOWN) &&
6277                 (UNIX_SERVER(SSTOVC(share)))) {
6278            share->ss_fstype = SMB_FS_NTFS_UNIX;
6279            /* UNIX system lying about being NTFS */
6280        }
6281
6282        /*
6283         * Note: If this is an OS X SMB 2/3 server, smbfs_mount() will
6284         * set share->ss_fstype() to SMB_FS_MAC_OS_X.  We cannot do
6285         * that here because at this point we haven't yet queried the
6286         * server for AAPL create context support.
6287         */
6288    }
6289
6290done:
6291    if (fs_attrs.file_system_namep != NULL) {
6292        SMB_FREE(fs_attrs.file_system_namep, M_SMBFSDATA);
6293    }
6294    if (fsname != NULL) {
6295        SMB_FREE(fsname, M_SMBSTR);
6296    }
6297}
6298
6299static int
6300smb2fs_smb_qpathinfo(struct smb_share *share, struct smbnode *np, enum vtype vnode_type,
6301                     struct smbfattr *fap, short infolevel,
6302                     const char **namep, size_t *name_lenp,
6303                     vfs_context_t context)
6304{
6305    struct FILE_ALL_INFORMATION *all_infop = NULL;
6306	int error = EINVAL;
6307	const char *name = (namep ? *namep : NULL);
6308	size_t name_len = (name_lenp ? *name_lenp : 0);
6309    uint32_t output_buffer_len;
6310
6311    SMB_MALLOC(all_infop,
6312               struct FILE_ALL_INFORMATION *,
6313               sizeof(struct FILE_ALL_INFORMATION),
6314               M_SMBTEMP,
6315               M_WAITOK | M_ZERO);
6316    if (all_infop == NULL) {
6317        SMBERROR("SMB_MALLOC failed\n");
6318        error = ENOMEM;
6319        goto bad;
6320    }
6321
6322    /*
6323     * Set up for the Query Info call
6324     */
6325    switch (infolevel) {
6326        case SMB_QFILEINFO_ALL_INFO:
6327            all_infop->share = share;
6328            all_infop->np = np;
6329            all_infop->fap = fap;
6330            all_infop->namep = namep;
6331            all_infop->name_lenp = name_lenp;
6332            break;
6333
6334        default:
6335            SMBERROR("Unimplemented infolevel %d\n", infolevel);
6336            goto bad;
6337            break;
6338    }
6339
6340    output_buffer_len = SMB2_FILE_ALL_INFO_LEN;
6341
6342    /*
6343     * Do the Compound Create/SetInfo/Close call
6344     * Query results are passed back in *fap
6345     */
6346    error = smb2fs_smb_cmpd_query(share, np, vnode_type,
6347                                  name, name_len,
6348                                  0, SMB2_FILE_READ_ATTRIBUTES | SMB2_SYNCHRONIZE,
6349                                  SMB2_0_INFO_FILE, FileAllInformation,
6350                                  0, NULL,
6351                                  &output_buffer_len, (uint8_t *) all_infop,
6352                                  context);
6353
6354bad:
6355    if (all_infop != NULL) {
6356        SMB_FREE(all_infop, M_SMBTEMP);
6357    }
6358
6359	return error;
6360}
6361
6362/*
6363 * The calling routine must hold a reference on the share
6364 */
6365int
6366smbfs_smb_qpathinfo(struct smb_share *share, struct smbnode *np, enum vtype vnode_type,
6367                    struct smbfattr *fap, short infolevel,
6368                    const char **namep, size_t *nmlenp,
6369                    vfs_context_t context)
6370{
6371   	struct smb_vc *vcp = SSTOVC(share);
6372	int error;
6373
6374    if (vcp->vc_flags & SMBV_SMB2) {
6375        error = smb2fs_smb_qpathinfo(share, np, vnode_type,
6376                                     fap, infolevel,
6377                                     namep, nmlenp,
6378                                     context);
6379    }
6380    else {
6381        error = smb1fs_smb_qpathinfo(share,
6382                                     np,
6383                                     fap,
6384                                     infolevel,
6385                                     namep,
6386                                     nmlenp,
6387                                     context);
6388    }
6389
6390    return error;
6391}
6392
6393/*
6394 * When calling this routine be very careful when passing the arguments.
6395 * Depending on the arguments different actions will be taken with this routine.
6396 *
6397 * The calling routine must hold a reference on the share
6398 *
6399 */
6400static int
6401smb2fs_smb_qstreaminfo(struct smb_share *share, struct smbnode *np, enum vtype vnode_type,
6402                       const char *namep, size_t name_len,
6403                       const char *stream_namep,
6404                       uio_t uio, size_t *sizep,
6405                       uint64_t *stream_sizep, uint64_t *stream_alloc_sizep,
6406                       uint32_t *stream_flagsp, uint32_t *max_accessp,
6407                       vfs_context_t context)
6408{
6409    /*
6410     * For this function, vnode_type is the item's type. The item will be
6411     * opened and checked for named streams.
6412     */
6413
6414    /*
6415     * Two usage cases:
6416     * 1) Given np and namep == NULL. Query the path of np
6417     * 2) Given np and namep (must be readdirattr). Query PARENT np and
6418     * child namep. In this case, do not update vnode np as that is the parent.
6419     *
6420     * In both cases, Query for a list of streams and if streams are found,
6421     * see if they match stream_namep that was passed in.
6422     */
6423    struct FILE_STREAM_INFORMATION *stream_infop = NULL;
6424	int error;
6425    uint32_t output_buffer_len;
6426
6427    if (namep == NULL) {
6428        /* Not readdirattr case */
6429        if ((np->n_fstatus & kNO_SUBSTREAMS) ||
6430            (np->n_dosattr & SMB_EFA_REPARSE_POINT)) {
6431            error = ENOATTR;
6432            goto bad;
6433        }
6434    }
6435
6436	if (sizep) {
6437		*sizep = 0;
6438    }
6439
6440    SMB_MALLOC(stream_infop,
6441               struct FILE_STREAM_INFORMATION *,
6442               sizeof(struct FILE_STREAM_INFORMATION),
6443               M_SMBTEMP,
6444               M_WAITOK | M_ZERO);
6445    if (stream_infop == NULL) {
6446        SMBERROR("SMB_MALLOC failed\n");
6447        error = ENOMEM;
6448        goto bad;
6449    }
6450
6451    /*
6452     * Set up for the Query Info call
6453     *
6454     * We have two typical usages for this call
6455     * 1) listxattr - uio and/or stream_buf_sizep
6456     *  a) if uio and stream_buf_sizep, then return all xattrs If stream_flagsp has
6457     *     SMB_NO_TRANSLATE_NAMES set, then AFP_Resource & AFP_AfpInfo are not translated
6458     *     to extended attribute names.
6459     *  b) if only stream_buf_sizep, then they are just trying to determine size
6460     *     of a buffer sufficiently large enough to hold all the xattr names
6461     * 2) Checking for existence of a specific stream
6462     *  a) If stream_namep and stream_sizep/stream_alloc_sizep, then look for
6463     *     that specific stream and if found, return its logical and alloc sizes
6464     *  b) If only stream_namep, just check for existence of that specific stream
6465     */
6466    stream_infop->share = share;
6467    stream_infop->np = np;
6468    stream_infop->namep = namep;
6469    stream_infop->name_len = name_len;
6470    stream_infop->uio = uio;
6471    stream_infop->stream_buf_sizep = sizep;
6472    stream_infop->stream_namep = stream_namep;
6473    stream_infop->stream_sizep = stream_sizep;
6474    stream_infop->stream_alloc_sizep = stream_alloc_sizep;
6475    stream_infop->stream_flagsp = stream_flagsp;
6476
6477    /*
6478     * Some servers do not grant us that many credits, so limit credit
6479     * usage to just 1. That should be plenty for getting
6480     * FileStreamInformation which is just a list of very short names like
6481     * ::$DATA
6482     */
6483    output_buffer_len = 64 * 1024;
6484
6485    /*
6486     * Do the Compound Create/QueryInfo/Close call
6487     * Query results are passed back in uio
6488     */
6489    error = smb2fs_smb_cmpd_query(share, np, vnode_type,
6490                                  namep, name_len,
6491                                  0, SMB2_FILE_READ_ATTRIBUTES | SMB2_SYNCHRONIZE,
6492                                  SMB2_0_INFO_FILE, FileStreamInformation,
6493                                  0, max_accessp,
6494                                  &output_buffer_len, (uint8_t *) stream_infop,
6495                                  context);
6496
6497    if (error) {
6498        if ((error != ENOATTR) && (error != EINVAL) &&
6499            (error != EACCES) && (error != ENOENT)) {
6500            SMBDEBUG("smb2fs_smb_cmpd_query failed %d\n", error);
6501        }
6502        goto bad;
6503    }
6504
6505    /* Is there only the data stream and no other named streams? */
6506    if ((namep == NULL) && (stream_flagsp != NULL)) {
6507        /* Not readdirattr case */
6508        if (*stream_flagsp & SMB_NO_SUBSTREAMS) {
6509            np->n_fstatus |= kNO_SUBSTREAMS;
6510        }
6511    }
6512
6513bad:
6514    if (stream_infop != NULL) {
6515        SMB_FREE(stream_infop, M_SMBTEMP);
6516    }
6517
6518	return error;
6519}
6520
6521/*
6522 * When calling this routine be very careful when passing the arguments.
6523 * Depending on the arguments different actions will be taken with this routine.
6524 *
6525 * The calling routine must hold a reference on the share
6526 *
6527 */
6528int
6529smbfs_smb_qstreaminfo(struct smb_share *share, struct smbnode *np, enum vtype vnode_type,
6530                      const char *namep, size_t name_len,
6531                      const char *stream_namep,
6532                      uio_t uio, size_t *sizep,
6533                      uint64_t *strm_sizep, uint64_t *strm_alloc_sizep,
6534                      uint32_t *stream_flags, uint32_t *max_accessp,
6535                      vfs_context_t context)
6536{
6537   	struct smb_vc *vcp = SSTOVC(share);
6538	int error;
6539
6540    if (vcp->vc_flags & SMBV_SMB2) {
6541        error = smb2fs_smb_qstreaminfo(share, np, vnode_type,
6542                                       namep, name_len,
6543                                       stream_namep,
6544                                       uio, sizep,
6545                                       strm_sizep, strm_alloc_sizep,
6546                                       stream_flags, max_accessp,
6547                                       context);
6548    }
6549    else {
6550        error = smb1fs_smb_qstreaminfo(share, np,
6551                                       namep, name_len,
6552                                       stream_namep,
6553                                       uio, sizep,
6554                                       strm_sizep, strm_alloc_sizep,
6555                                       stream_flags,
6556                                       context);
6557    }
6558
6559    return error;
6560
6561}
6562
6563/*
6564 * We should replace it with something more modern. See <rdar://problem/7595213>.
6565 * This routine is only used to test the existence of an item or to get its
6566 * DOS attributes when changing the status of the HIDDEN bit.
6567 *
6568 * The calling routine must hold a reference on the share
6569 *
6570 */
6571int
6572smbfs_smb_query_info(struct smb_share *share, struct smbnode *dnp, enum vtype vnode_type,
6573                     const char *in_name, size_t len, uint32_t *attr,
6574                     vfs_context_t context)
6575{
6576   	struct smb_vc *vcp = SSTOVC(share);
6577	const char *name = in_name;
6578	size_t name_len = len;
6579    struct smbfattr *fap = NULL;
6580	int error;
6581
6582    if (vcp->vc_flags & SMBV_SMB2) {
6583        SMB_MALLOC(fap,
6584                   struct smbfattr *,
6585                   sizeof(struct smbfattr),
6586                   M_SMBTEMP,
6587                   M_WAITOK | M_ZERO);
6588        if (fap == NULL) {
6589            SMBERROR("SMB_MALLOC failed\n");
6590            error = ENOMEM;
6591            goto out;
6592        }
6593
6594        if (vcp->vc_misc_flags & SMBV_NO_QUERYINFO) {
6595            /* Use Query Dir instead of Query Info, but only if SMB 2/3 */
6596            error = smb2fs_smb_cmpd_query_dir_one(share, dnp,
6597                                                  name, name_len,
6598                                                  fap, (char **) &name, &name_len,
6599                                                  context);
6600        }
6601        else {
6602            /* This is always a parent dir dnp and a name in that dir */
6603            error = smb2fs_smb_qpathinfo(share, dnp, vnode_type,
6604                                         fap, SMB_QFILEINFO_ALL_INFO,
6605                                         &name, &name_len,
6606                                         context);
6607        }
6608
6609        if (error) {
6610            goto out;
6611        }
6612
6613        /* return attributes if they want them */
6614        if (attr != NULL) {
6615            *attr = fap->fa_attr;
6616        }
6617
6618        /* if got returned a new name, free it since we do not need it */
6619        if (name != in_name) {
6620            SMB_FREE(name, M_SMBNODENAME);
6621        }
6622    }
6623    else {
6624        error = smb1fs_smb_query_info(share,
6625                                      dnp,
6626                                      name,
6627                                      len,
6628                                      attr,
6629                                      context);
6630    }
6631
6632out:
6633    if (fap != NULL) {
6634        SMB_FREE(fap, M_SMBTEMP);
6635    }
6636
6637    return error;
6638}
6639
6640static int
6641smb2fs_smb_rename(struct smb_share *share, struct smbnode *src,
6642                  struct smbnode *tdnp, const char *tnamep, size_t tname_len,
6643                  vfs_context_t context)
6644{
6645    int error;
6646    uint32_t setinfo_ntstatus;
6647    struct smb2_set_info_file_rename_info *renamep = NULL;
6648    enum vtype vnode_type = VREG;
6649
6650    /*
6651     * Looking at Win <-> Win with SMB 2/3, rename/move is handled by opening the
6652     * file with Delete and "Read Attributes", then a Set Info is done to move
6653     * or rename the file.  Finally a Close is sent.
6654     */
6655
6656    SMB_MALLOC(renamep,
6657               struct smb2_set_info_file_rename_info *,
6658               sizeof(struct smb2_set_info_file_rename_info),
6659               M_SMBTEMP,
6660               M_WAITOK | M_ZERO);
6661    if (renamep == NULL) {
6662        SMBERROR("SMB_MALLOC failed\n");
6663        error = ENOMEM;
6664        goto bad;
6665    }
6666
6667    /*
6668     * Set up for the Set Info call
6669     */
6670    renamep->replace_if_exists = 0;
6671    renamep->tname_len = (uint32_t) tname_len;
6672    renamep->tdnp = tdnp;
6673    renamep->tnamep = (char*) tnamep;
6674
6675    if ((src) && (src->n_vnode)) {
6676        /* Use vnode to determine type */
6677        vnode_type = vnode_isdir(src->n_vnode) ? VDIR : VREG;
6678    }
6679
6680    /*
6681     * Do the Compound Create/SetInfo/Close call
6682     * Delete access will allow us to rename an open file
6683     */
6684    error = smb2fs_smb_cmpd_set_info(share, src, vnode_type,
6685                                     NULL, 0,
6686                                     0, SMB2_FILE_READ_ATTRIBUTES | SMB2_STD_ACCESS_DELETE | SMB2_SYNCHRONIZE,
6687                                     SMB2_0_INFO_FILE, FileRenameInformation,
6688                                     0,
6689                                     sizeof (*renamep), (uint8_t *) renamep,
6690                                     &setinfo_ntstatus,
6691                                     context);
6692    if (error) {
6693        if (error != EACCES) {
6694            SMBDEBUG("smb2fs_smb_cmpd_set_info failed %d\n", error);
6695        }
6696        goto bad;
6697    }
6698
6699bad:
6700    if (renamep != NULL) {
6701        SMB_FREE(renamep, M_SMBTEMP);
6702    }
6703
6704    return error;
6705}
6706
6707/*
6708 * The calling routine must hold a reference on the share
6709 */
6710int
6711smbfs_smb_rename(struct smb_share *share, struct smbnode *src,
6712				 struct smbnode *tdnp, const char *tname, size_t tnmlen,
6713				 vfs_context_t context)
6714{
6715    int error;
6716
6717    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
6718        error = smb2fs_smb_rename(share, src, tdnp, tname, tnmlen, context);
6719    }
6720    else {
6721        error = smb1fs_smb_rename(share, src, tdnp, tname, tnmlen, context);
6722    }
6723
6724    return error;
6725}
6726
6727int
6728smbfs_smb_reparse_read_symlink(struct smb_share *share, struct smbnode *np,
6729                               struct uio *uiop, vfs_context_t context)
6730{
6731    int error;
6732
6733    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
6734        error = smb2fs_smb_cmpd_reparse_point_get(share, np, uiop, context);
6735    }
6736    else {
6737        error = smb1fs_smb_reparse_read_symlink(share, np, uiop, context);
6738    }
6739
6740    return error;
6741
6742}
6743
6744static int
6745smb2fs_smb_request_resume_key(struct smb_share *share, SMBFID fid, u_char *resume_key,
6746                              vfs_context_t context)
6747{
6748    struct smb2_ioctl_rq *ioctlp = NULL;
6749    int error = 0;
6750
6751    /*
6752     * Build the IOCTL request
6753     */
6754    SMB_MALLOC(ioctlp,
6755               struct smb2_ioctl_rq *,
6756               sizeof(struct smb2_ioctl_rq),
6757               M_SMBTEMP,
6758               M_WAITOK | M_ZERO);
6759    if (ioctlp == NULL) {
6760		SMBERROR("SMB_MALLOC failed\n");
6761        error = ENOMEM;
6762        goto bad;
6763    }
6764
6765    ioctlp->share = share;
6766    ioctlp->ctl_code = FSCTL_SRV_REQUEST_RESUME_KEY;
6767    ioctlp->fid = fid;
6768
6769	ioctlp->snd_input_len = 0;
6770	ioctlp->snd_output_len = 0;
6771	ioctlp->rcv_input_len = 0;
6772	ioctlp->rcv_output_len = 0x20;
6773
6774    error = smb2_smb_ioctl(share, ioctlp, NULL, context);
6775
6776    if (!error) {
6777        memcpy(resume_key, ioctlp->rcv_output_buffer, SMB2_RESUME_KEY_LEN);
6778        SMB_FREE(ioctlp->rcv_output_buffer, M_TEMP);
6779    }
6780
6781bad:
6782    if (ioctlp != NULL) {
6783        SMB_FREE(ioctlp, M_SMBTEMP);
6784    }
6785
6786    return (error);
6787}
6788
6789/*
6790 * The calling routine must hold a reference on the share
6791 */
6792int
6793smbfs_smb_rmdir(struct smb_share *share, struct smbnode *np,
6794                vfs_context_t context)
6795{
6796    int error;
6797
6798    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
6799        error = smb2fs_smb_delete (share, np, VDIR,
6800                                   NULL, 0,
6801                                   0, context);
6802    }
6803    else {
6804        error = smb1fs_smb_rmdir (share, np, context);
6805    }
6806
6807    return error;
6808}
6809
6810int
6811smb2fs_smb_security_get(struct smb_share *share, struct smbnode *np,
6812                        uint32_t desired_access, uint32_t security_attrs,
6813                        struct ntsecdesc **resp, uint32_t *resp_len,
6814                        vfs_context_t context)
6815{
6816	int error;
6817    enum vtype vnode_type = VREG;
6818
6819    /* Try to determine the vnode type for the Create Request */
6820
6821    if ((np) && (np->n_vnode)) {
6822        /* Use vnode to determine type */
6823        vnode_type = vnode_isdir(np->n_vnode) ? VDIR : VREG;
6824    }
6825
6826    /*
6827     * Do the Compound Create/QueryInfo/Close call
6828     */
6829    error = smb2fs_smb_cmpd_query(share, np, vnode_type,
6830                                  NULL, 0,
6831                                  0, desired_access,
6832                                  SMB2_0_INFO_SECURITY, 0,
6833                                  security_attrs, NULL,
6834                                  resp_len, (uint8_t *) resp,
6835                                  context);
6836    if (error) {
6837        SMBDEBUG("smb2fs_smb_cmpd_query failed %d\n", error);
6838    }
6839
6840    return error;
6841}
6842
6843int
6844smb2fs_smb_security_set(struct smb_share *share, struct smbnode *np,
6845                        uint32_t desired_access,
6846                        uint32_t security_attrs, uint16_t control_flags,
6847                        struct ntsid *owner, struct ntsid *group,
6848                        struct ntacl *sacl, struct ntacl *dacl,
6849                        vfs_context_t context)
6850{
6851	int error;
6852    uint32_t setinfo_ntstatus;
6853    struct smb2_set_info_security sec_info;
6854    enum vtype vnode_type = VREG;
6855
6856    /*
6857     * Set up for the Set Info call
6858     */
6859    sec_info.security_attrs = security_attrs;
6860    sec_info.control_flags = control_flags;
6861    sec_info.owner = owner;
6862    sec_info.group = group;
6863    sec_info.sacl = sacl;
6864    sec_info.dacl = dacl;
6865
6866    if ((np) && (np->n_vnode)) {
6867        /* Use vnode to determine type */
6868        vnode_type = vnode_isdir(np->n_vnode) ? VDIR : VREG;
6869    }
6870
6871    /*
6872     * Do the Compound Create/SetInfo/Close call
6873     */
6874    error = smb2fs_smb_cmpd_set_info(share, np, vnode_type,
6875                                     NULL, 0,
6876                                     0, desired_access,
6877                                     SMB2_0_INFO_SECURITY, 0,
6878                                     security_attrs,
6879                                     sizeof (sec_info), (uint8_t *) &sec_info,
6880                                     &setinfo_ntstatus,
6881                                     context);
6882    if (error) {
6883        SMBDEBUG("smb2fs_smb_cmpd_set_info failed %d, ntstatus 0x%x\n",
6884                 error, setinfo_ntstatus);
6885
6886        if (setinfo_ntstatus == STATUS_INVALID_SID) {
6887            /*
6888             * If the server returns STATUS_INVALID_SID, then just pretend
6889             * that we set the security info even though it "failed".
6890             * See <rdar://problem/10852453>.
6891             */
6892            error = 0;
6893        }
6894    }
6895
6896    return error;
6897}
6898
6899int
6900smbfs_smb_setsec(struct smb_share *share, struct smbnode *np,
6901                 uint32_t desired_access, SMBFID fid,
6902                 uint32_t selector, uint16_t control_flags,
6903                 struct ntsid *owner, struct ntsid *group,
6904                 struct ntacl *sacl, struct ntacl *dacl,
6905                 vfs_context_t context)
6906{
6907	int error;
6908
6909    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
6910        error = smb2fs_smb_security_set(share, np, desired_access,
6911                                        selector, control_flags,
6912                                        owner, group,
6913                                        sacl, dacl,
6914                                        context);
6915    }
6916    else {
6917        error = smb1fs_setsec(share, fid, selector, control_flags,
6918                            owner, group, sacl, dacl, context);
6919    }
6920
6921    return (error);
6922}
6923
6924static int
6925smb2fs_smb_set_allocation(struct smb_share *share, SMBFID fid,
6926                          uint64_t new_size, vfs_context_t context)
6927{
6928    int error;
6929    struct smb2_set_info_rq *infop = NULL;
6930
6931    SMB_MALLOC(infop,
6932               struct smb2_set_info_rq *,
6933               sizeof(struct smb2_set_info_rq),
6934               M_SMBTEMP,
6935               M_WAITOK | M_ZERO);
6936    if (infop == NULL) {
6937        SMBERROR("SMB_MALLOC failed\n");
6938        error = ENOMEM;
6939        goto bad;
6940    }
6941
6942    /*
6943     * Set up for the Set Info call
6944     */
6945    infop->info_type = SMB2_0_INFO_FILE;
6946    infop->file_info_class = FileAllocationInformation;
6947    infop->add_info = 0;
6948    infop->fid = fid;
6949    infop->input_buffer = (uint8_t *) &new_size;
6950
6951    error = smb2_smb_set_info(share, infop, NULL, context);
6952    if (error) {
6953        SMBDEBUG("smb2_smb_set_info failed %d ntstatus %d\n",
6954                 error,
6955                 infop->ret_ntstatus);
6956        goto bad;
6957    }
6958
6959bad:
6960    if (infop != NULL) {
6961        SMB_FREE(infop, M_SMBTEMP);
6962    }
6963
6964    return error;
6965}
6966
6967/*
6968 * This routine will send an allocation across the wire to the server.
6969 *
6970 * The calling routine must hold a reference on the share
6971 *
6972 */
6973int
6974smbfs_smb_set_allocation(struct smb_share *share, SMBFID fid, uint64_t new_size,
6975                         vfs_context_t context)
6976{
6977    int error;
6978
6979    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
6980        error = smb2fs_smb_set_allocation(share, fid, new_size, context);
6981    }
6982    else {
6983        error = smb1fs_set_allocation(share, fid, new_size, context);
6984    }
6985    return error;
6986}
6987
6988
6989static int
6990smb2fs_smb_set_eof(struct smb_share *share, SMBFID fid, uint64_t newsize,
6991                  vfs_context_t context)
6992{
6993    int error;
6994    struct smb2_set_info_rq *infop = NULL;
6995
6996    SMB_MALLOC(infop,
6997               struct smb2_set_info_rq *,
6998               sizeof(struct smb2_set_info_rq),
6999               M_SMBTEMP,
7000               M_WAITOK | M_ZERO);
7001    if (infop == NULL) {
7002        SMBERROR("SMB_MALLOC failed\n");
7003        error = ENOMEM;
7004        goto bad;
7005    }
7006
7007    /*
7008     * Set up for the Set Info call
7009     */
7010    infop->info_type = SMB2_0_INFO_FILE;
7011    infop->file_info_class = FileEndOfFileInformation;
7012    infop->add_info = 0;
7013    infop->fid = fid;
7014    infop->input_buffer = (uint8_t *) &newsize;
7015
7016    /*
7017     * Do the Set Info call
7018     */
7019    error = smb2_smb_set_info(share, infop, NULL, context);
7020    if (error) {
7021        SMBDEBUG("smb2_smb_set_info failed %d ntstatus %d\n",
7022                 error,
7023                 infop->ret_ntstatus);
7024        goto bad;
7025    }
7026
7027bad:
7028    if (infop != NULL) {
7029        SMB_FREE(infop, M_SMBTEMP);
7030    }
7031
7032	return error;
7033}
7034
7035/*
7036 * This routine will send a seteof across the wire to the server.
7037 *
7038 * The calling routine must hold a reference on the share
7039 *
7040 */
7041int
7042smbfs_smb_seteof(struct smb_share *share, SMBFID fid, uint64_t newsize,
7043                 vfs_context_t context)
7044{
7045	int error;
7046
7047    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
7048        error = smb2fs_smb_set_eof(share, fid, newsize, context);
7049    }
7050    else {
7051        error = smb1fs_seteof(share, fid, newsize, context);
7052    }
7053    return error;
7054}
7055
7056static int
7057smb2fs_smb_set_file_basic_info(struct smb_share *share,
7058                               struct smb2_set_info_file_basic_info **infopp,
7059                               struct timespec *crtime, struct timespec *atime,
7060                               struct timespec *mtime, uint32_t file_attrs)
7061{
7062    uint64_t tm;
7063
7064    SMB_MALLOC(*infopp,
7065               struct smb2_set_info_file_basic_info *,
7066               sizeof(struct smb2_set_info_file_basic_info),
7067               M_SMBTEMP,
7068               M_WAITOK | M_ZERO);
7069    if (*infopp == NULL) {
7070        SMBERROR("SMB_MALLOC failed\n");
7071        return (ENOMEM);
7072    }
7073
7074    /*
7075     * Set Creation time
7076     */
7077	tm = 0;
7078	if (crtime) {
7079		smb_time_local2NT(crtime, &tm, (share->ss_fstype == SMB_FS_FAT));
7080        (*infopp)->create_time = tm;
7081	}
7082
7083    /* Set last access time */
7084	tm = 0;
7085	if (atime) {
7086		smb_time_local2NT(atime, &tm, (share->ss_fstype == SMB_FS_FAT));
7087        (*infopp)->access_time = tm;
7088	}
7089
7090	/* Set last write time */
7091	tm = 0;
7092	if (mtime) {
7093		smb_time_local2NT(mtime, &tm, (share->ss_fstype == SMB_FS_FAT));
7094        (*infopp)->write_time = tm;
7095	}
7096
7097    /* We never allow anyone to set the change time */
7098
7099	/* set file attributes */
7100    (*infopp)->attributes = file_attrs;
7101
7102    return (0);
7103}
7104
7105static int
7106smb2fs_smb_setfattrNT(struct smb_share *share, uint32_t attr, SMBFID fid,
7107                      struct timespec *crtime, struct timespec *mtime,
7108                      struct timespec *atime, vfs_context_t context)
7109{
7110    int error;
7111    struct smb2_set_info_rq *infop = NULL;
7112    struct smb2_set_info_file_basic_info *basic_infop = NULL;
7113
7114    /* Allocate and fill out the file basic info */
7115    error = smb2fs_smb_set_file_basic_info(share, &basic_infop,
7116                                           crtime, atime, mtime, attr);
7117    if (error) {
7118        SMBDEBUG("smb2fs_smb_set_file_basic_info failed %d\n", error);
7119        goto bad;
7120    }
7121
7122    SMB_MALLOC(infop,
7123               struct smb2_set_info_rq *,
7124               sizeof(struct smb2_set_info_rq),
7125               M_SMBTEMP,
7126               M_WAITOK | M_ZERO);
7127    if (infop == NULL) {
7128        SMBERROR("SMB_MALLOC failed\n");
7129        error = ENOMEM;
7130        goto bad;
7131    }
7132
7133    /*
7134     * Set up for the Set Info call
7135     */
7136    infop->info_type = SMB2_0_INFO_FILE;
7137    infop->file_info_class = FileBasicInformation;
7138    infop->add_info = 0;
7139    infop->fid = fid;
7140    infop->input_buffer = (uint8_t *) basic_infop;
7141
7142    /*
7143     * Do the Set Info call
7144     */
7145    error = smb2_smb_set_info(share, infop, NULL, context);
7146    if (error) {
7147        SMBDEBUG("smb2_smb_set_info failed %d ntstatus %d\n",
7148                 error,
7149                 infop->ret_ntstatus);
7150        goto bad;
7151    }
7152
7153bad:
7154    if (infop != NULL) {
7155        SMB_FREE(infop, M_SMBTEMP);
7156    }
7157
7158    if (basic_infop != NULL) {
7159        SMB_FREE(basic_infop, M_SMBTEMP);
7160    }
7161
7162    return error;
7163}
7164
7165/*
7166 * Same as smbfs_smb_setpattrNT except with a file handle. Note once we remove
7167 * Windows 98 support we can remove passing the node into this routine.
7168 *
7169 * The calling routine must hold a reference on the share
7170 *
7171 */
7172int
7173smbfs_smb_setfattrNT(struct smb_share *share, uint32_t attr, SMBFID fid,
7174                     struct timespec *crtime, struct timespec *mtime,
7175					 struct timespec *atime, vfs_context_t context)
7176{
7177    int error;
7178
7179    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
7180        error = smb2fs_smb_setfattrNT(share, attr, fid, crtime, mtime, atime,
7181                                      context);
7182    }
7183    else {
7184        error = smb1fs_smb_setfattrNT(share, attr, fid, crtime, mtime, atime,
7185                                      context);
7186    }
7187    return error;
7188}
7189
7190/*
7191 * Set DOS file attributes, may want to replace with a more modern call
7192 *
7193 * The calling routine must hold a reference on the share
7194 *
7195 */
7196int
7197smbfs_smb_setpattr(struct smb_share *share, struct smbnode *np, enum vtype vnode_type,
7198                   const char *namep, size_t name_len,
7199                   uint16_t attr, vfs_context_t context)
7200{
7201    int error;
7202
7203    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
7204        error = smb2fs_smb_setpattrNT(share, np, vnode_type,
7205                                      namep, name_len,
7206                                      attr, NULL,
7207                                      NULL, NULL,
7208                                      context);
7209    }
7210    else {
7211        error = smb1fs_smb_setpattr(share, np,
7212                                    namep, name_len,
7213                                    attr, context);
7214    }
7215    return error;
7216}
7217
7218int
7219smb2fs_smb_setpattrNT(struct smb_share *share, struct smbnode *np, enum vtype vnode_type,
7220                      const char *namep, size_t name_len,
7221                      uint32_t attr, struct timespec *crtime,
7222                      struct timespec *mtime, struct timespec *atime,
7223                      vfs_context_t context)
7224{
7225    int error;
7226    uint32_t setinfo_ntstatus;
7227    struct smb2_set_info_file_basic_info *basic_infop = NULL;
7228
7229    /* Allocate and fill out the file basic info */
7230    error = smb2fs_smb_set_file_basic_info(share, &basic_infop,
7231                                           crtime, atime, mtime, attr);
7232    if (error) {
7233        SMBDEBUG("smb2fs_smb_set_file_basic_info failed %d\n", error);
7234        goto bad;
7235    }
7236
7237    /*
7238     * Do the Compound Create/SetInfo/Close call
7239     */
7240    error = smb2fs_smb_cmpd_set_info(share, np, vnode_type,
7241                                     namep, name_len,
7242                                     0, SMB2_FILE_WRITE_ATTRIBUTES | SMB2_SYNCHRONIZE,
7243                                     SMB2_0_INFO_FILE, FileBasicInformation,
7244                                     0,
7245                                     sizeof (*basic_infop), (uint8_t *) basic_infop,
7246                                     &setinfo_ntstatus,
7247                                     context);
7248    if (error) {
7249        SMBDEBUG("smb2fs_smb_cmpd_set_info failed %d\n", error);
7250        goto bad;
7251    }
7252
7253bad:
7254    if (basic_infop != NULL) {
7255        SMB_FREE(basic_infop, M_SMBTEMP);
7256    }
7257
7258    return error;
7259}
7260
7261/*
7262 * BASIC_INFO works with Samba, but Win2K servers say it is an invalid information
7263 * level on a SET_PATH_INFO.  Note Win2K does support *BASIC_INFO on a SET_FILE_INFO,
7264 * and they support the equivalent *BASIC_INFORMATION on SET_PATH_INFO. Go figure.
7265 *
7266 * The calling routine must hold a reference on the share
7267 *
7268 */
7269int
7270smbfs_smb_setpattrNT(struct smb_share *share, struct smbnode *np, enum vtype vnode_type,
7271                     const char *namep, size_t name_len,
7272                     uint32_t attr, struct timespec *crtime,
7273                     struct timespec *mtime, struct timespec *atime,
7274                     vfs_context_t context)
7275{
7276    int error;
7277
7278    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
7279        error = smb2fs_smb_setpattrNT(share, np, vnode_type,
7280                                      namep, name_len,
7281                                      attr, crtime,
7282                                      mtime, atime,
7283                                      context);
7284    }
7285    else {
7286        error = smb1fs_smb_setpattrNT(share, np, attr, crtime, mtime, atime,
7287                                      context);
7288    }
7289    return error;
7290}
7291
7292static int
7293smb2fs_smb_statfs(struct smbmount *smp,
7294                  struct FILE_FS_SIZE_INFORMATION *fs_size,
7295                  vfs_context_t context)
7296{
7297    struct smb_share *share = smp->sm_share;
7298	int error;
7299    uint32_t output_buffer_len;
7300
7301    output_buffer_len = sizeof(struct FILE_FS_SIZE_INFORMATION);
7302
7303    /*
7304     * Do the Compound Create/GetInfo/Close call
7305     * Query results are passed back in *fs_size
7306     *
7307     * Have to pass in submount path if it exists because we have no root vnode,
7308     * and smbmount and smb_share may not be fully set up yet.
7309     *
7310     * This is always done on the root of the share.
7311     */
7312    error = smb2fs_smb_cmpd_query(share, NULL, VDIR,
7313                                  (smp->sm_args.path_len == 0 ? NULL : smp->sm_args.path),
7314                                  smp->sm_args.path_len,
7315                                  0, SMB2_FILE_READ_ATTRIBUTES | SMB2_SYNCHRONIZE,
7316                                  SMB2_0_INFO_FILESYSTEM, FileFsSizeInformation,
7317                                  0, NULL,
7318                                  &output_buffer_len, (uint8_t *) fs_size,
7319                                  context);
7320
7321	return error;
7322}
7323
7324/*
7325 * The calling routine must hold a reference on the share
7326 */
7327int
7328smbfs_smb_statfs(struct smbmount *smp, struct vfsstatfs *sbp,
7329                 vfs_context_t context)
7330{
7331    struct smb_share *share = smp->sm_share;
7332   	struct smb_vc *vcp = SSTOVC(share);
7333    struct FILE_FS_SIZE_INFORMATION fs_size;
7334	int error;
7335	uint64_t s, t, f;
7336	size_t xmax;
7337
7338    bzero(&fs_size, sizeof(fs_size));
7339
7340    if (vcp->vc_flags & SMBV_SMB2) {
7341        error = smb2fs_smb_statfs(smp, &fs_size, context);
7342    }
7343    else {
7344        /*
7345         * Goal is to leave the SMB 1 code unchanged as much as possible
7346         * to minimize the risk.  That is why there is duplicate code here
7347         * for the SMB 2/3 path and also in SMB 1 code path.
7348         */
7349        error = smb1fs_statfs(share, sbp, context);
7350        return (error);
7351    }
7352
7353	if (error) {
7354        return error;
7355    }
7356
7357    t = fs_size.total_alloc_units;
7358    f = fs_size.avail_alloc_units;
7359    s = fs_size.bytes_per_sector;
7360    s *= fs_size.sectors_per_alloc_unit;
7361    /*
7362     * Don't allow over-large blocksizes as they determine
7363     * Finder List-view size granularities.  On the other
7364     * hand, we mustn't let the block count overflow the
7365     * 31 bits available.
7366     */
7367    while (s > 16 * 1024) {
7368        if (t > LONG_MAX)
7369            break;
7370        s /= 2;
7371        t *= 2;
7372        f *= 2;
7373    }
7374    while (t > LONG_MAX) {
7375        t /= 2;
7376        f /= 2;
7377        s *= 2;
7378    }
7379    sbp->f_bsize = (uint32_t)s;	/* fundamental file system block size */
7380    sbp->f_blocks= t;	/* total data blocks in file system */
7381    sbp->f_bfree = f;	/* free blocks in fs */
7382    sbp->f_bavail= f;	/* free blocks avail to non-superuser */
7383    sbp->f_files = (-1);	/* total file nodes in file system */
7384    sbp->f_ffree = (-1);	/* free file nodes in fs */
7385
7386    /*
7387     * Done with the network stuff, now get the iosize. This code was moved from
7388     * smbfs_vfs_getattr to here
7389     *
7390     * The min size of f_iosize is 1 MB and the max is SMB_IOMAX.
7391     *
7392     * We used to report back a multiple of the max io size supported by the
7393     * server and then read/write that amount in synchronous calls (SMB 1 still
7394     * does this). Now, we just let the applications decide how large and how
7395     * many IO blocks they want to give us. Finder will scale up to 8 MB IO
7396     * blocks depending on the transfer times for each block. UBC will give us
7397     * multiple blocks of f_iosize depending on their internal logic. UBC gets
7398     * the f_iosize from us because we call vfs_setioattr().
7399     */
7400    xmax = max(SSTOVC(share)->vc_rxmax, SSTOVC(share)->vc_wxmax);
7401
7402    /*
7403     * <Is this still needed???>
7404     * Now we want to make sure it will land on both a PAGE_SIZE boundary and a
7405     * smb xfer size boundary. So first mod the xfer size by the page size, then
7406     * subtract that from page size. This will give us the extra amount that
7407     * will be needed to get it on a page boundary. Now divide the page size by
7408     * this amount. This will give us the number of xmax it will take to make
7409     * f_iosize land on a page size and xfer boundary.
7410     */
7411    xmax = (PAGE_SIZE / (PAGE_SIZE - (xmax % PAGE_SIZE))) * xmax;
7412
7413    if (xmax < SMB_IOMIN) {
7414        xmax = SMB_IOMIN;
7415    }
7416
7417    if (xmax > SMB_IOMAX)
7418        sbp->f_iosize = SMB_IOMAX;
7419    else
7420        sbp->f_iosize = xmax;
7421
7422    return error;
7423}
7424
7425int
7426smb2fs_smb_validate_neg_info(struct smb_share *share, vfs_context_t context)
7427{
7428    struct smb_vc *vcp = SSTOVC(share);
7429	int error = 0;
7430    struct smb2_ioctl_rq *ioctlp = NULL;
7431    struct smb2_secure_neg_info req;
7432    struct smb2_secure_neg_info reply;
7433	struct smb_sopt *sp = NULL;
7434
7435    if (vcp == NULL) {
7436        SMBERROR("vcp is null \n");
7437        return EINVAL;
7438    }
7439
7440    /*
7441     * Only SMB 3.x and non Anonymous/Guest supports validate negotiate
7442     */
7443    if (!(vcp->vc_flags & SMBV_SMB2) ||
7444        (vcp->vc_flags & (SMBV_SMB2002 | SMBV_SMB21)) ||
7445        (vcp->vc_flags & SMBV_ANONYMOUS_ACCESS) ||
7446        (vcp->vc_flags & SMBV_GUEST_ACCESS)) {
7447        return 0;
7448    }
7449
7450    sp = &vcp->vc_sopt;
7451    if (sp == NULL) {
7452        SMBERROR("sp is null \n");
7453        return EINVAL;
7454    }
7455
7456    bzero(&req, sizeof(req));
7457    bzero(&reply, sizeof(reply));
7458
7459    SMB_MALLOC(ioctlp,
7460               struct smb2_ioctl_rq *,
7461               sizeof(struct smb2_ioctl_rq),
7462               M_SMBTEMP,
7463               M_WAITOK | M_ZERO);
7464    if (ioctlp == NULL) {
7465		SMBERROR("SMB_MALLOC failed\n");
7466        error = ENOMEM;
7467        goto bad;
7468    }
7469
7470    /*
7471     * Fill in the Secure Negotiate Request Info
7472     */
7473    req.capabilities = smb2_smb_get_client_capabilities(vcp);
7474    memcpy(&req.guid, vcp->vc_client_guid, 16);
7475    req.security_mode = smb2_smb_get_client_security_mode(vcp);
7476
7477    error = smb2_smb_get_client_dialects(vcp, 0, &req.dialect_count,
7478                                         req.dialects, sizeof(req.dialects));
7479    if (error) {
7480        return error;
7481    }
7482
7483    /*
7484     * Build and send the IOCTL request
7485     */
7486    ioctlp->share = share;
7487    ioctlp->ctl_code = FSCTL_VALIDATE_NEGOTIATE_INFO;
7488    ioctlp->fid = 0;
7489
7490	ioctlp->snd_output_len = 0;
7491	ioctlp->rcv_input_len = 0;
7492
7493    /*
7494     * Calculate len of Validate Negotiate Request
7495     * 24 = Capabilities (4) + GUID (16) + SecurityMode (2) + DialectCount (2)
7496     * +2 bytes per Dialect added
7497     */
7498    ioctlp->snd_input_len = 24;
7499    ioctlp->snd_input_len += 2 * req.dialect_count;
7500	ioctlp->snd_input_buffer = (uint8_t *) &req;
7501
7502    ioctlp->rcv_output_len = sizeof(reply);
7503    ioctlp->rcv_output_buffer = (uint8_t *) &reply;
7504
7505    error = smb2_smb_ioctl(share, ioctlp, NULL, context);
7506    if (error) {
7507        if ((error == EINVAL) || (error == ENOTSUP)) {
7508            /*
7509             * A signed reply with STATUS_NOT_SUPPORTED is acceptable, but
7510             * we can not validate the server capabilites. Just leave with
7511             * no error and without checking capabilities.
7512             *
7513             * NetApp is returning STATUS_INVALID_DEVICE_REQUEST instead which
7514             * is not correct.
7515             */
7516            SMBWARNING("Server does not fully support Validate Negotiate %d\n", error);
7517            error = 0;
7518        }
7519        else {
7520            SMBERROR("smb2_smb_ioctl failed %d\n", error);
7521        }
7522
7523        goto bad;
7524    }
7525
7526    /* Verify that the server info matches our current session */
7527
7528	/* Check Capabilities */
7529	if (reply.capabilities != sp->sv_capabilities) {
7530		SMBERROR("Server capabilities do not match \n");
7531		error = EAUTH;
7532        goto bad;
7533	}
7534
7535	/* Check GUID */
7536	if (memcmp(&reply.guid, &sp->sv_guid, sizeof(reply.guid)) != 0) {
7537		SMBERROR("Server GUID does not match \n");
7538		error = EAUTH;
7539        goto bad;
7540	}
7541
7542 	/* Check Security Mode */
7543	if (reply.security_mode != sp->sv_security_mode) {
7544		SMBERROR("Server security mode does not match \n");
7545		error = EAUTH;
7546        goto bad;
7547	}
7548
7549 	/* Check Dialect */
7550    switch (reply.dialects[0]) {
7551        case SMB2_DIALECT_0302:
7552            if (!(vcp->vc_flags & (SMBV_SMB2 | SMBV_SMB302))) {
7553                SMBERROR("Server dialect does not match \n");
7554                error = EAUTH;
7555            }
7556            break;
7557        case SMB2_DIALECT_0300:
7558            if (!(vcp->vc_flags & (SMBV_SMB2 | SMBV_SMB30))) {
7559                SMBERROR("Server dialect does not match \n");
7560                error = EAUTH;
7561            }
7562            break;
7563        case SMB2_DIALECT_0210:
7564            if (!(vcp->vc_flags & (SMBV_SMB2 | SMBV_SMB21))) {
7565                SMBERROR("Server dialect does not match \n");
7566                error = EAUTH;
7567            }
7568            break;
7569        case SMB2_DIALECT_0202:
7570            if (!(vcp->vc_flags & (SMBV_SMB2 | SMBV_SMB2002))) {
7571                SMBERROR("Server dialect does not match \n");
7572                error = EAUTH;
7573            }
7574            break;
7575
7576        default:
7577            SMBERROR("Unknown server dialect does not match \n");
7578            error = EAUTH;
7579            break;
7580    }
7581
7582bad:
7583    if (ioctlp != NULL) {
7584        SMB_FREE(ioctlp, M_SMBTEMP);
7585    }
7586
7587	return error;
7588}
7589
7590