2 Copyright (C) 2010 Proxmox Server Solutions GmbH
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.
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.
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/>.
17 Author: Dietmar Maurer <dietmar@proxmox.com>
23 #endif /* HAVE_CONFIG_H */
30 #include <sys/types.h>
37 #include "cfs-utils.h"
40 static struct cfs_operations cfs_ops
;
42 static cfs_plug_t
*cfs_plug_base_lookup_plug(cfs_plug_t
*plug
, char **path
)
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
);
48 cfs_plug_base_t
*bplug
= (cfs_plug_base_t
*)plug
;
50 g_return_val_if_fail(bplug
->entries
!= NULL
, NULL
);
52 cfs_debug("cfs_plug_base_lookup_plug %s", *path
);
54 if (!*path
|| !(*path
)[0])
57 char *name
= strsep(path
, "/");
59 cfs_debug("cfs_plug_base_lookup_plug name = %s new path = %s", name
, *path
);
63 if (!(sub
= (cfs_plug_t
*)g_hash_table_lookup(bplug
->entries
, name
))) {
64 /* revert strsep modification */
65 if (*path
) (*path
)[-1] = '/';
70 if ((sub
= sub
->lookup_plug(sub
, path
)))
77 static int cfs_plug_base_getattr(cfs_plug_t
*plug
, const char *path
, struct stat
*stbuf
)
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
);
84 cfs_debug("enter cfs_plug_base_getattr %s", path
);
88 memset(stbuf
, 0, sizeof(struct stat
));
91 cfs_plug_t
*base
= ((cfs_plug_base_t
*)plug
)->base
;
93 if (base
&& base
->ops
&& base
->ops
->getattr
)
94 ret
= base
->ops
->getattr(base
, path
, stbuf
);
98 stbuf
->st_mode
= S_IFDIR
| 0777;
103 cfs_debug("leave cfs_plug_base_getattr %s", path
);
111 fuse_fill_dir_t filler
;
114 static int tmp_hash_filler (
117 const struct stat
*stbuf
,
120 struct hash_filler
*hf
= (struct hash_filler
*)buf
;
122 if (hf
->entries
&& g_hash_table_lookup(hf
->entries
, name
))
125 if (name
[0] == '.' && (name
[1] == 0 || (name
[1] == '.' && name
[2] == 0)))
128 hf
->filler(hf
->buf
, name
, stbuf
, off
);
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
)
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
);
145 cfs_plug_base_t
*bplug
= (cfs_plug_base_t
*)plug
;
147 cfs_debug("enter cfs_plug_base_readdir %s", path
);
151 filler(buf
, ".", NULL
, 0);
152 filler(buf
, "..", NULL
, 0);
158 g_hash_table_iter_init (&iter
, bplug
->entries
);
160 while (g_hash_table_iter_next (&iter
, &key
, &value
)) {
161 filler(buf
, key
, NULL
, 0);
165 cfs_plug_t
*base
= ((cfs_plug_base_t
*)plug
)->base
;
167 if (base
&& base
->ops
&& base
->ops
->readdir
) {
168 struct hash_filler hf
= {
175 hf
.entries
= bplug
->entries
;
177 ret
= base
->ops
->readdir(base
, path
, &hf
, tmp_hash_filler
, 0, fi
);
186 static int cfs_plug_base_mkdir(cfs_plug_t
*plug
, const char *path
, mode_t mode
)
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
);
192 cfs_debug("enter cfs_plug_base_mkdir %s", path
);
196 cfs_plug_t
*base
= ((cfs_plug_base_t
*)plug
)->base
;
198 if (*path
&& base
&& base
->ops
&& base
->ops
->mkdir
)
199 ret
= base
->ops
->mkdir(base
, path
, mode
);
204 static int cfs_plug_base_rmdir(cfs_plug_t
*plug
, const char *path
)
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
);
210 cfs_debug("enter cfs_plug_base_rmdir %s", path
);
214 cfs_plug_t
*base
= ((cfs_plug_base_t
*)plug
)->base
;
216 if (*path
&& base
&& base
->ops
&& base
->ops
->rmdir
)
217 ret
= base
->ops
->rmdir(base
, path
);
222 static int cfs_plug_base_rename(cfs_plug_t
*plug
, const char *from
, const char *to
)
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
);
229 cfs_debug("enter cfs_plug_base_rename from %s to %s", from
, to
);
233 cfs_plug_t
*base
= ((cfs_plug_base_t
*)plug
)->base
;
235 if (base
&& base
->ops
&& base
->ops
->rename
)
236 ret
= base
->ops
->rename(base
, from
, to
);
241 static int cfs_plug_base_open(cfs_plug_t
*plug
, const char *path
, struct fuse_file_info
*fi
)
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
);
248 cfs_debug("enter cfs_plug_base_open %s", path
);
252 cfs_plug_t
*base
= ((cfs_plug_base_t
*)plug
)->base
;
254 if (base
&& base
->ops
&& base
->ops
->open
)
255 ret
= base
->ops
->open(base
, path
, fi
);
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
)
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
);
271 cfs_debug("enter cfs_plug_base_read %s %zu %jd", path
, size
, offset
);
275 cfs_plug_t
*base
= ((cfs_plug_base_t
*)plug
)->base
;
277 if (base
&& base
->ops
&& base
->ops
->read
)
278 ret
= base
->ops
->read(base
, path
, buf
, size
, offset
, fi
);
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
)
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
);
294 cfs_debug("enter cfs_plug_base_write %s %zu %jd", path
, size
, offset
);
298 cfs_plug_t
*base
= ((cfs_plug_base_t
*)plug
)->base
;
300 if (base
&& base
->ops
&& base
->ops
->write
)
301 ret
= base
->ops
->write(base
, path
, buf
, size
, offset
, fi
);
306 static int cfs_plug_base_truncate(cfs_plug_t
*plug
, const char *path
, off_t size
)
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
);
312 cfs_debug("enter cfs_plug_base_truncate %s %jd", path
, size
);
316 cfs_plug_t
*base
= ((cfs_plug_base_t
*)plug
)->base
;
318 if (base
&& base
->ops
&& base
->ops
->truncate
)
319 ret
= base
->ops
->truncate(base
, path
, size
);
324 static int cfs_plug_base_create(cfs_plug_t
*plug
, const char *path
, mode_t mode
,
325 struct fuse_file_info
*fi
)
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
);
332 cfs_debug("enter cfs_plug_base_create %s", path
);
336 cfs_plug_t
*base
= ((cfs_plug_base_t
*)plug
)->base
;
338 if (base
&& base
->ops
&& base
->ops
->create
)
339 ret
= base
->ops
->create(base
, path
, mode
, fi
);
344 static int cfs_plug_base_unlink(cfs_plug_t
*plug
, const char *path
)
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
);
350 cfs_debug("enter cfs_plug_base_unlink %s", path
);
354 cfs_plug_t
*base
= ((cfs_plug_base_t
*)plug
)->base
;
356 if (base
&& base
->ops
&& base
->ops
->unlink
)
357 ret
= base
->ops
->unlink(base
, path
);
362 static int cfs_plug_base_readlink(cfs_plug_t
*plug
, const char *path
, char *buf
, size_t max
)
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
);
369 cfs_debug("enter cfs_plug_base_readlink %s", path
);
373 cfs_plug_t
*base
= ((cfs_plug_base_t
*)plug
)->base
;
375 if (base
&& base
->ops
&& base
->ops
->readlink
)
376 ret
= base
->ops
->readlink(base
, path
, buf
, max
);
381 static int cfs_plug_base_utimens(cfs_plug_t
*plug
, const char *path
, const struct timespec tv
[2])
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
);
388 cfs_debug("enter cfs_plug_utimes %s", path
);
392 cfs_plug_t
*base
= ((cfs_plug_base_t
*)plug
)->base
;
394 if (base
&& base
->ops
&& base
->ops
->utimens
)
395 ret
= base
->ops
->utimens(base
, path
, tv
);
400 static int cfs_plug_base_statfs(cfs_plug_t
*plug
, const char *path
, struct statvfs
*stbuf
)
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
);
407 cfs_debug("enter cfs_plug_base_statfs %s", path
);
411 cfs_plug_t
*base
= ((cfs_plug_base_t
*)plug
)->base
;
413 if (base
&& base
->ops
&& base
->ops
->statfs
)
414 ret
= base
->ops
->statfs(base
, path
, stbuf
);
419 static gboolean
plug_remove_func(
424 cfs_plug_t
*plug
= (cfs_plug_t
*)value
;
426 if (plug
&& plug
->destroy_plug
)
427 plug
->destroy_plug(plug
);
432 static void cfs_plug_base_destroy(cfs_plug_t
*plug
)
434 g_return_if_fail(plug
!= NULL
);
435 g_return_if_fail(plug
->ops
== &cfs_ops
);
437 cfs_plug_base_t
*bplug
= (cfs_plug_base_t
*)plug
;
439 cfs_debug("enter cfs_plug_base_destroy %s", plug
->name
);
441 if (bplug
->entries
) {
442 g_hash_table_foreach_remove(bplug
->entries
, plug_remove_func
, NULL
);
443 g_hash_table_destroy(bplug
->entries
);
446 if (bplug
->base
&& bplug
->base
->destroy_plug
) {
447 bplug
->base
->destroy_plug(bplug
->base
);
455 static void cfs_plug_base_start_workers(cfs_plug_t
*plug
)
457 g_return_if_fail(plug
!= NULL
);
458 g_return_if_fail(plug
->ops
== &cfs_ops
);
460 cfs_plug_base_t
*bplug
= (cfs_plug_base_t
*)plug
;
464 g_hash_table_iter_init (&iter
, bplug
->entries
);
466 while (g_hash_table_iter_next (&iter
, &key
, &value
)) {
468 cfs_plug_t
*p
= (cfs_plug_t
*)value
;
470 if (p
->start_workers
)
475 if (bplug
->base
&& bplug
->base
->start_workers
) {
476 bplug
->base
->start_workers(bplug
->base
);
481 static void cfs_plug_base_stop_workers(cfs_plug_t
*plug
)
483 g_return_if_fail(plug
!= NULL
);
484 g_return_if_fail(plug
->ops
== &cfs_ops
);
486 cfs_plug_base_t
*bplug
= (cfs_plug_base_t
*)plug
;
490 g_hash_table_iter_init (&iter
, bplug
->entries
);
492 if (bplug
->base
&& bplug
->base
->stop_workers
) {
493 bplug
->base
->stop_workers(bplug
->base
);
496 while (g_hash_table_iter_next (&iter
, &key
, &value
)) {
498 cfs_plug_t
*p
= (cfs_plug_t
*)value
;
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
,
523 cfs_plug_base_t
*cfs_plug_base_new(const char *name
, cfs_plug_t
*base
)
525 g_return_val_if_fail(name
!= NULL
, NULL
);
526 g_return_val_if_fail(base
!= NULL
, NULL
);
528 cfs_plug_base_t
*plug
= g_new0(cfs_plug_base_t
, 1);
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
;
535 plug
->entries
= g_hash_table_new(g_str_hash
, g_str_equal
);
537 plug
->plug
.name
= g_strdup(name
);
539 plug
->plug
.ops
= &cfs_ops
;
546 void cfs_plug_base_insert(cfs_plug_base_t
*bplug
, cfs_plug_t
*sub
)
548 g_return_if_fail(bplug
!= NULL
);
549 g_return_if_fail(sub
!= NULL
);
550 g_return_if_fail(sub
->name
!= NULL
);
552 g_hash_table_replace(bplug
->entries
, sub
->name
, sub
);