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