examples: clifuse: Info level SMB_FIND_FILE_BOTH_DIRECTORY_INFO encodes attibutes...
[bbaumbach/samba-autobuild/.git] / examples / fuse / clifuse.c
1 /*
2  * Unix SMB/CIFS implementation.
3  * fusermount smb2 client
4  * Copyright (C) Volker Lendecke 2016
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #define FUSE_USE_VERSION 26
21 #define _FILE_OFFSET_BITS 64
22 #include "fuse/fuse_lowlevel.h"
23
24 #include "source3/include/includes.h"
25 #include "client.h"
26 #include "trans2.h"
27 #include "libsmb/proto.h"
28 #include "libsmb/clirap.h"
29 #include "libsmb/cli_smb2_fnum.h"
30 #include "lib/util/tevent_ntstatus.h"
31 #include "libcli/smb/smbXcli_base.h"
32 #include "libcli/security/security.h"
33 #include "clifuse.h"
34
35 struct mount_state {
36         struct tevent_context *ev;
37         struct cli_state *cli;
38         bool done;
39
40         struct tevent_fd *fde;
41         struct tevent_signal *signal_ev;
42
43         struct fuse_chan *ch;
44         struct fuse_session *se;
45
46         size_t bufsize;
47         char *buf;
48
49         struct idr_context *ino_ctx;
50         TALLOC_CTX *ino_parent;
51 };
52
53 struct inode_state {
54         struct idr_context *ino_ctx;
55         fuse_ino_t ino;
56         char path[1];
57 };
58
59 static int inode_state_destructor(struct inode_state *s);
60
61 static struct inode_state *inode_state_init(TALLOC_CTX *mem_ctx,
62                                             struct idr_context *ino_ctx,
63                                             const char *path)
64 {
65         struct inode_state *state;
66         size_t pathlen;
67         int ino;
68
69         pathlen = strlen(path);
70         state = talloc_size(
71                 mem_ctx, offsetof(struct inode_state, path) + pathlen + 1);
72         if (state == NULL) {
73                 return NULL;
74         }
75         talloc_set_name_const(state, "struct inode_state");
76
77         ino = idr_get_new_above(ino_ctx, state, 1, INT32_MAX);
78         if (ino == -1) {
79                 TALLOC_FREE(state);
80                 return NULL;
81         }
82
83         state->ino = ino;
84         state->ino_ctx = ino_ctx;
85         memcpy(state->path, path, pathlen + 1);
86
87         DBG_DEBUG("Creating ino %d for path %s\n", ino, path);
88
89         talloc_set_destructor(state, inode_state_destructor);
90
91         return state;
92 }
93
94 static struct inode_state *inode_state_new(struct mount_state *mstate,
95                                            const char *path)
96 {
97         return inode_state_init(mstate->ino_parent, mstate->ino_ctx, path);
98 }
99
100 static int inode_state_destructor(struct inode_state *s)
101 {
102         DBG_DEBUG("destroying inode %ju\n", (uintmax_t)s->ino);
103         idr_remove(s->ino_ctx, s->ino);
104         return 0;
105 }
106
107 struct ll_create_state {
108         struct mount_state *mstate;
109         fuse_req_t freq;
110         struct fuse_file_info fi;
111         char *path;
112 };
113
114 static void cli_ll_create_done(struct tevent_req *req);
115
116 static void cli_ll_create(fuse_req_t freq, fuse_ino_t parent, const char *name,
117                           mode_t mode, struct fuse_file_info *fi)
118 {
119         struct mount_state *mstate = talloc_get_type_abort(
120                 fuse_req_userdata(freq), struct mount_state);
121         struct ll_create_state *state;
122         struct inode_state *istate;
123         struct tevent_req *req;
124
125         DBG_DEBUG("parent=%ju, name=%s, mode=%x\n", (uintmax_t)parent,
126                   name, (unsigned)mode);
127
128         istate = idr_find(mstate->ino_ctx, parent);
129         if (istate == NULL) {
130                 fuse_reply_err(freq, ENOENT);
131                 return;
132         }
133
134         state = talloc(mstate, struct ll_create_state);
135         if (state == NULL) {
136                 fuse_reply_err(freq, ENOMEM);
137                 return;
138         }
139         state->mstate = mstate;
140         state->freq = freq;
141         state->fi = *fi;
142
143         state->path = talloc_asprintf(state, "%s%s%s", istate->path,
144                                       strlen(istate->path) ? "\\": "",
145                                       name);
146         if (state->path == NULL) {
147                 TALLOC_FREE(state);
148                 fuse_reply_err(freq, ENOMEM);
149                 return;
150         }
151
152         req = cli_smb2_create_fnum_send(
153                 state,
154                 mstate->ev,
155                 mstate->cli, state->path,
156                 0,
157                 SMB2_IMPERSONATION_IMPERSONATION,
158                 FILE_GENERIC_READ|FILE_GENERIC_WRITE,
159                 FILE_ATTRIBUTE_NORMAL,
160                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
161                 FILE_CREATE,
162                 FILE_NON_DIRECTORY_FILE,
163                 NULL);
164         if (req == NULL) {
165                 TALLOC_FREE(state);
166                 fuse_reply_err(freq, ENOMEM);
167                 return;
168         }
169         tevent_req_set_callback(req, cli_ll_create_done, state);
170 }
171
172 static void cli_ll_create_done(struct tevent_req *req)
173 {
174         struct ll_create_state *state = tevent_req_callback_data(
175                 req, struct ll_create_state);
176         struct fuse_entry_param e;
177         struct inode_state *ino;
178         uint16_t fnum;
179         NTSTATUS status;
180
181         status = cli_smb2_create_fnum_recv(req, &fnum, NULL, NULL, NULL);
182         TALLOC_FREE(req);
183         if (!NT_STATUS_IS_OK(status)) {
184                 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
185                 return;
186         }
187
188         state->fi.fh = fnum;
189         state->fi.direct_io = 0;
190         state->fi.keep_cache = 0;
191
192         ino = inode_state_new(state->mstate, state->path);
193         if (ino == NULL) {
194                 fuse_reply_err(state->freq, ENOMEM);
195                 return;
196         }
197
198         e = (struct fuse_entry_param) {
199                 .ino = ino->ino,
200                 .generation = 1, /* FIXME */
201                 .attr_timeout = 1.0,
202                 .entry_timeout = 1.0
203         };
204
205         fuse_reply_create(state->freq, &e, &state->fi);
206
207         TALLOC_FREE(state);
208 }
209
210 struct cli_get_unixattr_state {
211         struct tevent_context *ev;
212         struct cli_state *cli;
213         uint64_t fid_persistent;
214         uint64_t fid_volatile;
215
216         struct timespec create_time;
217         struct timespec access_time;
218         struct timespec write_time;
219         struct timespec change_time;
220         uint32_t mode;
221         uint64_t ino;
222         uint64_t size;
223 };
224
225 static void cli_get_unixattr_opened(struct tevent_req *subreq);
226 static void cli_get_unixattr_gotinfo(struct tevent_req *subreq);
227 static void cli_get_unixattr_closed(struct tevent_req *subreq);
228
229
230 static struct tevent_req *cli_get_unixattr_send(TALLOC_CTX *mem_ctx,
231                                                 struct tevent_context *ev,
232                                                 struct cli_state *cli,
233                                                 const char *path)
234 {
235         struct tevent_req *req, *subreq;
236         struct cli_get_unixattr_state *state;
237
238         req = tevent_req_create(mem_ctx, &state,
239                                 struct cli_get_unixattr_state);
240         if (req == NULL) {
241                 return NULL;
242         }
243         state->ev = ev;
244         state->cli = cli;
245
246         subreq = smb2cli_create_send(
247                 state, ev, cli->conn, cli->timeout, cli->smb2.session,
248                 cli->smb2.tcon, path, SMB2_OPLOCK_LEVEL_NONE,
249                 SMB2_IMPERSONATION_IMPERSONATION,
250                 SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES, 0,
251                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
252                 FILE_OPEN, 0, NULL);
253         if (tevent_req_nomem(subreq, req)) {
254                 return tevent_req_post(req, ev);
255         }
256         tevent_req_set_callback(subreq, cli_get_unixattr_opened, req);
257
258         return req;
259 }
260
261 static void cli_get_unixattr_opened(struct tevent_req *subreq)
262 {
263         struct tevent_req *req = tevent_req_callback_data(
264                 subreq, struct tevent_req);
265         struct cli_get_unixattr_state *state = tevent_req_data(
266                 req, struct cli_get_unixattr_state);
267         struct cli_state *cli = state->cli;
268         NTSTATUS status;
269
270         status = smb2cli_create_recv(subreq, &state->fid_persistent,
271                                      &state->fid_volatile, NULL, NULL, NULL);
272         TALLOC_FREE(subreq);
273         if (tevent_req_nterror(req, status)) {
274                 DBG_DEBUG("smb2cli_create_recv returned %s\n",
275                           nt_errstr(status));
276                 return;
277         }
278
279         subreq = smb2cli_query_info_send(
280                 state, state->ev, cli->conn, 0,
281                 cli->smb2.session, cli->smb2.tcon,
282                 1, /* in_info_type */
283                 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
284                 0xFFFF, /* in_max_output_length */
285                 NULL, /* in_input_buffer */
286                 0, /* in_additional_info */
287                 0, /* in_flags */
288                 state->fid_persistent,
289                 state->fid_volatile);
290         if (tevent_req_nomem(subreq, req)) {
291                 return;
292         }
293         tevent_req_set_callback(subreq, cli_get_unixattr_gotinfo, req);
294 }
295
296 static void cli_get_unixattr_gotinfo(struct tevent_req *subreq)
297 {
298         struct tevent_req *req = tevent_req_callback_data(
299                 subreq, struct tevent_req);
300         struct cli_get_unixattr_state *state = tevent_req_data(
301                 req, struct cli_get_unixattr_state);
302         struct cli_state *cli = state->cli;
303         NTSTATUS status;
304         DATA_BLOB outbuf;
305
306         status = smb2cli_query_info_recv(subreq, state, &outbuf);
307         TALLOC_FREE(subreq);
308         if (tevent_req_nterror(req, status)) {
309                 DBG_DEBUG("smb2cli_query_info_recv returned %s\n",
310                           nt_errstr(status));
311                 return;
312         }
313
314         if (outbuf.length < 0x60) {
315                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
316                 return;
317         }
318
319         state->create_time = interpret_long_date((char *)outbuf.data + 0x0);
320         state->access_time = interpret_long_date((char *)outbuf.data + 0x8);
321         state->write_time  = interpret_long_date((char *)outbuf.data + 0x10);
322         state->change_time = interpret_long_date((char *)outbuf.data + 0x18);
323         state->mode        = IVAL(outbuf.data, 0x20);
324         state->size        = BVAL(outbuf.data, 0x30);
325         state->ino         = BVAL(outbuf.data, 0x40);
326
327         subreq = smb2cli_close_send(state, state->ev, cli->conn, 0,
328                                     cli->smb2.session, cli->smb2.tcon, 0,
329                                     state->fid_persistent,
330                                     state->fid_volatile);
331         if (tevent_req_nomem(subreq, req)) {
332                 return;
333         }
334         tevent_req_set_callback(subreq, cli_get_unixattr_closed, req);
335 }
336
337 static void cli_get_unixattr_closed(struct tevent_req *subreq)
338 {
339         struct tevent_req *req = tevent_req_callback_data(
340                 subreq, struct tevent_req);
341         NTSTATUS status;
342
343         status = smb2cli_close_recv(subreq);
344         TALLOC_FREE(subreq);
345         if (tevent_req_nterror(req, status)) {
346                 return;
347         }
348         tevent_req_done(req);
349 }
350
351 static NTSTATUS cli_get_unixattr_recv(struct tevent_req *req,
352                                       struct stat *st)
353 {
354         struct cli_get_unixattr_state *state = tevent_req_data(
355                 req, struct cli_get_unixattr_state);
356         NTSTATUS status;
357
358         if (tevent_req_is_nterror(req, &status)) {
359                 return status;
360         }
361
362         if (IS_DOS_DIR(state->mode)) {
363                 st->st_mode = (S_IFDIR | 0555);
364                 st->st_nlink = 2;
365         } else {
366                 st->st_mode = (S_IFREG | 0444);
367                 st->st_nlink = 1;
368         }
369
370         st->st_size = state->size;
371         st->st_uid = getuid();
372         st->st_gid = getgid();
373         st->st_ino = state->ino;
374         st->st_atime = convert_timespec_to_time_t(state->access_time);
375         st->st_ctime = convert_timespec_to_time_t(state->change_time);
376         st->st_mtime = convert_timespec_to_time_t(state->write_time);
377
378         return NT_STATUS_OK;
379 }
380
381 struct cli_smb2_listdir_state {
382         struct tevent_context *ev;
383         struct smbXcli_conn *conn;
384         uint32_t timeout_msec;
385         struct smbXcli_session *session;
386         struct smbXcli_tcon *tcon;
387         uint8_t level;
388         uint8_t flags;
389         uint32_t file_index;
390         uint64_t fid_persistent;
391         uint64_t fid_volatile;
392         const char *mask;
393         uint32_t outbuf_len;
394
395         uint16_t attribute;
396         const char *mntpoint;
397         const char *pathname;
398         NTSTATUS (*fn)(const char *mntpoint, struct file_info *f,
399                        const char *mask, void *private_data);
400         void *private_data;
401         bool processed_file;
402 };
403
404 static void cli_smb2_listdir_done(struct tevent_req *subreq);
405
406 static struct tevent_req *cli_smb2_listdir_send(
407         TALLOC_CTX *mem_ctx,
408         struct tevent_context *ev,
409         struct smbXcli_conn *conn,
410         uint32_t timeout_msec,
411         struct smbXcli_session *session,
412         struct smbXcli_tcon *tcon,
413         uint8_t level,
414         uint8_t flags,
415         uint32_t file_index,
416         uint64_t fid_persistent,
417         uint64_t fid_volatile,
418         const char *mask,
419         uint32_t outbuf_len,
420         uint16_t attribute,
421         const char *mntpoint,
422         const char *pathname,
423         NTSTATUS (*fn)(const char *mntpoint, struct file_info *f,
424                        const char *mask, void *private_data),
425         void *private_data)
426 {
427         struct tevent_req *req, *subreq;
428         struct cli_smb2_listdir_state *state;
429
430         req = tevent_req_create(mem_ctx, &state,
431                                 struct cli_smb2_listdir_state);
432         if (req == NULL) {
433                 return NULL;
434         }
435         state->ev = ev;
436         state->conn = conn;
437         state->timeout_msec = timeout_msec;
438         state->session = session;
439         state->tcon = tcon;
440         state->level = level;
441         state->flags = flags;
442         state->file_index = file_index;
443         state->fid_persistent = fid_persistent;
444         state->fid_volatile = fid_volatile;
445         state->mask = mask;
446         state->outbuf_len = outbuf_len;
447         state->attribute = attribute;
448         state->mntpoint = mntpoint;
449         state->pathname = pathname;
450         state->fn = fn;
451         state->private_data = private_data;
452
453         subreq = smb2cli_query_directory_send(
454                 state, state->ev, state->conn, state->timeout_msec,
455                 state->session, state->tcon, state->level,
456                 state->flags, state->file_index,
457                 state->fid_persistent, state->fid_volatile,
458                 state->mask, state->outbuf_len);
459         if (tevent_req_nomem(subreq, req)) {
460                 return tevent_req_post(req, ev);
461         }
462         tevent_req_set_callback(subreq, cli_smb2_listdir_done, req);
463         return req;
464 }
465
466 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
467                                 uint32_t dir_data_length,
468                                 struct file_info *finfo,
469                                 uint32_t *next_offset)
470 {
471         size_t namelen = 0;
472         size_t slen = 0;
473         size_t ret = 0;
474
475         if (dir_data_length < 4) {
476                 return NT_STATUS_INFO_LENGTH_MISMATCH;
477         }
478
479         *next_offset = IVAL(dir_data, 0);
480
481         if (*next_offset > dir_data_length) {
482                 return NT_STATUS_INFO_LENGTH_MISMATCH;
483         }
484
485         if (*next_offset != 0) {
486                 /* Ensure we only read what in this record. */
487                 dir_data_length = *next_offset;
488         }
489
490         if (dir_data_length < 105) {
491                 return NT_STATUS_INFO_LENGTH_MISMATCH;
492         }
493
494         finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
495         finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
496         finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
497         finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
498         finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
499         finfo->mode = (uint16_t)IVAL(dir_data + 56, 0);
500         namelen = IVAL(dir_data + 60,0);
501         if (namelen > (dir_data_length - 104)) {
502                 return NT_STATUS_INFO_LENGTH_MISMATCH;
503         }
504         slen = CVAL(dir_data + 68, 0);
505         if (slen > 24) {
506                 return NT_STATUS_INFO_LENGTH_MISMATCH;
507         }
508         ret = pull_string_talloc(finfo,
509                                 dir_data,
510                                 FLAGS2_UNICODE_STRINGS,
511                                 &finfo->short_name,
512                                 dir_data + 70,
513                                 slen,
514                                 STR_UNICODE);
515         if (ret == (size_t)-1) {
516                 /* Bad conversion. */
517                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
518         }
519
520         ret = pull_string_talloc(finfo,
521                                 dir_data,
522                                 FLAGS2_UNICODE_STRINGS,
523                                 &finfo->name,
524                                 dir_data + 104,
525                                 namelen,
526                                 STR_UNICODE);
527         if (ret == (size_t)-1) {
528                 /* Bad conversion. */
529                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
530         }
531         return NT_STATUS_OK;
532 }
533
534 static void cli_smb2_listdir_done(struct tevent_req *subreq)
535 {
536         struct tevent_req *req = tevent_req_callback_data(
537                 subreq, struct tevent_req);
538         struct cli_smb2_listdir_state *state = tevent_req_data(
539                 req, struct cli_smb2_listdir_state);
540         uint8_t *data;
541         uint32_t data_len;
542         uint32_t next_offset = 0;
543         NTSTATUS status;
544
545         status = smb2cli_query_directory_recv(subreq, state, &data,
546                                               &data_len);
547         TALLOC_FREE(subreq);
548         if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
549                 tevent_req_done(req);
550                 return;
551         }
552         if (tevent_req_nterror(req, status)) {
553                 return;
554         }
555
556         do {
557                 struct file_info *finfo;
558                 bool ok;
559
560                 finfo = talloc_zero(state, struct file_info);
561                 if (tevent_req_nomem(finfo, req)) {
562                         return;
563                 }
564
565                 status = parse_finfo_id_both_directory_info(
566                         data, data_len, finfo, &next_offset);
567
568                 DEBUG(10, ("%s: parse_finfo_id_both_directory_info returned "
569                            "%s\n", __func__, nt_errstr(status)));
570
571                 if (tevent_req_nterror(req, status)) {
572                         return;
573                 }
574
575                 ok = dir_check_ftype(finfo->mode, state->attribute);
576
577                 DEBUG(10, ("%s: dir_check_ftype(%u,%u) returned %u\n",
578                            __func__, (unsigned)finfo->mode,
579                            (unsigned)state->attribute, (unsigned)ok));
580
581                 if (ok) {
582                         /*
583                          * Only process if attributes match. On SMB1 server
584                          * does this, so on SMB2 we need to emulate in the
585                          * client.
586                          *
587                          * https://bugzilla.samba.org/show_bug.cgi?id=10260
588                          */
589                         state->processed_file = true;
590
591                         status = state->fn(state->mntpoint, finfo,
592                                            state->pathname,
593                                            state->private_data);
594                         if (tevent_req_nterror(req, status)) {
595                                 return;
596                         }
597                 }
598
599                 TALLOC_FREE(finfo);
600
601                 if (next_offset != 0) {
602                         data += next_offset;
603                         data_len -= next_offset;
604                 }
605         } while (next_offset != 0);
606
607         subreq = smb2cli_query_directory_send(
608                 state, state->ev, state->conn, state->timeout_msec,
609                 state->session, state->tcon, state->level,
610                 state->flags, state->file_index,
611                 state->fid_persistent, state->fid_volatile,
612                 state->mask, state->outbuf_len);
613         if (tevent_req_nomem(subreq, req)) {
614                 return;
615         }
616         tevent_req_set_callback(subreq, cli_smb2_listdir_done, req);
617 }
618
619 static NTSTATUS cli_smb2_listdir_recv(struct tevent_req *req)
620 {
621         struct cli_smb2_listdir_state *state = tevent_req_data(
622                 req, struct cli_smb2_listdir_state);
623         NTSTATUS status;
624
625         if (tevent_req_is_nterror(req, &status)) {
626                 return status;
627         }
628
629         if (!state->processed_file) {
630                 /*
631                  * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
632                  * if no files match. Emulate this in the client.
633                  */
634                 return NT_STATUS_NO_SUCH_FILE;
635         }
636
637         return NT_STATUS_OK;
638 }
639
640 struct ll_lookup_state {
641         struct mount_state *mstate;
642         fuse_req_t freq;
643         char *path;
644 };
645
646 static void cli_ll_lookup_done(struct tevent_req *req);
647
648 static void cli_ll_lookup(fuse_req_t freq, fuse_ino_t parent_ino,
649                           const char *name)
650 {
651         struct mount_state *mstate = talloc_get_type_abort(
652                 fuse_req_userdata(freq), struct mount_state);
653         struct ll_lookup_state *state;
654         struct tevent_req *req;
655         struct inode_state *parent;
656
657         DBG_DEBUG("parent_ino=%ju, name=%s\n", (uintmax_t)parent_ino, name);
658
659         parent = idr_find(mstate->ino_ctx, parent_ino);
660         if (parent == NULL) {
661                 DBG_WARNING("could not find parent\n");
662                 fuse_reply_err(freq, ENOENT);
663                 return;
664         }
665
666         state = talloc(mstate, struct ll_lookup_state);
667         if (state == NULL) {
668                 DBG_WARNING("talloc failed\n");
669                 fuse_reply_err(freq, ENOMEM);
670                 return;
671         }
672         state->mstate = mstate;
673         state->freq = freq;
674
675         state->path = talloc_asprintf(state, "%s%s%s", parent->path,
676                                       strlen(parent->path) ? "\\": "",
677                                       name);
678         if (state->path == NULL) {
679                 TALLOC_FREE(state);
680                 fuse_reply_err(freq, ENOMEM);
681                 return;
682         }
683
684         req = cli_get_unixattr_send(state, mstate->ev, mstate->cli,
685                                     state->path);
686         if (req == NULL) {
687                 TALLOC_FREE(state);
688                 fuse_reply_err(freq, ENOMEM);
689                 return;
690         }
691         tevent_req_set_callback(req, cli_ll_lookup_done, state);
692 }
693
694 static void cli_ll_lookup_done(struct tevent_req *req)
695 {
696         struct ll_lookup_state *state = tevent_req_callback_data(
697                 req, struct ll_lookup_state);
698         struct stat sbuf = {0};
699         struct fuse_entry_param e;
700         struct inode_state *ino;
701         NTSTATUS status;
702
703         status = cli_get_unixattr_recv(req, &sbuf);
704         TALLOC_FREE(req);
705         if (!NT_STATUS_IS_OK(status)) {
706                 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
707                 return;
708         }
709
710         ino = inode_state_new(state->mstate, state->path);
711         if (ino == NULL) {
712                 fuse_reply_err(state->freq, ENOMEM);
713                 return;
714         }
715
716         e = (struct fuse_entry_param) {
717                 .ino = ino->ino,
718                 .attr = sbuf,
719                 .generation = 1, /* FIXME */
720                 .attr_timeout = 1.0,
721                 .entry_timeout = 1.0
722         };
723
724         fuse_reply_entry(state->freq, &e);
725         TALLOC_FREE(state);
726 }
727
728 struct ll_getattr_state {
729         struct mount_state *mstate;
730         fuse_req_t freq;
731         struct fuse_file_info fi;
732 };
733
734 static void cli_ll_getattr_done(struct tevent_req *req);
735
736 static void cli_ll_getattr(fuse_req_t freq, fuse_ino_t ino,
737                            struct fuse_file_info *fi)
738 {
739         struct mount_state *mstate = talloc_get_type_abort(
740                 fuse_req_userdata(freq), struct mount_state);
741         struct ll_getattr_state *state;
742         struct inode_state *istate;
743         struct tevent_req *req;
744
745         DBG_DEBUG("ino=%ju\n", (uintmax_t)ino);
746
747         istate = idr_find(mstate->ino_ctx, ino);
748         if (istate == NULL) {
749                 fuse_reply_err(freq, ENOENT);
750                 return;
751         }
752
753         state = talloc(mstate, struct ll_getattr_state);
754         if (state == NULL) {
755                 fuse_reply_err(freq, ENOMEM);
756                 return;
757         }
758         state->mstate = mstate;
759         state->freq = freq;
760
761         req = cli_get_unixattr_send(state, mstate->ev, mstate->cli,
762                                     istate->path);
763         if (req == NULL) {
764                 TALLOC_FREE(state);
765                 fuse_reply_err(freq, ENOMEM);
766                 return;
767         }
768         tevent_req_set_callback(req, cli_ll_getattr_done, state);
769 }
770
771 static void cli_ll_getattr_done(struct tevent_req *req)
772 {
773         struct ll_getattr_state *state = tevent_req_callback_data(
774                 req, struct ll_getattr_state);
775         struct stat st;
776         NTSTATUS status;
777         int ret;
778
779         status = cli_get_unixattr_recv(req, &st);
780         TALLOC_FREE(req);
781         if (!NT_STATUS_IS_OK(status)) {
782                 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
783                 return;
784         }
785
786         ret = fuse_reply_attr(state->freq, &st, 1);
787         if (ret != 0) {
788                 DBG_NOTICE("fuse_reply_attr failed: %s\n",
789                            strerror(-errno));
790         }
791 }
792
793
794 struct ll_open_state {
795         struct mount_state *mstate;
796         fuse_req_t freq;
797         struct fuse_file_info fi;
798 };
799
800 static void cli_ll_open_done(struct tevent_req *req);
801
802 static void cli_ll_open(fuse_req_t freq, fuse_ino_t ino,
803                         struct fuse_file_info *fi)
804 {
805         struct mount_state *mstate = talloc_get_type_abort(
806                 fuse_req_userdata(freq), struct mount_state);
807         struct ll_open_state *state;
808         struct inode_state *istate;
809         struct tevent_req *req;
810         uint32_t acc;
811
812         DBG_DEBUG("ino=%ju\n", (uintmax_t)ino);
813
814         istate = idr_find(mstate->ino_ctx, ino);
815         if (istate == NULL) {
816                 fuse_reply_err(freq, ENOENT);
817                 return;
818         }
819
820         state = talloc(mstate, struct ll_open_state);
821         if (state == NULL) {
822                 fuse_reply_err(freq, ENOMEM);
823                 return;
824         }
825         state->mstate = mstate;
826         state->freq = freq;
827         state->fi = *fi;
828
829         switch (fi->flags & O_ACCMODE) {
830         case O_RDONLY:
831                 acc = FILE_GENERIC_READ;
832                 break;
833         case O_WRONLY:
834                 acc = FILE_GENERIC_WRITE;
835                 break;
836         case O_RDWR:
837                 acc = FILE_GENERIC_READ|FILE_GENERIC_WRITE;
838                 break;
839         default:
840                 fuse_reply_err(freq, EACCES);
841                 return;
842         }
843
844         req = cli_smb2_create_fnum_send(
845                 state,
846                 mstate->ev,
847                 mstate->cli,
848                 istate->path,
849                 0,
850                 SMB2_IMPERSONATION_IMPERSONATION,
851                 acc,
852                 FILE_ATTRIBUTE_NORMAL,
853                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
854                 FILE_OPEN,
855                 FILE_NON_DIRECTORY_FILE,
856                 NULL);
857         if (req == NULL) {
858                 TALLOC_FREE(state);
859                 fuse_reply_err(freq, ENOMEM);
860                 return;
861         }
862         tevent_req_set_callback(req, cli_ll_open_done, state);
863 }
864
865 static void cli_ll_open_done(struct tevent_req *req)
866 {
867         struct ll_open_state *state = tevent_req_callback_data(
868                 req, struct ll_open_state);
869         uint16_t fnum;
870         NTSTATUS status;
871
872         status = cli_smb2_create_fnum_recv(req, &fnum, NULL, NULL, NULL);
873         TALLOC_FREE(req);
874         if (!NT_STATUS_IS_OK(status)) {
875                 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
876                 return;
877         }
878
879         state->fi.fh = fnum;
880         state->fi.direct_io = 0;
881         state->fi.keep_cache = 0;
882
883         fuse_reply_open(state->freq, &state->fi);
884
885         TALLOC_FREE(state);
886 }
887
888 struct ll_release_state {
889         struct mount_state *mstate;
890         fuse_req_t freq;
891         fuse_ino_t ino;
892 };
893
894 static void cli_ll_release_done(struct tevent_req *req);
895
896 static void cli_ll_release(fuse_req_t freq, fuse_ino_t ino,
897                            struct fuse_file_info *fi)
898 {
899         struct mount_state *mstate = talloc_get_type_abort(
900                 fuse_req_userdata(freq), struct mount_state);
901         struct ll_release_state *state;
902         struct inode_state *istate;
903         struct tevent_req *req;
904         uint16_t fnum;
905
906         DBG_DEBUG("ino=%ju\n", (uintmax_t)ino);
907
908         istate = idr_find(mstate->ino_ctx, ino);
909         if (istate == NULL) {
910                 fuse_reply_err(freq, ENOENT);
911                 return;
912         }
913
914         state = talloc(mstate, struct ll_release_state);
915         if (state == NULL) {
916                 fuse_reply_err(freq, ENOMEM);
917                 return;
918         }
919         state->mstate = mstate;
920         state->freq = freq;
921         state->ino = ino;
922
923         fnum = fi->fh;
924
925         req = cli_smb2_close_fnum_send(state, mstate->ev, mstate->cli, fnum);
926         if (req == NULL) {
927                 TALLOC_FREE(state);
928                 fuse_reply_err(freq, ENOMEM);
929                 return;
930         }
931         tevent_req_set_callback(req, cli_ll_release_done, state);
932 }
933
934 static void cli_ll_release_done(struct tevent_req *req)
935 {
936         struct ll_release_state *state = tevent_req_callback_data(
937                 req, struct ll_release_state);
938         struct inode_state *istate;
939         NTSTATUS status;
940
941         status = cli_smb2_close_fnum_recv(req);
942         TALLOC_FREE(req);
943         if (!NT_STATUS_IS_OK(status)) {
944                 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
945                 return;
946         }
947
948         istate = idr_find(state->mstate->ino_ctx, state->ino);
949         if (istate == NULL) {
950                 DEBUG(1, ("%s: inode %ju vanished!\n", __func__,
951                           (uintmax_t)state->ino));
952         }
953         TALLOC_FREE(istate);
954
955         fuse_reply_err(state->freq, 0);
956         TALLOC_FREE(state);
957 }
958
959 struct ll_read_state {
960         struct mount_state *mstate;
961         fuse_req_t freq;
962 };
963
964 static void cli_ll_read_done(struct tevent_req *req);
965
966 static void cli_ll_read(fuse_req_t freq, fuse_ino_t ino,
967                         size_t size, off_t off,
968                         struct fuse_file_info *fi)
969 {
970         struct mount_state *mstate = talloc_get_type_abort(
971                 fuse_req_userdata(freq), struct mount_state);
972         struct ll_read_state *state;
973         struct tevent_req *req;
974         uint16_t fnum;
975
976         DBG_DEBUG("ino=%ju, size=%zu, off=%ju\n", (uintmax_t)ino,
977                   size, (uintmax_t)off);
978
979         state = talloc(mstate, struct ll_read_state);
980         if (state == NULL) {
981                 fuse_reply_err(freq, ENOMEM);
982                 return;
983         }
984         state->mstate = mstate;
985         state->freq = freq;
986
987         fnum = fi->fh;
988
989         req = cli_smb2_read_send(state, mstate->ev, mstate->cli,
990                                  fnum, off, size);
991         if (req == NULL) {
992                 TALLOC_FREE(state);
993                 fuse_reply_err(freq, ENOMEM);
994                 return;
995         }
996         tevent_req_set_callback(req, cli_ll_read_done, state);
997 }
998
999 static void cli_ll_read_done(struct tevent_req *req)
1000 {
1001         struct ll_read_state *state = tevent_req_callback_data(
1002                 req, struct ll_read_state);
1003         ssize_t received;
1004         uint8_t *rcvbuf;
1005         NTSTATUS status;
1006
1007         status = cli_smb2_read_recv(req, &received, &rcvbuf);
1008         /* no talloc_free here yet */
1009
1010         if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
1011                 received = 0;
1012                 rcvbuf = NULL;
1013                 status = NT_STATUS_OK;
1014         }
1015
1016         if (!NT_STATUS_IS_OK(status)) {
1017                 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
1018                 return;
1019         }
1020         fuse_reply_buf(state->freq, (char *)rcvbuf, received);
1021         TALLOC_FREE(state);
1022 }
1023
1024 struct ll_write_state {
1025         struct mount_state *mstate;
1026         fuse_req_t freq;
1027 };
1028
1029 static void cli_ll_write_done(struct tevent_req *req);
1030
1031 static void cli_ll_write(fuse_req_t freq, fuse_ino_t ino, const char *buf,
1032                          size_t size, off_t off, struct fuse_file_info *fi)
1033 {
1034         struct mount_state *mstate = talloc_get_type_abort(
1035                 fuse_req_userdata(freq), struct mount_state);
1036         struct ll_write_state *state;
1037         struct tevent_req *req;
1038         uint16_t fnum;
1039
1040         DBG_DEBUG("ino=%ju, size=%zu, off=%ju\n", (uintmax_t)ino,
1041                   size, (uintmax_t)off);
1042
1043         state = talloc(mstate, struct ll_write_state);
1044         if (state == NULL) {
1045                 fuse_reply_err(freq, ENOMEM);
1046                 return;
1047         }
1048         state->mstate = mstate;
1049         state->freq = freq;
1050
1051         fnum = fi->fh;
1052
1053         req = cli_smb2_write_send(state, mstate->ev, mstate->cli, fnum, 0,
1054                                   (const uint8_t *)buf, off, size);
1055         if (req == NULL) {
1056                 TALLOC_FREE(state);
1057                 fuse_reply_err(freq, ENOMEM);
1058                 return;
1059         }
1060         tevent_req_set_callback(req, cli_ll_write_done, state);
1061 }
1062
1063 static void cli_ll_write_done(struct tevent_req *req)
1064 {
1065         struct ll_write_state *state = tevent_req_callback_data(
1066                 req, struct ll_write_state);
1067         size_t written;
1068         NTSTATUS status;
1069
1070         status = cli_smb2_write_recv(req, &written);
1071         /* no talloc_free here yet */
1072         if (!NT_STATUS_IS_OK(status)) {
1073                 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
1074                 return;
1075         }
1076         fuse_reply_write(state->freq, written);
1077         TALLOC_FREE(state);
1078 }
1079
1080
1081 struct ll_dir_state {
1082         uint64_t fid_persistent;
1083         uint64_t fid_volatile;
1084
1085         struct file_info *finfos;
1086         unsigned num_finfos, num_sent;
1087 };
1088
1089 static bool ll_dir_state_add(struct ll_dir_state *dir_state,
1090                              const char *name)
1091 {
1092         struct file_info *tmp, *finfo;
1093
1094         tmp = talloc_realloc(dir_state, dir_state->finfos,
1095                              struct file_info, dir_state->num_finfos+1);
1096         if (tmp == NULL) {
1097                 return false;
1098         }
1099         dir_state->finfos = tmp;
1100         finfo = &dir_state->finfos[dir_state->num_finfos];
1101
1102         ZERO_STRUCTP(finfo);
1103
1104         finfo->name = talloc_strdup(dir_state->finfos, name);
1105         if (finfo->name == NULL) {
1106                 return false;
1107         }
1108         dir_state->num_finfos += 1;
1109
1110         return true;
1111 }
1112
1113 struct ll_opendir_state {
1114         struct mount_state *mstate;
1115         fuse_req_t freq;
1116         struct fuse_file_info fi;
1117         struct ll_dir_state *dir_state;
1118 };
1119
1120 static void cli_ll_opendir_done(struct tevent_req *req);
1121
1122 static void cli_ll_opendir(fuse_req_t freq, fuse_ino_t ino,
1123                            struct fuse_file_info *fi)
1124 {
1125         struct mount_state *mstate = talloc_get_type_abort(
1126                 fuse_req_userdata(freq), struct mount_state);
1127         struct cli_state *cli = mstate->cli;
1128         struct ll_opendir_state *state;
1129         struct inode_state *istate;
1130         struct tevent_req *req;
1131
1132         DBG_DEBUG("ino=%ju\n", (uintmax_t)ino);
1133
1134         istate = idr_find(mstate->ino_ctx, ino);
1135         if (istate == NULL) {
1136                 fuse_reply_err(freq, ENOENT);
1137                 return;
1138         }
1139
1140         state = talloc(mstate, struct ll_opendir_state);
1141         if (state == NULL) {
1142                 fuse_reply_err(freq, ENOMEM);
1143                 return;
1144         }
1145         state->mstate = mstate;
1146         state->freq = freq;
1147         state->fi = *fi;
1148
1149         state->dir_state = talloc_zero(state, struct ll_dir_state);
1150         if (state->dir_state == NULL) {
1151                 TALLOC_FREE(state);
1152                 fuse_reply_err(freq, ENOMEM);
1153                 return;
1154         }
1155
1156         req = smb2cli_create_send(
1157                 state, mstate->ev, cli->conn, cli->timeout,
1158                 cli->smb2.session, cli->smb2.tcon, istate->path,
1159                 0, SMB2_IMPERSONATION_IMPERSONATION,
1160                 FILE_GENERIC_READ, FILE_ATTRIBUTE_DIRECTORY,
1161                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1162                 FILE_OPEN, FILE_DIRECTORY_FILE, NULL);
1163         if (req == NULL) {
1164                 TALLOC_FREE(state);
1165                 fuse_reply_err(freq, ENOMEM);
1166                 return;
1167         }
1168         tevent_req_set_callback(req, cli_ll_opendir_done, state);
1169 }
1170
1171 static void cli_ll_opendir_done(struct tevent_req *req)
1172 {
1173         struct ll_opendir_state *state = tevent_req_callback_data(
1174                 req, struct ll_opendir_state);
1175         NTSTATUS status;
1176
1177         status = smb2cli_create_recv(req,
1178                                      &state->dir_state->fid_persistent,
1179                                      &state->dir_state->fid_volatile,
1180                                      NULL, NULL, NULL);
1181         TALLOC_FREE(req);
1182
1183         DEBUG(10, ("%s: smbcli_create_recv returned %s\n", __func__,
1184                    nt_errstr(status)));
1185
1186         if (!NT_STATUS_IS_OK(status)) {
1187                 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
1188                 return;
1189         }
1190
1191         state->fi.fh = (uint64_t)talloc_move(state->mstate, &state->dir_state);
1192         state->fi.direct_io = 0;
1193         state->fi.keep_cache = 0;
1194
1195         fuse_reply_open(state->freq, &state->fi);
1196
1197         TALLOC_FREE(state);
1198 }
1199
1200 struct ll_readdir_state {
1201         fuse_req_t freq;
1202         struct ll_dir_state *dir_state;
1203 };
1204
1205 static void cli_ll_readdir_done(struct tevent_req *subreq);
1206 static NTSTATUS cli_ll_readdir_one(const char *mnt, struct file_info *finfo,
1207                                    const char *path, void *private_data);
1208 static void cli_ll_readdir_reply_one(fuse_req_t freq,
1209                                      struct ll_dir_state *dir_state);
1210
1211 static void cli_ll_readdir(fuse_req_t freq, fuse_ino_t ino, size_t size,
1212                            off_t off, struct fuse_file_info *fi)
1213 {
1214         struct mount_state *mstate = talloc_get_type_abort(
1215                 fuse_req_userdata(freq), struct mount_state);
1216         struct cli_state *cli = mstate->cli;
1217         struct ll_dir_state *dir_state;
1218         struct ll_readdir_state *state;
1219         struct tevent_req *req;
1220
1221         DBG_DEBUG("ino=%ju, size=%zu, off=%ju\n", (uintmax_t)ino, size,
1222                   (uintmax_t)off);
1223
1224         dir_state = talloc_get_type_abort((void *)fi->fh, struct ll_dir_state);
1225
1226         if (dir_state->finfos != NULL) {
1227                 DBG_DEBUG("finfos=%p\n", dir_state->finfos);
1228                 cli_ll_readdir_reply_one(freq, dir_state);
1229                 return;
1230         }
1231
1232         if (!ll_dir_state_add(dir_state, ".") ||
1233             !ll_dir_state_add(dir_state, "..")) {
1234                 fuse_reply_err(freq, ENOMEM);
1235                 return;
1236         }
1237
1238         state = talloc(mstate, struct ll_readdir_state);
1239         if (state == NULL) {
1240                 fuse_reply_err(freq, ENOMEM);
1241                 return;
1242         }
1243         state->freq = freq;
1244         state->dir_state = dir_state;
1245
1246         req = cli_smb2_listdir_send(
1247                 state, mstate->ev, cli->conn, cli->timeout,
1248                 cli->smb2.session, cli->smb2.tcon,
1249                 SMB2_FIND_ID_BOTH_DIRECTORY_INFO, 0, 0,
1250                 dir_state->fid_persistent, dir_state->fid_volatile,
1251                 "*", 0xffff,
1252                 FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM |
1253                 FILE_ATTRIBUTE_HIDDEN,
1254                 NULL, NULL, cli_ll_readdir_one, dir_state);
1255         if (req == NULL) {
1256                 TALLOC_FREE(state);
1257                 fuse_reply_err(freq, ENOMEM);
1258                 return;
1259         }
1260         tevent_req_set_callback(req, cli_ll_readdir_done, state);
1261 }
1262
1263 static void cli_ll_readdir_reply_one(fuse_req_t freq,
1264                                      struct ll_dir_state *dir_state)
1265 {
1266         struct file_info *finfo;
1267         char buf[1024];
1268         struct stat sbuf = {};
1269         size_t buflen;
1270
1271         if (dir_state->num_finfos == dir_state->num_sent) {
1272                 DEBUG(10, ("%s: Done\n", __func__));
1273                 fuse_reply_buf(freq, NULL, 0);
1274                 return;
1275         }
1276
1277         sbuf.st_mode = S_IFREG | 0755;
1278         sbuf.st_ino = random(); /* FIXME :-) */
1279         finfo = &dir_state->finfos[dir_state->num_sent];
1280
1281         DBG_DEBUG("Adding %s\n", finfo->name);
1282
1283         buflen = fuse_add_direntry(freq, buf, sizeof(buf),
1284                                    finfo->name, &sbuf, 0);
1285         fuse_reply_buf(freq, buf, buflen);
1286         dir_state->num_sent += 1;
1287         return;
1288 }
1289
1290 static NTSTATUS cli_ll_readdir_one(const char *mnt, struct file_info *finfo,
1291                                    const char *path, void *private_data)
1292 {
1293         struct ll_dir_state *dir_state = talloc_get_type_abort(
1294                 private_data, struct ll_dir_state);
1295
1296         if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
1297                 DEBUG(10, ("%s: Ignoring %s\n", __func__, finfo->name));
1298                 return NT_STATUS_OK;
1299         }
1300
1301         DBG_DEBUG("Got entry %s\n", finfo->name);
1302
1303         if (!ll_dir_state_add(dir_state, finfo->name)) {
1304                 return NT_STATUS_NO_MEMORY;
1305         }
1306         return NT_STATUS_OK;
1307 }
1308
1309 static void cli_ll_readdir_done(struct tevent_req *req)
1310 {
1311         struct ll_readdir_state *state = tevent_req_callback_data(
1312                 req, struct ll_readdir_state);
1313         NTSTATUS status;
1314
1315         status = cli_smb2_listdir_recv(req);
1316         TALLOC_FREE(req);
1317         if (!NT_STATUS_IS_OK(status)) {
1318                 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
1319                 return;
1320         }
1321         cli_ll_readdir_reply_one(state->freq, state->dir_state);
1322         TALLOC_FREE(state);
1323 }
1324
1325
1326 struct ll_releasedir_state {
1327         struct mount_state *mstate;
1328         fuse_req_t freq;
1329         struct ll_dir_state *dir_state;
1330 };
1331
1332 static void cli_ll_releasedir_done(struct tevent_req *req);
1333
1334 static void cli_ll_releasedir(fuse_req_t freq, fuse_ino_t ino,
1335                               struct fuse_file_info *fi)
1336 {
1337         struct mount_state *mstate = talloc_get_type_abort(
1338                 fuse_req_userdata(freq), struct mount_state);
1339         struct cli_state *cli = mstate->cli;
1340         struct ll_releasedir_state *state;
1341         struct tevent_req *req;
1342
1343         DBG_DEBUG("ino=%ju\n", (uintmax_t)ino);
1344
1345         state = talloc(mstate, struct ll_releasedir_state);
1346         if (state == NULL) {
1347                 fuse_reply_err(freq, ENOMEM);
1348                 return;
1349         }
1350         state->mstate = mstate;
1351         state->freq = freq;
1352
1353         state->dir_state = talloc_get_type_abort(
1354                 (void *)fi->fh, struct ll_dir_state);
1355
1356         req = smb2cli_close_send(state, mstate->ev, cli->conn, cli->timeout,
1357                                  cli->smb2.session, cli->smb2.tcon, 0,
1358                                  state->dir_state->fid_persistent,
1359                                  state->dir_state->fid_volatile);
1360         if (req == NULL) {
1361                 TALLOC_FREE(state);
1362                 fuse_reply_err(freq, ENOMEM);
1363                 return;
1364         }
1365         tevent_req_set_callback(req, cli_ll_releasedir_done, state);
1366 }
1367
1368 static void cli_ll_releasedir_done(struct tevent_req *req)
1369 {
1370         struct ll_releasedir_state *state = tevent_req_callback_data(
1371                 req, struct ll_releasedir_state);
1372         NTSTATUS status;
1373
1374         status = smb2cli_close_recv(req);
1375         TALLOC_FREE(req);
1376         if (!NT_STATUS_IS_OK(status)) {
1377                 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
1378                 return;
1379         }
1380         TALLOC_FREE(state->dir_state);
1381         fuse_reply_err(state->freq, 0);
1382         TALLOC_FREE(state);
1383 }
1384
1385 static struct fuse_lowlevel_ops cli_ll_ops = {
1386         .lookup = cli_ll_lookup,
1387         .getattr = cli_ll_getattr,
1388         .open = cli_ll_open,
1389         .create = cli_ll_create,
1390         .release = cli_ll_release,
1391         .read = cli_ll_read,
1392         .write = cli_ll_write,
1393         .opendir = cli_ll_opendir,
1394         .readdir = cli_ll_readdir,
1395         .releasedir = cli_ll_releasedir,
1396 };
1397
1398 static void fuse_chan_fd_handler(struct tevent_context *ev,
1399                                  struct tevent_fd *fde,
1400                                  uint16_t flags,
1401                                  void *private_data);
1402 static void fuse_chan_signal_handler(struct tevent_context *ev,
1403                                      struct tevent_signal *se,
1404                                      int signum,
1405                                      int count,
1406                                      void *siginfo,
1407                                      void *private_data);
1408
1409 static int mount_state_destructor(struct mount_state *s);
1410
1411 int do_mount(struct cli_state *cli, const char *mountpoint)
1412 {
1413         struct mount_state *state;
1414         struct inode_state *ino;
1415         struct fuse_args args = { 0 };
1416         int fd;
1417         int ret = 1;
1418
1419         state = talloc_zero(talloc_tos(), struct mount_state);
1420         if (state == NULL) {
1421                 fprintf(stderr, "talloc failed\n");
1422                 return 1;
1423         }
1424
1425         state->ev = tevent_context_init(state);
1426         if (state->ev == NULL) {
1427                 fprintf(stderr, "tevent_context_init failed\n");
1428                 TALLOC_FREE(state);
1429                 return 1;
1430         }
1431
1432         state->ino_ctx = idr_init(state);
1433         if (state->ino_ctx == NULL) {
1434                 fprintf(stderr, "idr_init failed\n");
1435                 TALLOC_FREE(state);
1436                 return 1;
1437         }
1438
1439         state->ino_parent = talloc_new(state);
1440         if (state->ino_parent == NULL) {
1441                 fprintf(stderr, "talloc_new failed\n");
1442                 TALLOC_FREE(state);
1443                 return 1;
1444         }
1445
1446         talloc_set_destructor(state, mount_state_destructor);
1447
1448         ino = inode_state_new(state, "");
1449         if (ino == NULL) {
1450                 fprintf(stderr, "inode_state_new failed\n");
1451                 TALLOC_FREE(state);
1452                 return 1;
1453         }
1454         if (ino->ino != FUSE_ROOT_ID) {
1455                 fprintf(stderr, "first inode gave %d, expected %d\n",
1456                         (int)ino->ino, FUSE_ROOT_ID);
1457                 TALLOC_FREE(state);
1458                 return 1;
1459         }
1460
1461         state->cli = cli;
1462
1463         state->ch = fuse_mount(mountpoint, &args);
1464         if (state->ch == NULL) {
1465                 perror("fuse_mount failed");
1466                 goto fail_free;
1467         }
1468
1469         state->bufsize = fuse_chan_bufsize(state->ch);
1470         state->buf = talloc_array(state, char, state->bufsize);
1471         if (state->buf == NULL) {
1472                 fprintf(stderr, "talloc failed\n");
1473                 goto fail_unmount;
1474         }
1475
1476         fd = fuse_chan_fd(state->ch);
1477
1478         state->fde = tevent_add_fd(state->ev, state, fd, TEVENT_FD_READ,
1479                                    fuse_chan_fd_handler, state);
1480         if (state->fde == NULL) {
1481                 fprintf(stderr, "tevent_add_fd failed\n");
1482                 goto fail_unmount;
1483         }
1484
1485         state->signal_ev = tevent_add_signal(state->ev, state, SIGINT, 0,
1486                                              fuse_chan_signal_handler, state);
1487         if (state->signal_ev == NULL) {
1488                 fprintf(stderr, "tevent_add_signal failed\n");
1489                 goto fail_unmount;
1490         }
1491
1492         state->se = fuse_lowlevel_new(&args, &cli_ll_ops, sizeof(cli_ll_ops),
1493                                       state);
1494         if (state->se == NULL) {
1495                 perror("fuse_lowlevel_new failed");
1496                 goto fail_unmount;
1497         }
1498
1499         fuse_session_add_chan(state->se, state->ch);
1500
1501         while (!state->done) {
1502                 ret = tevent_loop_once(state->ev);
1503                 if (ret == -1) {
1504                         perror("tevent_loop_once failed");
1505                         break;
1506                 }
1507         }
1508
1509         fuse_session_remove_chan(state->ch);
1510         fuse_session_destroy(state->se);
1511 fail_unmount:
1512         fuse_unmount(mountpoint, state->ch);
1513 fail_free:
1514         TALLOC_FREE(state);
1515         return ret;
1516 }
1517
1518 static int mount_state_destructor(struct mount_state *s)
1519 {
1520         TALLOC_FREE(s->ino_parent);
1521         return 0;
1522 }
1523
1524
1525 static void fuse_chan_fd_handler(struct tevent_context *ev,
1526                                  struct tevent_fd *fde,
1527                                  uint16_t flags,
1528                                  void *private_data)
1529 {
1530         struct mount_state *state = talloc_get_type_abort(
1531                 private_data, struct mount_state);
1532         int recvd;
1533
1534         if ((flags & TEVENT_FD_READ) == 0) {
1535                 return;
1536         }
1537
1538         recvd = fuse_chan_recv(&state->ch, state->buf, state->bufsize);
1539         if (recvd <= 0) {
1540                 state->done = true;
1541                 return;
1542         }
1543         fuse_session_process(state->se, state->buf, recvd, state->ch);
1544 }
1545
1546 static void fuse_chan_signal_handler(struct tevent_context *ev,
1547                                      struct tevent_signal *se,
1548                                      int signum,
1549                                      int count,
1550                                      void *siginfo,
1551                                      void *private_data)
1552 {
1553         struct mount_state *state = talloc_get_type_abort(
1554                 private_data, struct mount_state);
1555         state->done = true;
1556 }