1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include "qemu/osdep.h"
20#include "fsdev/qemu-fsdev.h"
21#include "qemu/thread.h"
22#include "qemu/coroutine.h"
23#include "qemu/main-loop.h"
24#include "coth.h"
25
26
27
28
29
30static int do_readdir(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent **dent)
31{
32 int err = 0;
33 V9fsState *s = pdu->s;
34 struct dirent *entry;
35
36 errno = 0;
37 entry = s->ops->readdir(&s->ctx, &fidp->fs);
38 if (!entry && errno) {
39 *dent = NULL;
40 err = -errno;
41 } else {
42 *dent = entry;
43 }
44 return err;
45}
46
47
48
49
50
51int coroutine_fn v9fs_co_readdir(V9fsPDU *pdu, V9fsFidState *fidp,
52 struct dirent **dent)
53{
54 int err;
55
56 if (v9fs_request_cancelled(pdu)) {
57 return -EINTR;
58 }
59 v9fs_co_run_in_worker({
60 err = do_readdir(pdu, fidp, dent);
61 });
62 return err;
63}
64
65
66
67
68
69
70static int do_readdir_many(V9fsPDU *pdu, V9fsFidState *fidp,
71 struct V9fsDirEnt **entries, off_t offset,
72 int32_t maxsize, bool dostat)
73{
74 V9fsState *s = pdu->s;
75 V9fsString name;
76 int len, err = 0;
77 int32_t size = 0;
78 off_t saved_dir_pos;
79 struct dirent *dent;
80 struct V9fsDirEnt *e = NULL;
81 V9fsPath path;
82 struct stat stbuf;
83
84 *entries = NULL;
85 v9fs_path_init(&path);
86
87
88
89
90
91
92
93
94
95
96 v9fs_readdir_lock(&fidp->fs.dir);
97
98
99 if (offset == 0) {
100 s->ops->rewinddir(&s->ctx, &fidp->fs);
101 } else {
102 s->ops->seekdir(&s->ctx, &fidp->fs, offset);
103 }
104
105
106 saved_dir_pos = s->ops->telldir(&s->ctx, &fidp->fs);
107 if (saved_dir_pos < 0) {
108 err = saved_dir_pos;
109 goto out;
110 }
111
112 while (true) {
113
114 if (v9fs_request_cancelled(pdu)) {
115 err = -EINTR;
116 break;
117 }
118
119
120 err = do_readdir(pdu, fidp, &dent);
121 if (err || !dent) {
122 break;
123 }
124
125
126
127
128
129
130
131 v9fs_string_init(&name);
132 v9fs_string_sprintf(&name, "%s", dent->d_name);
133 len = v9fs_readdir_response_size(&name);
134 v9fs_string_free(&name);
135 if (size + len > maxsize) {
136
137 break;
138 }
139
140
141 if (!e) {
142 *entries = e = g_malloc0(sizeof(V9fsDirEnt));
143 } else {
144 e = e->next = g_malloc0(sizeof(V9fsDirEnt));
145 }
146 e->dent = g_malloc0(sizeof(struct dirent));
147 memcpy(e->dent, dent, sizeof(struct dirent));
148
149
150 if (dostat) {
151 err = s->ops->name_to_path(
152 &s->ctx, &fidp->path, dent->d_name, &path
153 );
154 if (err < 0) {
155 err = -errno;
156 break;
157 }
158
159 err = s->ops->lstat(&s->ctx, &path, &stbuf);
160 if (err < 0) {
161 err = -errno;
162 break;
163 }
164
165 e->st = g_malloc0(sizeof(struct stat));
166 memcpy(e->st, &stbuf, sizeof(struct stat));
167 }
168
169 size += len;
170 saved_dir_pos = dent->d_off;
171 }
172
173
174 s->ops->seekdir(&s->ctx, &fidp->fs, saved_dir_pos);
175
176out:
177 v9fs_readdir_unlock(&fidp->fs.dir);
178 v9fs_path_free(&path);
179 if (err < 0) {
180 return err;
181 }
182 return size;
183}
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216int coroutine_fn v9fs_co_readdir_many(V9fsPDU *pdu, V9fsFidState *fidp,
217 struct V9fsDirEnt **entries,
218 off_t offset, int32_t maxsize,
219 bool dostat)
220{
221 int err = 0;
222
223 if (v9fs_request_cancelled(pdu)) {
224 return -EINTR;
225 }
226 v9fs_co_run_in_worker({
227 err = do_readdir_many(pdu, fidp, entries, offset, maxsize, dostat);
228 });
229 return err;
230}
231
232off_t v9fs_co_telldir(V9fsPDU *pdu, V9fsFidState *fidp)
233{
234 off_t err;
235 V9fsState *s = pdu->s;
236
237 if (v9fs_request_cancelled(pdu)) {
238 return -EINTR;
239 }
240 v9fs_co_run_in_worker(
241 {
242 err = s->ops->telldir(&s->ctx, &fidp->fs);
243 if (err < 0) {
244 err = -errno;
245 }
246 });
247 return err;
248}
249
250void coroutine_fn v9fs_co_seekdir(V9fsPDU *pdu, V9fsFidState *fidp,
251 off_t offset)
252{
253 V9fsState *s = pdu->s;
254 if (v9fs_request_cancelled(pdu)) {
255 return;
256 }
257 v9fs_co_run_in_worker(
258 {
259 s->ops->seekdir(&s->ctx, &fidp->fs, offset);
260 });
261}
262
263void coroutine_fn v9fs_co_rewinddir(V9fsPDU *pdu, V9fsFidState *fidp)
264{
265 V9fsState *s = pdu->s;
266 if (v9fs_request_cancelled(pdu)) {
267 return;
268 }
269 v9fs_co_run_in_worker(
270 {
271 s->ops->rewinddir(&s->ctx, &fidp->fs);
272 });
273}
274
275int coroutine_fn v9fs_co_mkdir(V9fsPDU *pdu, V9fsFidState *fidp,
276 V9fsString *name, mode_t mode, uid_t uid,
277 gid_t gid, struct stat *stbuf)
278{
279 int err;
280 FsCred cred;
281 V9fsPath path;
282 V9fsState *s = pdu->s;
283
284 if (v9fs_request_cancelled(pdu)) {
285 return -EINTR;
286 }
287 cred_init(&cred);
288 cred.fc_mode = mode;
289 cred.fc_uid = uid;
290 cred.fc_gid = gid;
291 v9fs_path_read_lock(s);
292 v9fs_co_run_in_worker(
293 {
294 err = s->ops->mkdir(&s->ctx, &fidp->path, name->data, &cred);
295 if (err < 0) {
296 err = -errno;
297 } else {
298 v9fs_path_init(&path);
299 err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
300 if (!err) {
301 err = s->ops->lstat(&s->ctx, &path, stbuf);
302 if (err < 0) {
303 err = -errno;
304 }
305 }
306 v9fs_path_free(&path);
307 }
308 });
309 v9fs_path_unlock(s);
310 return err;
311}
312
313int coroutine_fn v9fs_co_opendir(V9fsPDU *pdu, V9fsFidState *fidp)
314{
315 int err;
316 V9fsState *s = pdu->s;
317
318 if (v9fs_request_cancelled(pdu)) {
319 return -EINTR;
320 }
321 v9fs_path_read_lock(s);
322 v9fs_co_run_in_worker(
323 {
324 err = s->ops->opendir(&s->ctx, &fidp->path, &fidp->fs);
325 if (err < 0) {
326 err = -errno;
327 } else {
328 err = 0;
329 }
330 });
331 v9fs_path_unlock(s);
332 if (!err) {
333 total_open_fd++;
334 if (total_open_fd > open_fd_hw) {
335 v9fs_reclaim_fd(pdu);
336 }
337 }
338 return err;
339}
340
341int coroutine_fn v9fs_co_closedir(V9fsPDU *pdu, V9fsFidOpenState *fs)
342{
343 int err;
344 V9fsState *s = pdu->s;
345
346 if (v9fs_request_cancelled(pdu)) {
347 return -EINTR;
348 }
349 v9fs_co_run_in_worker(
350 {
351 err = s->ops->closedir(&s->ctx, fs);
352 if (err < 0) {
353 err = -errno;
354 }
355 });
356 if (!err) {
357 total_open_fd--;
358 }
359 return err;
360}
361