]> git.proxmox.com Git - pve-cluster.git/blob - data/src/cfs-plug.c
3eee161eccdb5a4afe9e2b53da6875d66b40d647
[pve-cluster.git] / data / src / cfs-plug.c
1 /*
2 Copyright (C) 2010 Proxmox Server Solutions GmbH
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Affero General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Affero General Public License for more details.
13
14 You should have received a copy of the GNU Affero General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 Author: Dietmar Maurer <dietmar@proxmox.com>
18
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif /* HAVE_CONFIG_H */
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <glib.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/file.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <dirent.h>
36
37 #include "cfs-utils.h"
38 #include "cfs-plug.h"
39
40 static struct cfs_operations cfs_ops;
41
42 static cfs_plug_t *cfs_plug_base_lookup_plug(cfs_plug_t *plug, char **path)
43 {
44 g_return_val_if_fail(plug != NULL, NULL);
45 g_return_val_if_fail(plug->ops == &cfs_ops, NULL);
46 g_return_val_if_fail(path != NULL, NULL);
47
48 cfs_plug_base_t *bplug = (cfs_plug_base_t *)plug;
49
50 g_return_val_if_fail(bplug->entries != NULL, NULL);
51
52 cfs_debug("cfs_plug_base_lookup_plug %s", *path);
53
54 if (!*path || !(*path)[0])
55 return plug;
56
57 char *name = strsep(path, "/");
58
59 cfs_debug("cfs_plug_base_lookup_plug name = %s new path = %s", name, *path);
60
61 cfs_plug_t *sub;
62
63 if (!(sub = (cfs_plug_t *)g_hash_table_lookup(bplug->entries, name))) {
64 /* revert strsep modification */
65 if (*path) (*path)[-1] = '/';
66 *path = name;
67 return plug;
68 }
69
70 if ((sub = sub->lookup_plug(sub, path)))
71 return sub;
72
73 *path = NULL;
74 return NULL;
75 }
76
77 static int cfs_plug_base_getattr(cfs_plug_t *plug, const char *path, struct stat *stbuf)
78 {
79 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
80 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
81 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
82 g_return_val_if_fail(stbuf != NULL, PARAM_CHECK_ERRNO);
83
84 cfs_debug("enter cfs_plug_base_getattr %s", path);
85
86 int ret = -EACCES;
87
88 memset(stbuf, 0, sizeof(struct stat));
89
90 if (*path) {
91 cfs_plug_t *base = ((cfs_plug_base_t *)plug)->base;
92
93 if (base && base->ops && base->ops->getattr)
94 ret = base->ops->getattr(base, path, stbuf);
95 goto ret;
96 }
97
98 stbuf->st_mode = S_IFDIR | 0777;
99 stbuf->st_nlink = 2;
100 ret = 0;
101
102 ret:
103 cfs_debug("leave cfs_plug_base_getattr %s", path);
104 return ret;
105 }
106
107
108 struct hash_filler {
109 void *buf;
110 GHashTable *entries;
111 fuse_fill_dir_t filler;
112 };
113
114 static int tmp_hash_filler (
115 void *buf,
116 const char *name,
117 const struct stat *stbuf,
118 off_t off) {
119
120 struct hash_filler *hf = (struct hash_filler *)buf;
121
122 if (hf->entries && g_hash_table_lookup(hf->entries, name))
123 return 0;
124
125 if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
126 return 0;
127
128 hf->filler(hf->buf, name, stbuf, off);
129
130 return 0;
131 }
132
133 static int cfs_plug_base_readdir(cfs_plug_t *plug, const char *path, void *buf, fuse_fill_dir_t filler,
134 off_t offset, struct fuse_file_info *fi)
135 {
136 (void) offset;
137 (void) fi;
138
139 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
140 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
141 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
142 g_return_val_if_fail(buf != NULL, PARAM_CHECK_ERRNO);
143 g_return_val_if_fail(filler != NULL, PARAM_CHECK_ERRNO);
144
145 cfs_plug_base_t *bplug = (cfs_plug_base_t *)plug;
146
147 cfs_debug("enter cfs_plug_base_readdir %s", path);
148
149 int ret = -EACCES;
150
151 filler(buf, ".", NULL, 0);
152 filler(buf, "..", NULL, 0);
153
154 if (!path[0]) {
155 GHashTableIter iter;
156 gpointer key, value;
157
158 g_hash_table_iter_init (&iter, bplug->entries);
159
160 while (g_hash_table_iter_next (&iter, &key, &value)) {
161 filler(buf, key, NULL, 0);
162 }
163 }
164
165 cfs_plug_t *base = ((cfs_plug_base_t *)plug)->base;
166
167 if (base && base->ops && base->ops->readdir) {
168 struct hash_filler hf = {
169 .buf = buf,
170 .filler = filler,
171 .entries = NULL
172 };
173
174 if (!path[0])
175 hf.entries = bplug->entries;
176
177 ret = base->ops->readdir(base, path, &hf, tmp_hash_filler, 0, fi);
178
179 } else {
180 ret = 0;
181 }
182
183 return ret;
184 }
185
186 static int cfs_plug_base_mkdir(cfs_plug_t *plug, const char *path, mode_t mode)
187 {
188 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
189 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
190 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
191
192 cfs_debug("enter cfs_plug_base_mkdir %s", path);
193
194 int ret = -EACCES;
195
196 cfs_plug_t *base = ((cfs_plug_base_t *)plug)->base;
197
198 if (*path && base && base->ops && base->ops->mkdir)
199 ret = base->ops->mkdir(base, path, mode);
200
201 return ret;
202 }
203
204 static int cfs_plug_base_rmdir(cfs_plug_t *plug, const char *path)
205 {
206 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
207 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
208 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
209
210 cfs_debug("enter cfs_plug_base_rmdir %s", path);
211
212 int ret = -EACCES;
213
214 cfs_plug_t *base = ((cfs_plug_base_t *)plug)->base;
215
216 if (*path && base && base->ops && base->ops->rmdir)
217 ret = base->ops->rmdir(base, path);
218
219 return ret;
220 }
221
222 static int cfs_plug_base_rename(cfs_plug_t *plug, const char *from, const char *to)
223 {
224 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
225 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
226 g_return_val_if_fail(from != NULL, PARAM_CHECK_ERRNO);
227 g_return_val_if_fail(to != NULL, PARAM_CHECK_ERRNO);
228
229 cfs_debug("enter cfs_plug_base_rename from %s to %s", from, to);
230
231 int ret = -EACCES;
232
233 cfs_plug_t *base = ((cfs_plug_base_t *)plug)->base;
234
235 if (base && base->ops && base->ops->rename)
236 ret = base->ops->rename(base, from, to);
237
238 return ret;
239 }
240
241 static int cfs_plug_base_open(cfs_plug_t *plug, const char *path, struct fuse_file_info *fi)
242 {
243 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
244 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
245 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
246 g_return_val_if_fail(fi != NULL, PARAM_CHECK_ERRNO);
247
248 cfs_debug("enter cfs_plug_base_open %s", path);
249
250 int ret = -EACCES;
251
252 cfs_plug_t *base = ((cfs_plug_base_t *)plug)->base;
253
254 if (base && base->ops && base->ops->open)
255 ret = base->ops->open(base, path, fi);
256
257 return ret;
258 }
259
260 static int cfs_plug_base_read(cfs_plug_t *plug, const char *path, char *buf,
261 size_t size, off_t offset, struct fuse_file_info *fi)
262 {
263 (void) fi;
264
265 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
266 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
267 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
268 g_return_val_if_fail(buf != NULL, PARAM_CHECK_ERRNO);
269 g_return_val_if_fail(fi != NULL, PARAM_CHECK_ERRNO);
270
271 cfs_debug("enter cfs_plug_base_read %s %zu %jd", path, size, offset);
272
273 int ret = -EACCES;
274
275 cfs_plug_t *base = ((cfs_plug_base_t *)plug)->base;
276
277 if (base && base->ops && base->ops->read)
278 ret = base->ops->read(base, path, buf, size, offset, fi);
279
280 return ret;
281 }
282
283 static int cfs_plug_base_write(cfs_plug_t *plug, const char *path, const char *buf,
284 size_t size, off_t offset, struct fuse_file_info *fi)
285 {
286 (void) fi;
287
288 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
289 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
290 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
291 g_return_val_if_fail(buf != NULL, PARAM_CHECK_ERRNO);
292 g_return_val_if_fail(fi != NULL, PARAM_CHECK_ERRNO);
293
294 cfs_debug("enter cfs_plug_base_write %s %zu %jd", path, size, offset);
295
296 int ret = -EACCES;
297
298 cfs_plug_t *base = ((cfs_plug_base_t *)plug)->base;
299
300 if (base && base->ops && base->ops->write)
301 ret = base->ops->write(base, path, buf, size, offset, fi);
302
303 return ret;
304 }
305
306 static int cfs_plug_base_truncate(cfs_plug_t *plug, const char *path, off_t size)
307 {
308 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
309 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
310 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
311
312 cfs_debug("enter cfs_plug_base_truncate %s %jd", path, size);
313
314 int ret = -EACCES;
315
316 cfs_plug_t *base = ((cfs_plug_base_t *)plug)->base;
317
318 if (base && base->ops && base->ops->truncate)
319 ret = base->ops->truncate(base, path, size);
320
321 return ret;
322 }
323
324 static int cfs_plug_base_create(cfs_plug_t *plug, const char *path, mode_t mode,
325 struct fuse_file_info *fi)
326 {
327 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
328 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
329 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
330 g_return_val_if_fail(fi != NULL, PARAM_CHECK_ERRNO);
331
332 cfs_debug("enter cfs_plug_base_create %s", path);
333
334 int ret = -EACCES;
335
336 cfs_plug_t *base = ((cfs_plug_base_t *)plug)->base;
337
338 if (base && base->ops && base->ops->create)
339 ret = base->ops->create(base, path, mode, fi);
340
341 return ret;
342 }
343
344 static int cfs_plug_base_unlink(cfs_plug_t *plug, const char *path)
345 {
346 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
347 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
348 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
349
350 cfs_debug("enter cfs_plug_base_unlink %s", path);
351
352 int ret = -EACCES;
353
354 cfs_plug_t *base = ((cfs_plug_base_t *)plug)->base;
355
356 if (base && base->ops && base->ops->unlink)
357 ret = base->ops->unlink(base, path);
358
359 return ret;
360 }
361
362 static int cfs_plug_base_readlink(cfs_plug_t *plug, const char *path, char *buf, size_t max)
363 {
364 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
365 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
366 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
367 g_return_val_if_fail(buf != NULL, PARAM_CHECK_ERRNO);
368
369 cfs_debug("enter cfs_plug_base_readlink %s", path);
370
371 int ret = -EACCES;
372
373 cfs_plug_t *base = ((cfs_plug_base_t *)plug)->base;
374
375 if (base && base->ops && base->ops->readlink)
376 ret = base->ops->readlink(base, path, buf, max);
377
378 return ret;
379 }
380
381 static int cfs_plug_base_utimens(cfs_plug_t *plug, const char *path, const struct timespec tv[2])
382 {
383 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
384 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
385 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
386 g_return_val_if_fail(tv != NULL, PARAM_CHECK_ERRNO);
387
388 cfs_debug("enter cfs_plug_utimes %s", path);
389
390 int ret = -EACCES;
391
392 cfs_plug_t *base = ((cfs_plug_base_t *)plug)->base;
393
394 if (base && base->ops && base->ops->utimens)
395 ret = base->ops->utimens(base, path, tv);
396
397 return ret;
398 }
399
400 static int cfs_plug_base_statfs(cfs_plug_t *plug, const char *path, struct statvfs *stbuf)
401 {
402 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
403 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
404 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
405 g_return_val_if_fail(stbuf != NULL, PARAM_CHECK_ERRNO);
406
407 cfs_debug("enter cfs_plug_base_statfs %s", path);
408
409 int ret = -EACCES;
410
411 cfs_plug_t *base = ((cfs_plug_base_t *)plug)->base;
412
413 if (base && base->ops && base->ops->statfs)
414 ret = base->ops->statfs(base, path, stbuf);
415
416 return ret;
417 }
418
419 static gboolean plug_remove_func(
420 gpointer key,
421 gpointer value,
422 gpointer user_data)
423 {
424 cfs_plug_t *plug = (cfs_plug_t *)value;
425
426 if (plug && plug->destroy_plug)
427 plug->destroy_plug(plug);
428
429 return TRUE;
430 }
431
432 static void cfs_plug_base_destroy(cfs_plug_t *plug)
433 {
434 g_return_if_fail(plug != NULL);
435 g_return_if_fail(plug->ops == &cfs_ops);
436
437 cfs_plug_base_t *bplug = (cfs_plug_base_t *)plug;
438
439 cfs_debug("enter cfs_plug_base_destroy %s", plug->name);
440
441 if (bplug->entries) {
442 g_hash_table_foreach_remove(bplug->entries, plug_remove_func, NULL);
443 g_hash_table_destroy(bplug->entries);
444 }
445
446 if (bplug->base && bplug->base->destroy_plug) {
447 bplug->base->destroy_plug(bplug->base);
448 }
449
450 g_free(plug->name);
451
452 g_free(plug);
453 }
454
455 static void cfs_plug_base_start_workers(cfs_plug_t *plug)
456 {
457 g_return_if_fail(plug != NULL);
458 g_return_if_fail(plug->ops == &cfs_ops);
459
460 cfs_plug_base_t *bplug = (cfs_plug_base_t *)plug;
461 GHashTableIter iter;
462 gpointer key, value;
463
464 g_hash_table_iter_init (&iter, bplug->entries);
465
466 while (g_hash_table_iter_next (&iter, &key, &value)) {
467
468 cfs_plug_t *p = (cfs_plug_t *)value;
469
470 if (p->start_workers)
471 p->start_workers(p);
472
473 }
474
475 if (bplug->base && bplug->base->start_workers) {
476 bplug->base->start_workers(bplug->base);
477 }
478
479 }
480
481 static void cfs_plug_base_stop_workers(cfs_plug_t *plug)
482 {
483 g_return_if_fail(plug != NULL);
484 g_return_if_fail(plug->ops == &cfs_ops);
485
486 cfs_plug_base_t *bplug = (cfs_plug_base_t *)plug;
487 GHashTableIter iter;
488 gpointer key, value;
489
490 g_hash_table_iter_init (&iter, bplug->entries);
491
492 if (bplug->base && bplug->base->stop_workers) {
493 bplug->base->stop_workers(bplug->base);
494 }
495
496 while (g_hash_table_iter_next (&iter, &key, &value)) {
497
498 cfs_plug_t *p = (cfs_plug_t *)value;
499
500 if (p->stop_workers)
501 p->stop_workers(p);
502
503 }
504 }
505
506 static struct cfs_operations cfs_ops = {
507 .getattr = cfs_plug_base_getattr,
508 .create = cfs_plug_base_create,
509 .open = cfs_plug_base_open,
510 .read = cfs_plug_base_read,
511 .write = cfs_plug_base_write,
512 .truncate = cfs_plug_base_truncate,
513 .unlink = cfs_plug_base_unlink,
514 .readdir = cfs_plug_base_readdir,
515 .mkdir = cfs_plug_base_mkdir,
516 .rmdir = cfs_plug_base_rmdir,
517 .rename = cfs_plug_base_rename,
518 .readlink = cfs_plug_base_readlink,
519 .utimens = cfs_plug_base_utimens,
520 .statfs = cfs_plug_base_statfs,
521 };
522
523 cfs_plug_base_t *cfs_plug_base_new(const char *name, cfs_plug_t *base)
524 {
525 g_return_val_if_fail(name != NULL, NULL);
526 g_return_val_if_fail(base != NULL, NULL);
527
528 cfs_plug_base_t *plug = g_new0(cfs_plug_base_t, 1);
529
530 plug->plug.lookup_plug = cfs_plug_base_lookup_plug;
531 plug->plug.destroy_plug = cfs_plug_base_destroy;
532 plug->plug.start_workers = cfs_plug_base_start_workers;
533 plug->plug.stop_workers = cfs_plug_base_stop_workers;
534
535 plug->entries = g_hash_table_new(g_str_hash, g_str_equal);
536
537 plug->plug.name = g_strdup(name);
538
539 plug->plug.ops = &cfs_ops;
540
541 plug->base = base;
542
543 return plug;
544 }
545
546 void cfs_plug_base_insert(cfs_plug_base_t *bplug, cfs_plug_t *sub)
547 {
548 g_return_if_fail(bplug != NULL);
549 g_return_if_fail(sub != NULL);
550 g_return_if_fail(sub->name != NULL);
551
552 g_hash_table_replace(bplug->entries, sub->name, sub);
553 }