rpc_server: Avoid casts in DBG statements
[Samba.git] / examples / fuse / clifuse.c
blob954c412f09cddb0166b112b3590f8bd4e33f4ac5
1 /*
2 * Unix SMB/CIFS implementation.
3 * fusermount smb2 client
4 * Copyright (C) Volker Lendecke 2016
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.
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.
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/>.
20 #define FUSE_USE_VERSION 26
21 #define _FILE_OFFSET_BITS 64
22 #include "fuse/fuse_lowlevel.h"
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"
35 struct mount_state {
36 struct tevent_context *ev;
37 struct cli_state *cli;
38 bool done;
40 struct tevent_fd *fde;
41 struct tevent_signal *signal_ev;
43 struct fuse_chan *ch;
44 struct fuse_session *se;
46 size_t bufsize;
47 char *buf;
49 struct idr_context *ino_ctx;
50 TALLOC_CTX *ino_parent;
53 struct inode_state {
54 struct idr_context *ino_ctx;
55 fuse_ino_t ino;
56 char path[1];
59 static int inode_state_destructor(struct inode_state *s);
61 static struct inode_state *inode_state_init(TALLOC_CTX *mem_ctx,
62 struct idr_context *ino_ctx,
63 const char *path)
65 struct inode_state *state;
66 size_t pathlen;
67 int ino;
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;
75 talloc_set_name_const(state, "struct inode_state");
77 ino = idr_get_new_above(ino_ctx, state, 1, INT32_MAX);
78 if (ino == -1) {
79 TALLOC_FREE(state);
80 return NULL;
83 state->ino = ino;
84 state->ino_ctx = ino_ctx;
85 memcpy(state->path, path, pathlen + 1);
87 DBG_DEBUG("Creating ino %d for path %s\n", ino, path);
89 talloc_set_destructor(state, inode_state_destructor);
91 return state;
94 static struct inode_state *inode_state_new(struct mount_state *mstate,
95 const char *path)
97 return inode_state_init(mstate->ino_parent, mstate->ino_ctx, path);
100 static int inode_state_destructor(struct inode_state *s)
102 DBG_DEBUG("destroying inode %ju\n", (uintmax_t)s->ino);
103 idr_remove(s->ino_ctx, s->ino);
104 return 0;
107 struct ll_create_state {
108 struct mount_state *mstate;
109 fuse_req_t freq;
110 struct fuse_file_info fi;
111 char *path;
114 static void cli_ll_create_done(struct tevent_req *req);
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)
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;
125 DBG_DEBUG("parent=%ju, name=%s, mode=%x\n", (uintmax_t)parent,
126 name, (unsigned)mode);
128 istate = idr_find(mstate->ino_ctx, parent);
129 if (istate == NULL) {
130 fuse_reply_err(freq, ENOENT);
131 return;
134 state = talloc(mstate, struct ll_create_state);
135 if (state == NULL) {
136 fuse_reply_err(freq, ENOMEM);
137 return;
139 state->mstate = mstate;
140 state->freq = freq;
141 state->fi = *fi;
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;
152 req = cli_smb2_create_fnum_send(
153 state,
154 mstate->ev,
155 mstate->cli, state->path,
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;
169 tevent_req_set_callback(req, cli_ll_create_done, state);
172 static void cli_ll_create_done(struct tevent_req *req)
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;
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;
188 state->fi.fh = fnum;
189 state->fi.direct_io = 0;
190 state->fi.keep_cache = 0;
192 ino = inode_state_new(state->mstate, state->path);
193 if (ino == NULL) {
194 fuse_reply_err(state->freq, ENOMEM);
195 return;
198 e = (struct fuse_entry_param) {
199 .ino = ino->ino,
200 .generation = 1, /* FIXME */
201 .attr_timeout = 1.0,
202 .entry_timeout = 1.0
205 fuse_reply_create(state->freq, &e, &state->fi);
207 TALLOC_FREE(state);
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;
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;
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);
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)
235 struct tevent_req *req, *subreq;
236 struct cli_get_unixattr_state *state;
238 req = tevent_req_create(mem_ctx, &state,
239 struct cli_get_unixattr_state);
240 if (req == NULL) {
241 return NULL;
243 state->ev = ev;
244 state->cli = cli;
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);
256 tevent_req_set_callback(subreq, cli_get_unixattr_opened, req);
258 return req;
261 static void cli_get_unixattr_opened(struct tevent_req *subreq)
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;
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;
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;
293 tevent_req_set_callback(subreq, cli_get_unixattr_gotinfo, req);
296 static void cli_get_unixattr_gotinfo(struct tevent_req *subreq)
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;
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;
314 if (outbuf.length < 0x60) {
315 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
316 return;
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);
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;
334 tevent_req_set_callback(subreq, cli_get_unixattr_closed, req);
337 static void cli_get_unixattr_closed(struct tevent_req *subreq)
339 struct tevent_req *req = tevent_req_callback_data(
340 subreq, struct tevent_req);
341 NTSTATUS status;
343 status = smb2cli_close_recv(subreq);
344 TALLOC_FREE(subreq);
345 if (tevent_req_nterror(req, status)) {
346 return;
348 tevent_req_done(req);
351 static NTSTATUS cli_get_unixattr_recv(struct tevent_req *req,
352 struct stat *st)
354 struct cli_get_unixattr_state *state = tevent_req_data(
355 req, struct cli_get_unixattr_state);
356 NTSTATUS status;
358 if (tevent_req_is_nterror(req, &status)) {
359 return status;
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;
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);
378 return NT_STATUS_OK;
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;
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;
404 static void cli_smb2_listdir_done(struct tevent_req *subreq);
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)
427 struct tevent_req *req, *subreq;
428 struct cli_smb2_listdir_state *state;
430 req = tevent_req_create(mem_ctx, &state,
431 struct cli_smb2_listdir_state);
432 if (req == NULL) {
433 return NULL;
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;
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);
462 tevent_req_set_callback(subreq, cli_smb2_listdir_done, req);
463 return req;
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)
471 size_t namelen = 0;
472 size_t slen = 0;
473 size_t ret = 0;
475 if (dir_data_length < 4) {
476 return NT_STATUS_INFO_LENGTH_MISMATCH;
479 *next_offset = IVAL(dir_data, 0);
481 if (*next_offset > dir_data_length) {
482 return NT_STATUS_INFO_LENGTH_MISMATCH;
485 if (*next_offset != 0) {
486 /* Ensure we only read what in this record. */
487 dir_data_length = *next_offset;
490 if (dir_data_length < 105) {
491 return NT_STATUS_INFO_LENGTH_MISMATCH;
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 = CVAL(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;
504 slen = CVAL(dir_data + 68, 0);
505 if (slen > 24) {
506 return NT_STATUS_INFO_LENGTH_MISMATCH;
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;
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;
531 return NT_STATUS_OK;
534 static void cli_smb2_listdir_done(struct tevent_req *subreq)
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;
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;
552 if (tevent_req_nterror(req, status)) {
553 return;
556 do {
557 struct file_info *finfo;
558 bool ok;
560 finfo = talloc_zero(state, struct file_info);
561 if (tevent_req_nomem(finfo, req)) {
562 return;
565 status = parse_finfo_id_both_directory_info(
566 data, data_len, finfo, &next_offset);
568 DEBUG(10, ("%s: parse_finfo_id_both_directory_info returned "
569 "%s\n", __func__, nt_errstr(status)));
571 if (tevent_req_nterror(req, status)) {
572 return;
575 ok = dir_check_ftype(finfo->mode, state->attribute);
577 DEBUG(10, ("%s: dir_check_ftype(%u,%u) returned %u\n",
578 __func__, (unsigned)finfo->mode,
579 (unsigned)state->attribute, (unsigned)ok));
581 if (ok) {
583 * Only process if attributes match. On SMB1 server
584 * does this, so on SMB2 we need to emulate in the
585 * client.
587 * https://bugzilla.samba.org/show_bug.cgi?id=10260
589 state->processed_file = true;
591 status = state->fn(state->mntpoint, finfo,
592 state->pathname,
593 state->private_data);
594 if (tevent_req_nterror(req, status)) {
595 return;
599 TALLOC_FREE(finfo);
601 if (next_offset != 0) {
602 data += next_offset;
603 data_len -= next_offset;
605 } while (next_offset != 0);
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;
616 tevent_req_set_callback(subreq, cli_smb2_listdir_done, req);
619 static NTSTATUS cli_smb2_listdir_recv(struct tevent_req *req)
621 struct cli_smb2_listdir_state *state = tevent_req_data(
622 req, struct cli_smb2_listdir_state);
623 NTSTATUS status;
625 if (tevent_req_is_nterror(req, &status)) {
626 return status;
629 if (!state->processed_file) {
631 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
632 * if no files match. Emulate this in the client.
634 return NT_STATUS_NO_SUCH_FILE;
637 return NT_STATUS_OK;
640 struct ll_lookup_state {
641 struct mount_state *mstate;
642 fuse_req_t freq;
643 char *path;
646 static void cli_ll_lookup_done(struct tevent_req *req);
648 static void cli_ll_lookup(fuse_req_t freq, fuse_ino_t parent_ino,
649 const char *name)
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;
657 DBG_DEBUG("parent_ino=%ju, name=%s\n", (uintmax_t)parent_ino, name);
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;
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;
672 state->mstate = mstate;
673 state->freq = freq;
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;
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;
691 tevent_req_set_callback(req, cli_ll_lookup_done, state);
694 static void cli_ll_lookup_done(struct tevent_req *req)
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;
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;
710 ino = inode_state_new(state->mstate, state->path);
711 if (ino == NULL) {
712 fuse_reply_err(state->freq, ENOMEM);
713 return;
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
724 fuse_reply_entry(state->freq, &e);
725 TALLOC_FREE(state);
728 struct ll_getattr_state {
729 struct mount_state *mstate;
730 fuse_req_t freq;
731 struct fuse_file_info fi;
734 static void cli_ll_getattr_done(struct tevent_req *req);
736 static void cli_ll_getattr(fuse_req_t freq, fuse_ino_t ino,
737 struct fuse_file_info *fi)
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;
745 DBG_DEBUG("ino=%ju\n", (uintmax_t)ino);
747 istate = idr_find(mstate->ino_ctx, ino);
748 if (istate == NULL) {
749 fuse_reply_err(freq, ENOENT);
750 return;
753 state = talloc(mstate, struct ll_getattr_state);
754 if (state == NULL) {
755 fuse_reply_err(freq, ENOMEM);
756 return;
758 state->mstate = mstate;
759 state->freq = freq;
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;
768 tevent_req_set_callback(req, cli_ll_getattr_done, state);
771 static void cli_ll_getattr_done(struct tevent_req *req)
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;
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;
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));
794 struct ll_open_state {
795 struct mount_state *mstate;
796 fuse_req_t freq;
797 struct fuse_file_info fi;
800 static void cli_ll_open_done(struct tevent_req *req);
802 static void cli_ll_open(fuse_req_t freq, fuse_ino_t ino,
803 struct fuse_file_info *fi)
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;
812 DBG_DEBUG("ino=%ju\n", (uintmax_t)ino);
814 istate = idr_find(mstate->ino_ctx, ino);
815 if (istate == NULL) {
816 fuse_reply_err(freq, ENOENT);
817 return;
820 state = talloc(mstate, struct ll_open_state);
821 if (state == NULL) {
822 fuse_reply_err(freq, ENOMEM);
823 return;
825 state->mstate = mstate;
826 state->freq = freq;
827 state->fi = *fi;
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;
844 req = cli_smb2_create_fnum_send(
845 state,
846 mstate->ev,
847 mstate->cli,
848 istate->path,
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;
862 tevent_req_set_callback(req, cli_ll_open_done, state);
865 static void cli_ll_open_done(struct tevent_req *req)
867 struct ll_open_state *state = tevent_req_callback_data(
868 req, struct ll_open_state);
869 uint16_t fnum;
870 NTSTATUS status;
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;
879 state->fi.fh = fnum;
880 state->fi.direct_io = 0;
881 state->fi.keep_cache = 0;
883 fuse_reply_open(state->freq, &state->fi);
885 TALLOC_FREE(state);
888 struct ll_release_state {
889 struct mount_state *mstate;
890 fuse_req_t freq;
891 fuse_ino_t ino;
894 static void cli_ll_release_done(struct tevent_req *req);
896 static void cli_ll_release(fuse_req_t freq, fuse_ino_t ino,
897 struct fuse_file_info *fi)
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;
906 DBG_DEBUG("ino=%ju\n", (uintmax_t)ino);
908 istate = idr_find(mstate->ino_ctx, ino);
909 if (istate == NULL) {
910 fuse_reply_err(freq, ENOENT);
911 return;
914 state = talloc(mstate, struct ll_release_state);
915 if (state == NULL) {
916 fuse_reply_err(freq, ENOMEM);
917 return;
919 state->mstate = mstate;
920 state->freq = freq;
921 state->ino = ino;
923 fnum = fi->fh;
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;
931 tevent_req_set_callback(req, cli_ll_release_done, state);
934 static void cli_ll_release_done(struct tevent_req *req)
936 struct ll_release_state *state = tevent_req_callback_data(
937 req, struct ll_release_state);
938 struct inode_state *istate;
939 NTSTATUS status;
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;
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));
953 TALLOC_FREE(istate);
955 fuse_reply_err(state->freq, 0);
956 TALLOC_FREE(state);
959 struct ll_read_state {
960 struct mount_state *mstate;
961 fuse_req_t freq;
964 static void cli_ll_read_done(struct tevent_req *req);
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)
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;
976 DBG_DEBUG("ino=%ju, size=%zu, off=%ju\n", (uintmax_t)ino,
977 size, (uintmax_t)off);
979 state = talloc(mstate, struct ll_read_state);
980 if (state == NULL) {
981 fuse_reply_err(freq, ENOMEM);
982 return;
984 state->mstate = mstate;
985 state->freq = freq;
987 fnum = fi->fh;
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;
996 tevent_req_set_callback(req, cli_ll_read_done, state);
999 static void cli_ll_read_done(struct tevent_req *req)
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;
1007 status = cli_smb2_read_recv(req, &received, &rcvbuf);
1008 /* no talloc_free here yet */
1010 if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
1011 received = 0;
1012 rcvbuf = NULL;
1013 status = NT_STATUS_OK;
1016 if (!NT_STATUS_IS_OK(status)) {
1017 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
1018 return;
1020 fuse_reply_buf(state->freq, (char *)rcvbuf, received);
1021 TALLOC_FREE(state);
1024 struct ll_write_state {
1025 struct mount_state *mstate;
1026 fuse_req_t freq;
1029 static void cli_ll_write_done(struct tevent_req *req);
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)
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;
1040 DBG_DEBUG("ino=%ju, size=%zu, off=%ju\n", (uintmax_t)ino,
1041 size, (uintmax_t)off);
1043 state = talloc(mstate, struct ll_write_state);
1044 if (state == NULL) {
1045 fuse_reply_err(freq, ENOMEM);
1046 return;
1048 state->mstate = mstate;
1049 state->freq = freq;
1051 fnum = fi->fh;
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;
1060 tevent_req_set_callback(req, cli_ll_write_done, state);
1063 static void cli_ll_write_done(struct tevent_req *req)
1065 struct ll_write_state *state = tevent_req_callback_data(
1066 req, struct ll_write_state);
1067 size_t written;
1068 NTSTATUS status;
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;
1076 fuse_reply_write(state->freq, written);
1077 TALLOC_FREE(state);
1081 struct ll_dir_state {
1082 uint64_t fid_persistent;
1083 uint64_t fid_volatile;
1085 struct file_info *finfos;
1086 unsigned num_finfos, num_sent;
1089 static bool ll_dir_state_add(struct ll_dir_state *dir_state,
1090 const char *name)
1092 struct file_info *tmp, *finfo;
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;
1099 dir_state->finfos = tmp;
1100 finfo = &dir_state->finfos[dir_state->num_finfos];
1102 ZERO_STRUCTP(finfo);
1104 finfo->name = talloc_strdup(dir_state->finfos, name);
1105 if (finfo->name == NULL) {
1106 return false;
1108 dir_state->num_finfos += 1;
1110 return true;
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;
1120 static void cli_ll_opendir_done(struct tevent_req *req);
1122 static void cli_ll_opendir(fuse_req_t freq, fuse_ino_t ino,
1123 struct fuse_file_info *fi)
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;
1132 DBG_DEBUG("ino=%ju\n", (uintmax_t)ino);
1134 istate = idr_find(mstate->ino_ctx, ino);
1135 if (istate == NULL) {
1136 fuse_reply_err(freq, ENOENT);
1137 return;
1140 state = talloc(mstate, struct ll_opendir_state);
1141 if (state == NULL) {
1142 fuse_reply_err(freq, ENOMEM);
1143 return;
1145 state->mstate = mstate;
1146 state->freq = freq;
1147 state->fi = *fi;
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;
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;
1168 tevent_req_set_callback(req, cli_ll_opendir_done, state);
1171 static void cli_ll_opendir_done(struct tevent_req *req)
1173 struct ll_opendir_state *state = tevent_req_callback_data(
1174 req, struct ll_opendir_state);
1175 NTSTATUS status;
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);
1183 DEBUG(10, ("%s: smbcli_create_recv returned %s\n", __func__,
1184 nt_errstr(status)));
1186 if (!NT_STATUS_IS_OK(status)) {
1187 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
1188 return;
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;
1195 fuse_reply_open(state->freq, &state->fi);
1197 TALLOC_FREE(state);
1200 struct ll_readdir_state {
1201 fuse_req_t freq;
1202 struct ll_dir_state *dir_state;
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);
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)
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;
1221 DBG_DEBUG("ino=%ju, size=%zu, off=%ju\n", (uintmax_t)ino, size,
1222 (uintmax_t)off);
1224 dir_state = talloc_get_type_abort((void *)fi->fh, struct ll_dir_state);
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;
1232 if (!ll_dir_state_add(dir_state, ".") ||
1233 !ll_dir_state_add(dir_state, "..")) {
1234 fuse_reply_err(freq, ENOMEM);
1235 return;
1238 state = talloc(mstate, struct ll_readdir_state);
1239 if (state == NULL) {
1240 fuse_reply_err(freq, ENOMEM);
1241 return;
1243 state->freq = freq;
1244 state->dir_state = dir_state;
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;
1260 tevent_req_set_callback(req, cli_ll_readdir_done, state);
1263 static void cli_ll_readdir_reply_one(fuse_req_t freq,
1264 struct ll_dir_state *dir_state)
1266 struct file_info *finfo;
1267 char buf[1024];
1268 struct stat sbuf = {};
1269 size_t buflen;
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;
1277 sbuf.st_mode = S_IFREG | 0755;
1278 sbuf.st_ino = random(); /* FIXME :-) */
1279 finfo = &dir_state->finfos[dir_state->num_sent];
1281 DBG_DEBUG("Adding %s\n", finfo->name);
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;
1290 static NTSTATUS cli_ll_readdir_one(const char *mnt, struct file_info *finfo,
1291 const char *path, void *private_data)
1293 struct ll_dir_state *dir_state = talloc_get_type_abort(
1294 private_data, struct ll_dir_state);
1296 if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
1297 DEBUG(10, ("%s: Ignoring %s\n", __func__, finfo->name));
1298 return NT_STATUS_OK;
1301 DBG_DEBUG("Got entry %s\n", finfo->name);
1303 if (!ll_dir_state_add(dir_state, finfo->name)) {
1304 return NT_STATUS_NO_MEMORY;
1306 return NT_STATUS_OK;
1309 static void cli_ll_readdir_done(struct tevent_req *req)
1311 struct ll_readdir_state *state = tevent_req_callback_data(
1312 req, struct ll_readdir_state);
1313 NTSTATUS status;
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;
1321 cli_ll_readdir_reply_one(state->freq, state->dir_state);
1322 TALLOC_FREE(state);
1326 struct ll_releasedir_state {
1327 struct mount_state *mstate;
1328 fuse_req_t freq;
1329 struct ll_dir_state *dir_state;
1332 static void cli_ll_releasedir_done(struct tevent_req *req);
1334 static void cli_ll_releasedir(fuse_req_t freq, fuse_ino_t ino,
1335 struct fuse_file_info *fi)
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;
1343 DBG_DEBUG("ino=%ju\n", (uintmax_t)ino);
1345 state = talloc(mstate, struct ll_releasedir_state);
1346 if (state == NULL) {
1347 fuse_reply_err(freq, ENOMEM);
1348 return;
1350 state->mstate = mstate;
1351 state->freq = freq;
1353 state->dir_state = talloc_get_type_abort(
1354 (void *)fi->fh, struct ll_dir_state);
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;
1365 tevent_req_set_callback(req, cli_ll_releasedir_done, state);
1368 static void cli_ll_releasedir_done(struct tevent_req *req)
1370 struct ll_releasedir_state *state = tevent_req_callback_data(
1371 req, struct ll_releasedir_state);
1372 NTSTATUS status;
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;
1380 TALLOC_FREE(state->dir_state);
1381 fuse_reply_err(state->freq, 0);
1382 TALLOC_FREE(state);
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,
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);
1409 static int mount_state_destructor(struct mount_state *s);
1411 int do_mount(struct cli_state *cli, const char *mountpoint)
1413 struct mount_state *state;
1414 struct inode_state *ino;
1415 struct fuse_args args = { 0 };
1416 int fd;
1417 int ret = 1;
1419 state = talloc_zero(talloc_tos(), struct mount_state);
1420 if (state == NULL) {
1421 fprintf(stderr, "talloc failed\n");
1422 return 1;
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;
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;
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;
1446 talloc_set_destructor(state, mount_state_destructor);
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;
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;
1461 state->cli = cli;
1463 state->ch = fuse_mount(mountpoint, &args);
1464 if (state->ch == NULL) {
1465 perror("fuse_mount failed");
1466 goto fail_free;
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;
1476 fd = fuse_chan_fd(state->ch);
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;
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;
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;
1499 fuse_session_add_chan(state->se, state->ch);
1501 while (!state->done) {
1502 ret = tevent_loop_once(state->ev);
1503 if (ret == -1) {
1504 perror("tevent_loop_once failed");
1505 break;
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;
1518 static int mount_state_destructor(struct mount_state *s)
1520 TALLOC_FREE(s->ino_parent);
1521 return 0;
1525 static void fuse_chan_fd_handler(struct tevent_context *ev,
1526 struct tevent_fd *fde,
1527 uint16_t flags,
1528 void *private_data)
1530 struct mount_state *state = talloc_get_type_abort(
1531 private_data, struct mount_state);
1532 int recvd;
1534 if ((flags & TEVENT_FD_READ) == 0) {
1535 return;
1538 recvd = fuse_chan_recv(&state->ch, state->buf, state->bufsize);
1539 if (recvd <= 0) {
1540 state->done = true;
1541 return;
1543 fuse_session_process(state->se, state->buf, recvd, state->ch);
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)
1553 struct mount_state *state = talloc_get_type_abort(
1554 private_data, struct mount_state);
1555 state->done = true;