vfs_aio_fork: Use a shorter random delay
[Samba.git] / examples / fuse / clifuse.c
blobda9dd4d3e829e29a9291b9d851fb5b188a2079f3
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, mstate->ev, mstate->cli, state->path,
154 0, FILE_GENERIC_READ|FILE_GENERIC_WRITE, FILE_ATTRIBUTE_NORMAL,
155 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
156 FILE_CREATE, FILE_NON_DIRECTORY_FILE);
157 if (req == NULL) {
158 TALLOC_FREE(state);
159 fuse_reply_err(freq, ENOMEM);
160 return;
162 tevent_req_set_callback(req, cli_ll_create_done, state);
165 static void cli_ll_create_done(struct tevent_req *req)
167 struct ll_create_state *state = tevent_req_callback_data(
168 req, struct ll_create_state);
169 struct fuse_entry_param e;
170 struct inode_state *ino;
171 uint16_t fnum;
172 NTSTATUS status;
174 status = cli_smb2_create_fnum_recv(req, &fnum, NULL);
175 TALLOC_FREE(req);
176 if (!NT_STATUS_IS_OK(status)) {
177 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
178 return;
181 state->fi.fh = fnum;
182 state->fi.direct_io = 0;
183 state->fi.keep_cache = 0;
185 ino = inode_state_new(state->mstate, state->path);
186 if (ino == NULL) {
187 fuse_reply_err(state->freq, ENOMEM);
188 return;
191 e = (struct fuse_entry_param) {
192 .ino = ino->ino,
193 .generation = 1, /* FIXME */
194 .attr_timeout = 1.0,
195 .entry_timeout = 1.0
198 fuse_reply_create(state->freq, &e, &state->fi);
200 TALLOC_FREE(state);
203 struct cli_get_unixattr_state {
204 struct tevent_context *ev;
205 struct cli_state *cli;
206 uint64_t fid_persistent;
207 uint64_t fid_volatile;
209 struct timespec create_time;
210 struct timespec access_time;
211 struct timespec write_time;
212 struct timespec change_time;
213 uint32_t mode;
214 uint64_t ino;
215 uint64_t size;
218 static void cli_get_unixattr_opened(struct tevent_req *subreq);
219 static void cli_get_unixattr_gotinfo(struct tevent_req *subreq);
220 static void cli_get_unixattr_closed(struct tevent_req *subreq);
223 static struct tevent_req *cli_get_unixattr_send(TALLOC_CTX *mem_ctx,
224 struct tevent_context *ev,
225 struct cli_state *cli,
226 const char *path)
228 struct tevent_req *req, *subreq;
229 struct cli_get_unixattr_state *state;
231 req = tevent_req_create(mem_ctx, &state,
232 struct cli_get_unixattr_state);
233 if (req == NULL) {
234 return NULL;
236 state->ev = ev;
237 state->cli = cli;
239 subreq = smb2cli_create_send(
240 state, ev, cli->conn, cli->timeout, cli->smb2.session,
241 cli->smb2.tcon, path, SMB2_OPLOCK_LEVEL_NONE,
242 SMB2_IMPERSONATION_IMPERSONATION,
243 SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES, 0,
244 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
245 FILE_OPEN, 0, NULL);
246 if (tevent_req_nomem(subreq, req)) {
247 return tevent_req_post(req, ev);
249 tevent_req_set_callback(subreq, cli_get_unixattr_opened, req);
251 return req;
254 static void cli_get_unixattr_opened(struct tevent_req *subreq)
256 struct tevent_req *req = tevent_req_callback_data(
257 subreq, struct tevent_req);
258 struct cli_get_unixattr_state *state = tevent_req_data(
259 req, struct cli_get_unixattr_state);
260 struct cli_state *cli = state->cli;
261 NTSTATUS status;
263 status = smb2cli_create_recv(subreq, &state->fid_persistent,
264 &state->fid_volatile, NULL, NULL, NULL);
265 TALLOC_FREE(subreq);
266 if (tevent_req_nterror(req, status)) {
267 DBG_DEBUG("smb2cli_create_recv returned %s\n",
268 nt_errstr(status));
269 return;
272 subreq = smb2cli_query_info_send(
273 state, state->ev, cli->conn, 0,
274 cli->smb2.session, cli->smb2.tcon,
275 1, /* in_info_type */
276 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
277 0xFFFF, /* in_max_output_length */
278 NULL, /* in_input_buffer */
279 0, /* in_additional_info */
280 0, /* in_flags */
281 state->fid_persistent,
282 state->fid_volatile);
283 if (tevent_req_nomem(subreq, req)) {
284 return;
286 tevent_req_set_callback(subreq, cli_get_unixattr_gotinfo, req);
289 static void cli_get_unixattr_gotinfo(struct tevent_req *subreq)
291 struct tevent_req *req = tevent_req_callback_data(
292 subreq, struct tevent_req);
293 struct cli_get_unixattr_state *state = tevent_req_data(
294 req, struct cli_get_unixattr_state);
295 struct cli_state *cli = state->cli;
296 NTSTATUS status;
297 DATA_BLOB outbuf;
299 status = smb2cli_query_info_recv(subreq, state, &outbuf);
300 TALLOC_FREE(subreq);
301 if (tevent_req_nterror(req, status)) {
302 DBG_DEBUG("smb2cli_query_info_recv returned %s\n",
303 nt_errstr(status));
304 return;
307 if (outbuf.length < 0x60) {
308 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
309 return;
312 state->create_time = interpret_long_date((char *)outbuf.data + 0x0);
313 state->access_time = interpret_long_date((char *)outbuf.data + 0x8);
314 state->write_time = interpret_long_date((char *)outbuf.data + 0x10);
315 state->change_time = interpret_long_date((char *)outbuf.data + 0x18);
316 state->mode = IVAL(outbuf.data, 0x20);
317 state->size = BVAL(outbuf.data, 0x30);
318 state->ino = BVAL(outbuf.data, 0x40);
320 subreq = smb2cli_close_send(state, state->ev, cli->conn, 0,
321 cli->smb2.session, cli->smb2.tcon, 0,
322 state->fid_persistent,
323 state->fid_volatile);
324 if (tevent_req_nomem(subreq, req)) {
325 return;
327 tevent_req_set_callback(subreq, cli_get_unixattr_closed, req);
330 static void cli_get_unixattr_closed(struct tevent_req *subreq)
332 struct tevent_req *req = tevent_req_callback_data(
333 subreq, struct tevent_req);
334 NTSTATUS status;
336 status = smb2cli_close_recv(subreq);
337 TALLOC_FREE(subreq);
338 if (tevent_req_nterror(req, status)) {
339 return;
341 tevent_req_done(req);
344 static NTSTATUS cli_get_unixattr_recv(struct tevent_req *req,
345 struct stat *st)
347 struct cli_get_unixattr_state *state = tevent_req_data(
348 req, struct cli_get_unixattr_state);
349 NTSTATUS status;
351 if (tevent_req_is_nterror(req, &status)) {
352 return status;
355 if (IS_DOS_DIR(state->mode)) {
356 st->st_mode = (S_IFDIR | 0555);
357 st->st_nlink = 2;
358 } else {
359 st->st_mode = (S_IFREG | 0444);
360 st->st_nlink = 1;
363 st->st_size = state->size;
364 st->st_uid = getuid();
365 st->st_gid = getgid();
366 st->st_ino = state->ino;
367 st->st_atime = convert_timespec_to_time_t(state->access_time);
368 st->st_ctime = convert_timespec_to_time_t(state->change_time);
369 st->st_mtime = convert_timespec_to_time_t(state->write_time);
371 return NT_STATUS_OK;
374 struct cli_smb2_listdir_state {
375 struct tevent_context *ev;
376 struct smbXcli_conn *conn;
377 uint32_t timeout_msec;
378 struct smbXcli_session *session;
379 struct smbXcli_tcon *tcon;
380 uint8_t level;
381 uint8_t flags;
382 uint32_t file_index;
383 uint64_t fid_persistent;
384 uint64_t fid_volatile;
385 const char *mask;
386 uint32_t outbuf_len;
388 uint16_t attribute;
389 const char *mntpoint;
390 const char *pathname;
391 NTSTATUS (*fn)(const char *mntpoint, struct file_info *f,
392 const char *mask, void *private_data);
393 void *private_data;
394 bool processed_file;
397 static void cli_smb2_listdir_done(struct tevent_req *subreq);
399 static struct tevent_req *cli_smb2_listdir_send(
400 TALLOC_CTX *mem_ctx,
401 struct tevent_context *ev,
402 struct smbXcli_conn *conn,
403 uint32_t timeout_msec,
404 struct smbXcli_session *session,
405 struct smbXcli_tcon *tcon,
406 uint8_t level,
407 uint8_t flags,
408 uint32_t file_index,
409 uint64_t fid_persistent,
410 uint64_t fid_volatile,
411 const char *mask,
412 uint32_t outbuf_len,
413 uint16_t attribute,
414 const char *mntpoint,
415 const char *pathname,
416 NTSTATUS (*fn)(const char *mntpoint, struct file_info *f,
417 const char *mask, void *private_data),
418 void *private_data)
420 struct tevent_req *req, *subreq;
421 struct cli_smb2_listdir_state *state;
423 req = tevent_req_create(mem_ctx, &state,
424 struct cli_smb2_listdir_state);
425 if (req == NULL) {
426 return NULL;
428 state->ev = ev;
429 state->conn = conn;
430 state->timeout_msec = timeout_msec;
431 state->session = session;
432 state->tcon = tcon;
433 state->level = level;
434 state->flags = flags;
435 state->file_index = file_index;
436 state->fid_persistent = fid_persistent;
437 state->fid_volatile = fid_volatile;
438 state->mask = mask;
439 state->outbuf_len = outbuf_len;
440 state->attribute = attribute;
441 state->mntpoint = mntpoint;
442 state->pathname = pathname;
443 state->fn = fn;
444 state->private_data = private_data;
446 subreq = smb2cli_query_directory_send(
447 state, state->ev, state->conn, state->timeout_msec,
448 state->session, state->tcon, state->level,
449 state->flags, state->file_index,
450 state->fid_persistent, state->fid_volatile,
451 state->mask, state->outbuf_len);
452 if (tevent_req_nomem(subreq, req)) {
453 return tevent_req_post(req, ev);
455 tevent_req_set_callback(subreq, cli_smb2_listdir_done, req);
456 return req;
459 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
460 uint32_t dir_data_length,
461 struct file_info *finfo,
462 uint32_t *next_offset)
464 size_t namelen = 0;
465 size_t slen = 0;
466 size_t ret = 0;
468 if (dir_data_length < 4) {
469 return NT_STATUS_INFO_LENGTH_MISMATCH;
472 *next_offset = IVAL(dir_data, 0);
474 if (*next_offset > dir_data_length) {
475 return NT_STATUS_INFO_LENGTH_MISMATCH;
478 if (*next_offset != 0) {
479 /* Ensure we only read what in this record. */
480 dir_data_length = *next_offset;
483 if (dir_data_length < 105) {
484 return NT_STATUS_INFO_LENGTH_MISMATCH;
487 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
488 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
489 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
490 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
491 finfo->mode = CVAL(dir_data + 56, 0);
492 namelen = IVAL(dir_data + 60,0);
493 if (namelen > (dir_data_length - 104)) {
494 return NT_STATUS_INFO_LENGTH_MISMATCH;
496 slen = CVAL(dir_data + 68, 0);
497 if (slen > 24) {
498 return NT_STATUS_INFO_LENGTH_MISMATCH;
500 ret = pull_string_talloc(finfo,
501 dir_data,
502 FLAGS2_UNICODE_STRINGS,
503 &finfo->short_name,
504 dir_data + 70,
505 slen,
506 STR_UNICODE);
507 if (ret == (size_t)-1) {
508 /* Bad conversion. */
509 return NT_STATUS_INVALID_NETWORK_RESPONSE;
512 ret = pull_string_talloc(finfo,
513 dir_data,
514 FLAGS2_UNICODE_STRINGS,
515 &finfo->name,
516 dir_data + 104,
517 namelen,
518 STR_UNICODE);
519 if (ret == (size_t)-1) {
520 /* Bad conversion. */
521 return NT_STATUS_INVALID_NETWORK_RESPONSE;
523 return NT_STATUS_OK;
526 static void cli_smb2_listdir_done(struct tevent_req *subreq)
528 struct tevent_req *req = tevent_req_callback_data(
529 subreq, struct tevent_req);
530 struct cli_smb2_listdir_state *state = tevent_req_data(
531 req, struct cli_smb2_listdir_state);
532 uint8_t *data;
533 uint32_t data_len;
534 uint32_t next_offset = 0;
535 NTSTATUS status;
537 status = smb2cli_query_directory_recv(subreq, state, &data,
538 &data_len);
539 TALLOC_FREE(subreq);
540 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
541 tevent_req_done(req);
542 return;
544 if (tevent_req_nterror(req, status)) {
545 return;
548 do {
549 struct file_info *finfo;
550 bool ok;
552 finfo = talloc_zero(state, struct file_info);
553 if (tevent_req_nomem(finfo, req)) {
554 return;
557 status = parse_finfo_id_both_directory_info(
558 data, data_len, finfo, &next_offset);
560 DEBUG(10, ("%s: parse_finfo_id_both_directory_info returned "
561 "%s\n", __func__, nt_errstr(status)));
563 if (tevent_req_nterror(req, status)) {
564 return;
567 ok = dir_check_ftype(finfo->mode, state->attribute);
569 DEBUG(10, ("%s: dir_check_ftype(%u,%u) returned %u\n",
570 __func__, (unsigned)finfo->mode,
571 (unsigned)state->attribute, (unsigned)ok));
573 if (ok) {
575 * Only process if attributes match. On SMB1 server
576 * does this, so on SMB2 we need to emulate in the
577 * client.
579 * https://bugzilla.samba.org/show_bug.cgi?id=10260
581 state->processed_file = true;
583 status = state->fn(state->mntpoint, finfo,
584 state->pathname,
585 state->private_data);
586 if (tevent_req_nterror(req, status)) {
587 return;
591 TALLOC_FREE(finfo);
593 if (next_offset != 0) {
594 data += next_offset;
595 data_len -= next_offset;
597 } while (next_offset != 0);
599 subreq = smb2cli_query_directory_send(
600 state, state->ev, state->conn, state->timeout_msec,
601 state->session, state->tcon, state->level,
602 state->flags, state->file_index,
603 state->fid_persistent, state->fid_volatile,
604 state->mask, state->outbuf_len);
605 if (tevent_req_nomem(subreq, req)) {
606 return;
608 tevent_req_set_callback(subreq, cli_smb2_listdir_done, req);
611 static NTSTATUS cli_smb2_listdir_recv(struct tevent_req *req)
613 struct cli_smb2_listdir_state *state = tevent_req_data(
614 req, struct cli_smb2_listdir_state);
615 NTSTATUS status;
617 if (tevent_req_is_nterror(req, &status)) {
618 return status;
621 if (!state->processed_file) {
623 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
624 * if no files match. Emulate this in the client.
626 return NT_STATUS_NO_SUCH_FILE;
629 return NT_STATUS_OK;
632 struct ll_lookup_state {
633 struct mount_state *mstate;
634 fuse_req_t freq;
635 char *path;
638 static void cli_ll_lookup_done(struct tevent_req *req);
640 static void cli_ll_lookup(fuse_req_t freq, fuse_ino_t parent_ino,
641 const char *name)
643 struct mount_state *mstate = talloc_get_type_abort(
644 fuse_req_userdata(freq), struct mount_state);
645 struct ll_lookup_state *state;
646 struct tevent_req *req;
647 struct inode_state *parent;
649 DBG_DEBUG("parent_ino=%ju, name=%s\n", (uintmax_t)parent_ino, name);
651 parent = idr_find(mstate->ino_ctx, parent_ino);
652 if (parent == NULL) {
653 DBG_WARNING("could not find parent\n");
654 fuse_reply_err(freq, ENOENT);
655 return;
658 state = talloc(mstate, struct ll_lookup_state);
659 if (state == NULL) {
660 DBG_WARNING("talloc failed\n");
661 fuse_reply_err(freq, ENOMEM);
662 return;
664 state->mstate = mstate;
665 state->freq = freq;
667 state->path = talloc_asprintf(state, "%s%s%s", parent->path,
668 strlen(parent->path) ? "\\": "",
669 name);
670 if (state->path == NULL) {
671 TALLOC_FREE(state);
672 fuse_reply_err(freq, ENOMEM);
673 return;
676 req = cli_get_unixattr_send(state, mstate->ev, mstate->cli,
677 state->path);
678 if (req == NULL) {
679 TALLOC_FREE(state);
680 fuse_reply_err(freq, ENOMEM);
681 return;
683 tevent_req_set_callback(req, cli_ll_lookup_done, state);
686 static void cli_ll_lookup_done(struct tevent_req *req)
688 struct ll_lookup_state *state = tevent_req_callback_data(
689 req, struct ll_lookup_state);
690 struct stat sbuf = {0};
691 struct fuse_entry_param e;
692 struct inode_state *ino;
693 NTSTATUS status;
695 status = cli_get_unixattr_recv(req, &sbuf);
696 TALLOC_FREE(req);
697 if (!NT_STATUS_IS_OK(status)) {
698 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
699 return;
702 ino = inode_state_new(state->mstate, state->path);
703 if (ino == NULL) {
704 fuse_reply_err(state->freq, ENOMEM);
705 return;
708 e = (struct fuse_entry_param) {
709 .ino = ino->ino,
710 .attr = sbuf,
711 .generation = 1, /* FIXME */
712 .attr_timeout = 1.0,
713 .entry_timeout = 1.0
716 fuse_reply_entry(state->freq, &e);
717 TALLOC_FREE(state);
720 struct ll_getattr_state {
721 struct mount_state *mstate;
722 fuse_req_t freq;
723 struct fuse_file_info fi;
726 static void cli_ll_getattr_done(struct tevent_req *req);
728 static void cli_ll_getattr(fuse_req_t freq, fuse_ino_t ino,
729 struct fuse_file_info *fi)
731 struct mount_state *mstate = talloc_get_type_abort(
732 fuse_req_userdata(freq), struct mount_state);
733 struct ll_getattr_state *state;
734 struct inode_state *istate;
735 struct tevent_req *req;
737 DBG_DEBUG("ino=%ju\n", (uintmax_t)ino);
739 istate = idr_find(mstate->ino_ctx, ino);
740 if (istate == NULL) {
741 fuse_reply_err(freq, ENOENT);
742 return;
745 state = talloc(mstate, struct ll_getattr_state);
746 if (state == NULL) {
747 fuse_reply_err(freq, ENOMEM);
748 return;
750 state->mstate = mstate;
751 state->freq = freq;
753 req = cli_get_unixattr_send(state, mstate->ev, mstate->cli,
754 istate->path);
755 if (req == NULL) {
756 TALLOC_FREE(state);
757 fuse_reply_err(freq, ENOMEM);
758 return;
760 tevent_req_set_callback(req, cli_ll_getattr_done, state);
763 static void cli_ll_getattr_done(struct tevent_req *req)
765 struct ll_getattr_state *state = tevent_req_callback_data(
766 req, struct ll_getattr_state);
767 struct stat st;
768 NTSTATUS status;
769 int ret;
771 status = cli_get_unixattr_recv(req, &st);
772 TALLOC_FREE(req);
773 if (!NT_STATUS_IS_OK(status)) {
774 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
775 return;
778 ret = fuse_reply_attr(state->freq, &st, 1);
779 if (ret != 0) {
780 DBG_NOTICE("fuse_reply_attr failed: %s\n",
781 strerror(-errno));
786 struct ll_open_state {
787 struct mount_state *mstate;
788 fuse_req_t freq;
789 struct fuse_file_info fi;
792 static void cli_ll_open_done(struct tevent_req *req);
794 static void cli_ll_open(fuse_req_t freq, fuse_ino_t ino,
795 struct fuse_file_info *fi)
797 struct mount_state *mstate = talloc_get_type_abort(
798 fuse_req_userdata(freq), struct mount_state);
799 struct ll_open_state *state;
800 struct inode_state *istate;
801 struct tevent_req *req;
802 uint32_t acc;
804 DBG_DEBUG("ino=%ju\n", (uintmax_t)ino);
806 istate = idr_find(mstate->ino_ctx, ino);
807 if (istate == NULL) {
808 fuse_reply_err(freq, ENOENT);
809 return;
812 state = talloc(mstate, struct ll_open_state);
813 if (state == NULL) {
814 fuse_reply_err(freq, ENOMEM);
815 return;
817 state->mstate = mstate;
818 state->freq = freq;
819 state->fi = *fi;
821 switch (fi->flags & O_ACCMODE) {
822 case O_RDONLY:
823 acc = FILE_GENERIC_READ;
824 break;
825 case O_WRONLY:
826 acc = FILE_GENERIC_WRITE;
827 break;
828 case O_RDWR:
829 acc = FILE_GENERIC_READ|FILE_GENERIC_WRITE;
830 break;
831 default:
832 fuse_reply_err(freq, EACCES);
833 return;
836 req = cli_smb2_create_fnum_send(
837 state, mstate->ev, mstate->cli, istate->path,
838 0, acc, FILE_ATTRIBUTE_NORMAL,
839 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
840 FILE_OPEN, FILE_NON_DIRECTORY_FILE);
841 if (req == NULL) {
842 TALLOC_FREE(state);
843 fuse_reply_err(freq, ENOMEM);
844 return;
846 tevent_req_set_callback(req, cli_ll_open_done, state);
849 static void cli_ll_open_done(struct tevent_req *req)
851 struct ll_open_state *state = tevent_req_callback_data(
852 req, struct ll_open_state);
853 uint16_t fnum;
854 NTSTATUS status;
856 status = cli_smb2_create_fnum_recv(req, &fnum, NULL);
857 TALLOC_FREE(req);
858 if (!NT_STATUS_IS_OK(status)) {
859 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
860 return;
863 state->fi.fh = fnum;
864 state->fi.direct_io = 0;
865 state->fi.keep_cache = 0;
867 fuse_reply_open(state->freq, &state->fi);
869 TALLOC_FREE(state);
872 struct ll_release_state {
873 struct mount_state *mstate;
874 fuse_req_t freq;
875 fuse_ino_t ino;
878 static void cli_ll_release_done(struct tevent_req *req);
880 static void cli_ll_release(fuse_req_t freq, fuse_ino_t ino,
881 struct fuse_file_info *fi)
883 struct mount_state *mstate = talloc_get_type_abort(
884 fuse_req_userdata(freq), struct mount_state);
885 struct ll_release_state *state;
886 struct inode_state *istate;
887 struct tevent_req *req;
888 uint16_t fnum;
890 DBG_DEBUG("ino=%ju\n", (uintmax_t)ino);
892 istate = idr_find(mstate->ino_ctx, ino);
893 if (istate == NULL) {
894 fuse_reply_err(freq, ENOENT);
895 return;
898 state = talloc(mstate, struct ll_release_state);
899 if (state == NULL) {
900 fuse_reply_err(freq, ENOMEM);
901 return;
903 state->mstate = mstate;
904 state->freq = freq;
905 state->ino = ino;
907 fnum = fi->fh;
909 req = cli_smb2_close_fnum_send(state, mstate->ev, mstate->cli, fnum);
910 if (req == NULL) {
911 TALLOC_FREE(state);
912 fuse_reply_err(freq, ENOMEM);
913 return;
915 tevent_req_set_callback(req, cli_ll_release_done, state);
918 static void cli_ll_release_done(struct tevent_req *req)
920 struct ll_release_state *state = tevent_req_callback_data(
921 req, struct ll_release_state);
922 struct inode_state *istate;
923 NTSTATUS status;
925 status = cli_smb2_close_fnum_recv(req);
926 TALLOC_FREE(req);
927 if (!NT_STATUS_IS_OK(status)) {
928 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
929 return;
932 istate = idr_find(state->mstate->ino_ctx, state->ino);
933 if (istate == NULL) {
934 DEBUG(1, ("%s: inode %ju vanished!\n", __func__,
935 (uintmax_t)state->ino));
937 TALLOC_FREE(istate);
939 fuse_reply_err(state->freq, 0);
940 TALLOC_FREE(state);
943 struct ll_read_state {
944 struct mount_state *mstate;
945 fuse_req_t freq;
948 static void cli_ll_read_done(struct tevent_req *req);
950 static void cli_ll_read(fuse_req_t freq, fuse_ino_t ino,
951 size_t size, off_t off,
952 struct fuse_file_info *fi)
954 struct mount_state *mstate = talloc_get_type_abort(
955 fuse_req_userdata(freq), struct mount_state);
956 struct ll_read_state *state;
957 struct tevent_req *req;
958 uint16_t fnum;
960 DBG_DEBUG("ino=%ju, size=%zu, off=%ju\n", (uintmax_t)ino,
961 size, (uintmax_t)off);
963 state = talloc(mstate, struct ll_read_state);
964 if (state == NULL) {
965 fuse_reply_err(freq, ENOMEM);
966 return;
968 state->mstate = mstate;
969 state->freq = freq;
971 fnum = fi->fh;
973 req = cli_smb2_read_send(state, mstate->ev, mstate->cli,
974 fnum, off, size);
975 if (req == NULL) {
976 TALLOC_FREE(state);
977 fuse_reply_err(freq, ENOMEM);
978 return;
980 tevent_req_set_callback(req, cli_ll_read_done, state);
983 static void cli_ll_read_done(struct tevent_req *req)
985 struct ll_read_state *state = tevent_req_callback_data(
986 req, struct ll_read_state);
987 ssize_t received;
988 uint8_t *rcvbuf;
989 NTSTATUS status;
991 status = cli_smb2_read_recv(req, &received, &rcvbuf);
992 /* no talloc_free here yet */
994 if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
995 received = 0;
996 rcvbuf = NULL;
997 status = NT_STATUS_OK;
1000 if (!NT_STATUS_IS_OK(status)) {
1001 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
1002 return;
1004 fuse_reply_buf(state->freq, (char *)rcvbuf, received);
1005 TALLOC_FREE(state);
1008 struct ll_write_state {
1009 struct mount_state *mstate;
1010 fuse_req_t freq;
1013 static void cli_ll_write_done(struct tevent_req *req);
1015 static void cli_ll_write(fuse_req_t freq, fuse_ino_t ino, const char *buf,
1016 size_t size, off_t off, struct fuse_file_info *fi)
1018 struct mount_state *mstate = talloc_get_type_abort(
1019 fuse_req_userdata(freq), struct mount_state);
1020 struct ll_write_state *state;
1021 struct tevent_req *req;
1022 uint16_t fnum;
1024 DBG_DEBUG("ino=%ju, size=%zu, off=%ju\n", (uintmax_t)ino,
1025 size, (uintmax_t)off);
1027 state = talloc(mstate, struct ll_write_state);
1028 if (state == NULL) {
1029 fuse_reply_err(freq, ENOMEM);
1030 return;
1032 state->mstate = mstate;
1033 state->freq = freq;
1035 fnum = fi->fh;
1037 req = cli_smb2_write_send(state, mstate->ev, mstate->cli, fnum, 0,
1038 (const uint8_t *)buf, off, size);
1039 if (req == NULL) {
1040 TALLOC_FREE(state);
1041 fuse_reply_err(freq, ENOMEM);
1042 return;
1044 tevent_req_set_callback(req, cli_ll_write_done, state);
1047 static void cli_ll_write_done(struct tevent_req *req)
1049 struct ll_write_state *state = tevent_req_callback_data(
1050 req, struct ll_write_state);
1051 size_t written;
1052 NTSTATUS status;
1054 status = cli_smb2_write_recv(req, &written);
1055 /* no talloc_free here yet */
1056 if (!NT_STATUS_IS_OK(status)) {
1057 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
1058 return;
1060 fuse_reply_write(state->freq, written);
1061 TALLOC_FREE(state);
1065 struct ll_dir_state {
1066 uint64_t fid_persistent;
1067 uint64_t fid_volatile;
1069 struct file_info *finfos;
1070 unsigned num_finfos, num_sent;
1073 static bool ll_dir_state_add(struct ll_dir_state *dir_state,
1074 const char *name)
1076 struct file_info *tmp, *finfo;
1078 tmp = talloc_realloc(dir_state, dir_state->finfos,
1079 struct file_info, dir_state->num_finfos+1);
1080 if (tmp == NULL) {
1081 return false;
1083 dir_state->finfos = tmp;
1084 finfo = &dir_state->finfos[dir_state->num_finfos];
1086 ZERO_STRUCTP(finfo);
1088 finfo->name = talloc_strdup(dir_state->finfos, name);
1089 if (finfo->name == NULL) {
1090 return false;
1092 dir_state->num_finfos += 1;
1094 return true;
1097 struct ll_opendir_state {
1098 struct mount_state *mstate;
1099 fuse_req_t freq;
1100 struct fuse_file_info fi;
1101 struct ll_dir_state *dir_state;
1104 static void cli_ll_opendir_done(struct tevent_req *req);
1106 static void cli_ll_opendir(fuse_req_t freq, fuse_ino_t ino,
1107 struct fuse_file_info *fi)
1109 struct mount_state *mstate = talloc_get_type_abort(
1110 fuse_req_userdata(freq), struct mount_state);
1111 struct cli_state *cli = mstate->cli;
1112 struct ll_opendir_state *state;
1113 struct inode_state *istate;
1114 struct tevent_req *req;
1116 DBG_DEBUG("ino=%ju\n", (uintmax_t)ino);
1118 istate = idr_find(mstate->ino_ctx, ino);
1119 if (istate == NULL) {
1120 fuse_reply_err(freq, ENOENT);
1121 return;
1124 state = talloc(mstate, struct ll_opendir_state);
1125 if (state == NULL) {
1126 fuse_reply_err(freq, ENOMEM);
1127 return;
1129 state->mstate = mstate;
1130 state->freq = freq;
1131 state->fi = *fi;
1133 state->dir_state = talloc_zero(state, struct ll_dir_state);
1134 if (state->dir_state == NULL) {
1135 TALLOC_FREE(state);
1136 fuse_reply_err(freq, ENOMEM);
1137 return;
1140 req = smb2cli_create_send(
1141 state, mstate->ev, cli->conn, cli->timeout,
1142 cli->smb2.session, cli->smb2.tcon, istate->path,
1143 0, SMB2_IMPERSONATION_IMPERSONATION,
1144 FILE_GENERIC_READ, FILE_ATTRIBUTE_DIRECTORY,
1145 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1146 FILE_OPEN, FILE_DIRECTORY_FILE, NULL);
1147 if (req == NULL) {
1148 TALLOC_FREE(state);
1149 fuse_reply_err(freq, ENOMEM);
1150 return;
1152 tevent_req_set_callback(req, cli_ll_opendir_done, state);
1155 static void cli_ll_opendir_done(struct tevent_req *req)
1157 struct ll_opendir_state *state = tevent_req_callback_data(
1158 req, struct ll_opendir_state);
1159 NTSTATUS status;
1161 status = smb2cli_create_recv(req,
1162 &state->dir_state->fid_persistent,
1163 &state->dir_state->fid_volatile,
1164 NULL, NULL, NULL);
1165 TALLOC_FREE(req);
1167 DEBUG(10, ("%s: smbcli_create_recv returned %s\n", __func__,
1168 nt_errstr(status)));
1170 if (!NT_STATUS_IS_OK(status)) {
1171 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
1172 return;
1175 state->fi.fh = (uint64_t)talloc_move(state->mstate, &state->dir_state);
1176 state->fi.direct_io = 0;
1177 state->fi.keep_cache = 0;
1179 fuse_reply_open(state->freq, &state->fi);
1181 TALLOC_FREE(state);
1184 struct ll_readdir_state {
1185 fuse_req_t freq;
1186 struct ll_dir_state *dir_state;
1189 static void cli_ll_readdir_done(struct tevent_req *subreq);
1190 static NTSTATUS cli_ll_readdir_one(const char *mnt, struct file_info *finfo,
1191 const char *path, void *private_data);
1192 static void cli_ll_readdir_reply_one(fuse_req_t freq,
1193 struct ll_dir_state *dir_state);
1195 static void cli_ll_readdir(fuse_req_t freq, fuse_ino_t ino, size_t size,
1196 off_t off, struct fuse_file_info *fi)
1198 struct mount_state *mstate = talloc_get_type_abort(
1199 fuse_req_userdata(freq), struct mount_state);
1200 struct cli_state *cli = mstate->cli;
1201 struct ll_dir_state *dir_state;
1202 struct ll_readdir_state *state;
1203 struct tevent_req *req;
1205 DBG_DEBUG("ino=%ju, size=%zu, off=%ju\n", (uintmax_t)ino, size,
1206 (uintmax_t)off);
1208 dir_state = talloc_get_type_abort((void *)fi->fh, struct ll_dir_state);
1210 if (dir_state->finfos != NULL) {
1211 DBG_DEBUG("finfos=%p\n", dir_state->finfos);
1212 cli_ll_readdir_reply_one(freq, dir_state);
1213 return;
1216 if (!ll_dir_state_add(dir_state, ".") ||
1217 !ll_dir_state_add(dir_state, "..")) {
1218 fuse_reply_err(freq, ENOMEM);
1219 return;
1222 state = talloc(mstate, struct ll_readdir_state);
1223 if (state == NULL) {
1224 fuse_reply_err(freq, ENOMEM);
1225 return;
1227 state->freq = freq;
1228 state->dir_state = dir_state;
1230 req = cli_smb2_listdir_send(
1231 state, mstate->ev, cli->conn, cli->timeout,
1232 cli->smb2.session, cli->smb2.tcon,
1233 SMB2_FIND_ID_BOTH_DIRECTORY_INFO, 0, 0,
1234 dir_state->fid_persistent, dir_state->fid_volatile,
1235 "*", 0xffff,
1236 FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM |
1237 FILE_ATTRIBUTE_HIDDEN,
1238 NULL, NULL, cli_ll_readdir_one, dir_state);
1239 if (req == NULL) {
1240 TALLOC_FREE(state);
1241 fuse_reply_err(freq, ENOMEM);
1242 return;
1244 tevent_req_set_callback(req, cli_ll_readdir_done, state);
1247 static void cli_ll_readdir_reply_one(fuse_req_t freq,
1248 struct ll_dir_state *dir_state)
1250 struct file_info *finfo;
1251 char buf[1024];
1252 struct stat sbuf = {};
1253 size_t buflen;
1255 if (dir_state->num_finfos == dir_state->num_sent) {
1256 DEBUG(10, ("%s: Done\n", __func__));
1257 fuse_reply_buf(freq, NULL, 0);
1258 return;
1261 sbuf.st_mode = S_IFREG | 0755;
1262 sbuf.st_ino = random(); /* FIXME :-) */
1263 finfo = &dir_state->finfos[dir_state->num_sent];
1265 DBG_DEBUG("Adding %s\n", finfo->name);
1267 buflen = fuse_add_direntry(freq, buf, sizeof(buf),
1268 finfo->name, &sbuf, 0);
1269 fuse_reply_buf(freq, buf, buflen);
1270 dir_state->num_sent += 1;
1271 return;
1274 static NTSTATUS cli_ll_readdir_one(const char *mnt, struct file_info *finfo,
1275 const char *path, void *private_data)
1277 struct ll_dir_state *dir_state = talloc_get_type_abort(
1278 private_data, struct ll_dir_state);
1280 if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
1281 DEBUG(10, ("%s: Ignoring %s\n", __func__, finfo->name));
1282 return NT_STATUS_OK;
1285 DBG_DEBUG("Got entry %s\n", finfo->name);
1287 if (!ll_dir_state_add(dir_state, finfo->name)) {
1288 return NT_STATUS_NO_MEMORY;
1290 return NT_STATUS_OK;
1293 static void cli_ll_readdir_done(struct tevent_req *req)
1295 struct ll_readdir_state *state = tevent_req_callback_data(
1296 req, struct ll_readdir_state);
1297 NTSTATUS status;
1299 status = cli_smb2_listdir_recv(req);
1300 TALLOC_FREE(req);
1301 if (!NT_STATUS_IS_OK(status)) {
1302 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
1303 return;
1305 cli_ll_readdir_reply_one(state->freq, state->dir_state);
1306 TALLOC_FREE(state);
1310 struct ll_releasedir_state {
1311 struct mount_state *mstate;
1312 fuse_req_t freq;
1313 struct ll_dir_state *dir_state;
1316 static void cli_ll_releasedir_done(struct tevent_req *req);
1318 static void cli_ll_releasedir(fuse_req_t freq, fuse_ino_t ino,
1319 struct fuse_file_info *fi)
1321 struct mount_state *mstate = talloc_get_type_abort(
1322 fuse_req_userdata(freq), struct mount_state);
1323 struct cli_state *cli = mstate->cli;
1324 struct ll_releasedir_state *state;
1325 struct tevent_req *req;
1327 DBG_DEBUG("ino=%ju\n", (uintmax_t)ino);
1329 state = talloc(mstate, struct ll_releasedir_state);
1330 if (state == NULL) {
1331 fuse_reply_err(freq, ENOMEM);
1332 return;
1334 state->mstate = mstate;
1335 state->freq = freq;
1337 state->dir_state = talloc_get_type_abort(
1338 (void *)fi->fh, struct ll_dir_state);
1340 req = smb2cli_close_send(state, mstate->ev, cli->conn, cli->timeout,
1341 cli->smb2.session, cli->smb2.tcon, 0,
1342 state->dir_state->fid_persistent,
1343 state->dir_state->fid_volatile);
1344 if (req == NULL) {
1345 TALLOC_FREE(state);
1346 fuse_reply_err(freq, ENOMEM);
1347 return;
1349 tevent_req_set_callback(req, cli_ll_releasedir_done, state);
1352 static void cli_ll_releasedir_done(struct tevent_req *req)
1354 struct ll_releasedir_state *state = tevent_req_callback_data(
1355 req, struct ll_releasedir_state);
1356 NTSTATUS status;
1358 status = smb2cli_close_recv(req);
1359 TALLOC_FREE(req);
1360 if (!NT_STATUS_IS_OK(status)) {
1361 fuse_reply_err(state->freq, map_errno_from_nt_status(status));
1362 return;
1364 TALLOC_FREE(state->dir_state);
1365 fuse_reply_err(state->freq, 0);
1366 TALLOC_FREE(state);
1369 static struct fuse_lowlevel_ops cli_ll_ops = {
1370 .lookup = cli_ll_lookup,
1371 .getattr = cli_ll_getattr,
1372 .open = cli_ll_open,
1373 .create = cli_ll_create,
1374 .release = cli_ll_release,
1375 .read = cli_ll_read,
1376 .write = cli_ll_write,
1377 .opendir = cli_ll_opendir,
1378 .readdir = cli_ll_readdir,
1379 .releasedir = cli_ll_releasedir,
1382 static void fuse_chan_fd_handler(struct tevent_context *ev,
1383 struct tevent_fd *fde,
1384 uint16_t flags,
1385 void *private_data);
1386 static void fuse_chan_signal_handler(struct tevent_context *ev,
1387 struct tevent_signal *se,
1388 int signum,
1389 int count,
1390 void *siginfo,
1391 void *private_data);
1393 static int mount_state_destructor(struct mount_state *s);
1395 int do_mount(struct cli_state *cli, const char *mountpoint)
1397 struct mount_state *state;
1398 struct inode_state *ino;
1399 struct fuse_args args = { 0 };
1400 int fd;
1401 int ret = 1;
1403 state = talloc_zero(talloc_tos(), struct mount_state);
1404 if (state == NULL) {
1405 fprintf(stderr, "talloc failed\n");
1406 return 1;
1409 state->ev = tevent_context_init(state);
1410 if (state->ev == NULL) {
1411 fprintf(stderr, "tevent_context_init failed\n");
1412 TALLOC_FREE(state);
1413 return 1;
1416 state->ino_ctx = idr_init(state);
1417 if (state->ino_ctx == NULL) {
1418 fprintf(stderr, "idr_init failed\n");
1419 TALLOC_FREE(state);
1420 return 1;
1423 state->ino_parent = talloc_new(state);
1424 if (state->ino_parent == NULL) {
1425 fprintf(stderr, "talloc_new failed\n");
1426 TALLOC_FREE(state);
1427 return 1;
1430 talloc_set_destructor(state, mount_state_destructor);
1432 ino = inode_state_new(state, "");
1433 if (ino == NULL) {
1434 fprintf(stderr, "inode_state_new failed\n");
1435 TALLOC_FREE(state);
1436 return 1;
1438 if (ino->ino != FUSE_ROOT_ID) {
1439 fprintf(stderr, "first inode gave %d, expected %d\n",
1440 (int)ino->ino, FUSE_ROOT_ID);
1441 TALLOC_FREE(state);
1442 return 1;
1445 state->cli = cli;
1447 state->ch = fuse_mount(mountpoint, &args);
1448 if (state->ch == NULL) {
1449 perror("fuse_mount failed");
1450 goto fail_free;
1453 state->bufsize = fuse_chan_bufsize(state->ch);
1454 state->buf = talloc_array(state, char, state->bufsize);
1455 if (state->buf == NULL) {
1456 fprintf(stderr, "talloc failed\n");
1457 goto fail_unmount;
1460 fd = fuse_chan_fd(state->ch);
1462 state->fde = tevent_add_fd(state->ev, state, fd, TEVENT_FD_READ,
1463 fuse_chan_fd_handler, state);
1464 if (state->fde == NULL) {
1465 fprintf(stderr, "tevent_add_fd failed\n");
1466 goto fail_unmount;
1469 state->signal_ev = tevent_add_signal(state->ev, state, SIGINT, 0,
1470 fuse_chan_signal_handler, state);
1471 if (state->signal_ev == NULL) {
1472 fprintf(stderr, "tevent_add_signal failed\n");
1473 goto fail_unmount;
1476 state->se = fuse_lowlevel_new(&args, &cli_ll_ops, sizeof(cli_ll_ops),
1477 state);
1478 if (state->se == NULL) {
1479 perror("fuse_lowlevel_new failed");
1480 goto fail_unmount;
1483 fuse_session_add_chan(state->se, state->ch);
1485 while (!state->done) {
1486 ret = tevent_loop_once(state->ev);
1487 if (ret == -1) {
1488 perror("tevent_loop_once failed");
1489 break;
1493 fuse_session_remove_chan(state->ch);
1494 fuse_session_destroy(state->se);
1495 fail_unmount:
1496 fuse_unmount(mountpoint, state->ch);
1497 fail_free:
1498 TALLOC_FREE(state);
1499 return ret;
1502 static int mount_state_destructor(struct mount_state *s)
1504 TALLOC_FREE(s->ino_parent);
1505 return 0;
1509 static void fuse_chan_fd_handler(struct tevent_context *ev,
1510 struct tevent_fd *fde,
1511 uint16_t flags,
1512 void *private_data)
1514 struct mount_state *state = talloc_get_type_abort(
1515 private_data, struct mount_state);
1516 int recvd;
1518 if ((flags & TEVENT_FD_READ) == 0) {
1519 return;
1522 recvd = fuse_chan_recv(&state->ch, state->buf, state->bufsize);
1523 if (recvd <= 0) {
1524 state->done = true;
1525 return;
1527 fuse_session_process(state->se, state->buf, recvd, state->ch);
1530 static void fuse_chan_signal_handler(struct tevent_context *ev,
1531 struct tevent_signal *se,
1532 int signum,
1533 int count,
1534 void *siginfo,
1535 void *private_data)
1537 struct mount_state *state = talloc_get_type_abort(
1538 private_data, struct mount_state);
1539 state->done = true;