blob: 3773303a55ff379aa5dc131bdf52e68e519e4d20
1 | /* |
2 | FUSE: Filesystem in Userspace |
3 | Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> |
4 | |
5 | This program can be distributed under the terms of the GNU LGPLv2. |
6 | See the file COPYING.LIB |
7 | */ |
8 | |
9 | #include "config.h" |
10 | #include "fuse_lowlevel.h" |
11 | #include "fuse_lowlevel_compat.h" |
12 | |
13 | #include <stdio.h> |
14 | #include <stdlib.h> |
15 | #include <string.h> |
16 | #include <assert.h> |
17 | #include <errno.h> |
18 | |
19 | struct fuse_session { |
20 | struct fuse_session_ops op; |
21 | |
22 | void *data; |
23 | |
24 | volatile int exited; |
25 | |
26 | struct fuse_chan *ch; |
27 | }; |
28 | |
29 | struct fuse_chan { |
30 | struct fuse_chan_ops op; |
31 | |
32 | struct fuse_session *se; |
33 | |
34 | int fd; |
35 | |
36 | size_t bufsize; |
37 | |
38 | void *data; |
39 | }; |
40 | |
41 | struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data) |
42 | { |
43 | struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se)); |
44 | if (se == NULL) { |
45 | fprintf(stderr, "fuse: failed to allocate session\n"); |
46 | return NULL; |
47 | } |
48 | |
49 | memset(se, 0, sizeof(*se)); |
50 | se->op = *op; |
51 | se->data = data; |
52 | |
53 | return se; |
54 | } |
55 | |
56 | void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch) |
57 | { |
58 | assert(se->ch == NULL); |
59 | assert(ch->se == NULL); |
60 | se->ch = ch; |
61 | ch->se = se; |
62 | } |
63 | |
64 | void fuse_session_remove_chan(struct fuse_chan *ch) |
65 | { |
66 | struct fuse_session *se = ch->se; |
67 | if (se) { |
68 | assert(se->ch == ch); |
69 | se->ch = NULL; |
70 | ch->se = NULL; |
71 | } |
72 | } |
73 | |
74 | struct fuse_chan *fuse_session_next_chan(struct fuse_session *se, |
75 | struct fuse_chan *ch) |
76 | { |
77 | assert(ch == NULL || ch == se->ch); |
78 | if (ch == NULL) |
79 | return se->ch; |
80 | else |
81 | return NULL; |
82 | } |
83 | |
84 | void fuse_session_process(struct fuse_session *se, const char *buf, size_t len, |
85 | struct fuse_chan *ch) |
86 | { |
87 | se->op.process(se->data, buf, len, ch); |
88 | } |
89 | |
90 | void fuse_session_destroy(struct fuse_session *se) |
91 | { |
92 | if (se->op.destroy) |
93 | se->op.destroy(se->data); |
94 | if (se->ch != NULL) |
95 | fuse_chan_destroy(se->ch); |
96 | free(se); |
97 | } |
98 | |
99 | void fuse_session_exit(struct fuse_session *se) |
100 | { |
101 | if (se->op.exit) |
102 | se->op.exit(se->data, 1); |
103 | se->exited = 1; |
104 | } |
105 | |
106 | void fuse_session_reset(struct fuse_session *se) |
107 | { |
108 | if (se->op.exit) |
109 | se->op.exit(se->data, 0); |
110 | se->exited = 0; |
111 | } |
112 | |
113 | int fuse_session_exited(struct fuse_session *se) |
114 | { |
115 | if (se->op.exited) |
116 | return se->op.exited(se->data); |
117 | else |
118 | return se->exited; |
119 | } |
120 | |
121 | static struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd, |
122 | size_t bufsize, void *data) |
123 | { |
124 | struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch)); |
125 | if (ch == NULL) { |
126 | fprintf(stderr, "fuse: failed to allocate channel\n"); |
127 | return NULL; |
128 | } |
129 | |
130 | memset(ch, 0, sizeof(*ch)); |
131 | ch->op = *op; |
132 | ch->fd = fd; |
133 | ch->bufsize = bufsize; |
134 | ch->data = data; |
135 | |
136 | return ch; |
137 | } |
138 | |
139 | struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd, |
140 | size_t bufsize, void *data) |
141 | { |
142 | return fuse_chan_new_common(op, fd, bufsize, data); |
143 | } |
144 | |
145 | int fuse_chan_fd(struct fuse_chan *ch) |
146 | { |
147 | return ch->fd; |
148 | } |
149 | |
150 | size_t fuse_chan_bufsize(struct fuse_chan *ch) |
151 | { |
152 | return ch->bufsize; |
153 | } |
154 | |
155 | void *fuse_chan_data(struct fuse_chan *ch) |
156 | { |
157 | return ch->data; |
158 | } |
159 | |
160 | struct fuse_session *fuse_chan_session(struct fuse_chan *ch) |
161 | { |
162 | return ch->se; |
163 | } |
164 | |
165 | int fuse_chan_recv(struct fuse_chan **chp, char *buf, size_t size) |
166 | { |
167 | struct fuse_chan *ch = *chp; |
168 | |
169 | return ch->op.receive(chp, buf, size); |
170 | } |
171 | |
172 | #ifdef __SOLARIS__ |
173 | int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size) |
174 | { |
175 | int res; |
176 | |
177 | res = fuse_chan_recv(&ch, buf, size); |
178 | return res >= 0 ? res : (res != -EINTR && res != -EAGAIN) ? -1 : 0; |
179 | } |
180 | #endif /* __SOLARIS__ */ |
181 | |
182 | int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], size_t count) |
183 | { |
184 | return ch->op.send(ch, iov, count); |
185 | } |
186 | |
187 | void fuse_chan_destroy(struct fuse_chan *ch) |
188 | { |
189 | fuse_session_remove_chan(ch); |
190 | if (ch->op.destroy) |
191 | ch->op.destroy(ch); |
192 | free(ch); |
193 | } |
194 |