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>
36 #include <arpa/inet.h>
38 #include "cfs-utils.h"
39 #include "cfs-plug-memdb.h"
43 static struct cfs_operations cfs_ops
;
45 static void tree_entry_stat(memdb_tree_entry_t
*te
, struct stat
*stbuf
, gboolean quorate
)
47 g_return_if_fail(te
!= NULL
);
48 g_return_if_fail(stbuf
!= NULL
);
50 if (te
->type
== DT_DIR
) {
51 stbuf
->st_mode
= S_IFDIR
| (quorate
? 0777 : 0555);
54 stbuf
->st_mode
= S_IFREG
| (quorate
? 0666 : 0444);
58 stbuf
->st_size
= te
->size
;
60 (stbuf
->st_size
+ MEMDB_BLOCKSIZE
-1)/MEMDB_BLOCKSIZE
;
61 stbuf
->st_atime
= te
->mtime
;
62 stbuf
->st_mtime
= te
->mtime
;
63 stbuf
->st_ctime
= te
->mtime
;
66 static int cfs_plug_memdb_getattr(cfs_plug_t
*plug
, const char *path
, struct stat
*stbuf
)
68 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
69 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
70 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
71 g_return_val_if_fail(stbuf
!= NULL
, PARAM_CHECK_ERRNO
);
73 memset(stbuf
, 0, sizeof(struct stat
));
75 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
77 memdb_tree_entry_t
*te
= memdb_getattr(mdb
->memdb
, path
);
80 tree_entry_stat(te
, stbuf
, cfs_is_quorate());
88 static int cfs_plug_memdb_readdir(
92 fuse_fill_dir_t filler
,
94 struct fuse_file_info
*fi
)
99 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
100 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
101 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
102 g_return_val_if_fail(buf
!= NULL
, PARAM_CHECK_ERRNO
);
103 g_return_val_if_fail(filler
!= NULL
, PARAM_CHECK_ERRNO
);
105 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
107 GList
*dirlist
= memdb_readdir(mdb
->memdb
, path
);
111 filler(buf
, ".", NULL
, 0);
112 filler(buf
, "..", NULL
, 0);
115 memset(&stbuf
, 0, sizeof(struct stat
));
119 memdb_tree_entry_t
*te
= (memdb_tree_entry_t
*)l
->data
;
121 tree_entry_stat(te
, &stbuf
, 0);
122 filler(buf
, te
->name
, &stbuf
, 0);
126 memdb_dirlist_free(dirlist
);
132 static int cfs_plug_memdb_open(cfs_plug_t
*plug
, const char *path
, struct fuse_file_info
*fi
)
134 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
135 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
136 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
137 g_return_val_if_fail(fi
!= NULL
, PARAM_CHECK_ERRNO
);
139 memdb_tree_entry_t
*te
;
141 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
143 if ((te
= memdb_getattr(mdb
->memdb
, path
))) {
151 static int cfs_plug_memdb_read(
157 struct fuse_file_info
*fi
)
161 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
162 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
163 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
164 g_return_val_if_fail(buf
!= NULL
, PARAM_CHECK_ERRNO
);
167 gpointer data
= NULL
;
169 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
171 len
= memdb_read(mdb
->memdb
, path
, &data
);
176 if (offset
+ size
> len
)
178 memcpy(buf
, data
+ offset
, size
);
189 static int cfs_plug_memdb_write(
195 struct fuse_file_info
*fi
)
199 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
200 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
201 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
202 g_return_val_if_fail(buf
!= NULL
, PARAM_CHECK_ERRNO
);
206 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
209 res
= dcdb_send_fuse_message(mdb
->dfsm
, DCDB_MESSAGE_CFS_WRITE
, path
, NULL
, buf
,
212 uint32_t ctime
= time(NULL
);
213 res
= memdb_write(mdb
->memdb
, path
, 0, ctime
, buf
, size
, offset
, 0);
219 static int cfs_plug_memdb_truncate(cfs_plug_t
*plug
, const char *path
, off_t size
)
221 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
222 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
223 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
227 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
230 res
= dcdb_send_fuse_message(mdb
->dfsm
, DCDB_MESSAGE_CFS_WRITE
, path
, NULL
, NULL
,
233 uint32_t ctime
= time(NULL
);
234 res
= memdb_write(mdb
->memdb
, path
, 0, ctime
, NULL
, 0, size
, 1);
240 static int cfs_plug_memdb_create (
244 struct fuse_file_info
*fi
)
246 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
247 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
248 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
249 g_return_val_if_fail(fi
!= NULL
, PARAM_CHECK_ERRNO
);
253 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
256 res
= dcdb_send_fuse_message(mdb
->dfsm
, DCDB_MESSAGE_CFS_CREATE
, path
,
257 NULL
, NULL
, 0, 0, 0);
259 uint32_t ctime
= time(NULL
);
261 res
= memdb_create(mdb
->memdb
, path
, 0, ctime
);
267 static int cfs_plug_memdb_mkdir(cfs_plug_t
*plug
, const char *path
, mode_t mode
)
269 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
270 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
271 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
275 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
278 res
= dcdb_send_fuse_message(mdb
->dfsm
, DCDB_MESSAGE_CFS_MKDIR
, path
,
279 NULL
, NULL
, 0, 0, 0);
281 uint32_t ctime
= time(NULL
);
282 res
= memdb_mkdir(mdb
->memdb
, path
, 0, ctime
);
288 static int cfs_plug_memdb_rmdir(cfs_plug_t
*plug
, const char *path
)
290 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
291 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
292 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
296 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
299 res
= dcdb_send_fuse_message(mdb
->dfsm
, DCDB_MESSAGE_CFS_DELETE
, path
,
300 NULL
, NULL
, 0, 0, 0);
302 uint32_t ctime
= time(NULL
);
303 res
= memdb_delete(mdb
->memdb
, path
, 0, ctime
);
309 static int cfs_plug_memdb_rename(cfs_plug_t
*plug
, const char *from
, const char *to
)
311 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
312 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
313 g_return_val_if_fail(from
!= NULL
, PARAM_CHECK_ERRNO
);
314 g_return_val_if_fail(to
!= NULL
, PARAM_CHECK_ERRNO
);
318 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
321 res
= dcdb_send_fuse_message(mdb
->dfsm
, DCDB_MESSAGE_CFS_RENAME
, from
, to
,
324 uint32_t ctime
= time(NULL
);
325 res
= memdb_rename(mdb
->memdb
, from
, to
, 0, ctime
);
331 static int cfs_plug_memdb_unlink(cfs_plug_t
*plug
, const char *path
)
333 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
334 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
335 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
339 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
342 res
= dcdb_send_fuse_message(mdb
->dfsm
, DCDB_MESSAGE_CFS_DELETE
, path
,
343 NULL
, NULL
, 0, 0, 0);
345 uint32_t ctime
= time(NULL
);
346 res
= memdb_delete(mdb
->memdb
, path
, 0, ctime
);
352 static int cfs_plug_memdb_utimens(
355 const struct timespec tv
[2])
357 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
358 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
359 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
360 g_return_val_if_fail(tv
!= NULL
, PARAM_CHECK_ERRNO
);
364 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
368 memdb_tree_entry_t
*te
= memdb_getattr(mdb
->memdb
, path
);
369 uint32_t mtime
= tv
[1].tv_sec
;
371 gboolean unlock_req
= FALSE
;
374 if (te
&& mtime
== 0 && te
->type
== DT_DIR
&&
375 path_is_lockdir(path
)) {
380 if (unlock_req
&& memdb_tree_entry_csum(te
, csum
))
381 dcdb_send_unlock(mdb
->dfsm
, path
, csum
, TRUE
);
383 res
= dcdb_send_fuse_message(mdb
->dfsm
, DCDB_MESSAGE_CFS_MTIME
, path
,
384 NULL
, NULL
, 0, mtime
, 0);
386 uint32_t ctime
= time(NULL
);
387 if (unlock_req
&& memdb_tree_entry_csum(te
, csum
) &&
388 memdb_lock_expired(mdb
->memdb
, path
, csum
)) {
389 res
= memdb_delete(mdb
->memdb
, path
, 0, ctime
);
391 res
= memdb_mtime(mdb
->memdb
, path
, 0, mtime
);
401 static int cfs_plug_memdb_statfs(cfs_plug_t
*plug
, const char *path
, struct statvfs
*stbuf
)
403 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
404 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
405 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
406 g_return_val_if_fail(stbuf
!= NULL
, PARAM_CHECK_ERRNO
);
408 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
410 return memdb_statfs(mdb
->memdb
, stbuf
);
413 static void cfs_plug_memdb_destroy(cfs_plug_t
*plug
)
415 g_return_if_fail(plug
!= NULL
);
416 g_return_if_fail(plug
->ops
== &cfs_ops
);
423 static cfs_plug_t
*cfs_plug_memdb_lookup_plug(cfs_plug_t
*plug
, char **path
)
425 g_return_val_if_fail(plug
!= NULL
, NULL
);
426 g_return_val_if_fail(plug
->ops
== &cfs_ops
, NULL
);
431 static struct cfs_operations cfs_ops
= {
432 .getattr
= cfs_plug_memdb_getattr
,
433 .readdir
= cfs_plug_memdb_readdir
,
434 .open
= cfs_plug_memdb_open
,
435 .create
= cfs_plug_memdb_create
,
436 .read
= cfs_plug_memdb_read
,
437 .write
= cfs_plug_memdb_write
,
438 .truncate
= cfs_plug_memdb_truncate
,
439 .unlink
= cfs_plug_memdb_unlink
,
440 .mkdir
= cfs_plug_memdb_mkdir
,
441 .rmdir
= cfs_plug_memdb_rmdir
,
442 .rename
= cfs_plug_memdb_rename
,
443 .utimens
= cfs_plug_memdb_utimens
,
444 .statfs
= cfs_plug_memdb_statfs
,
445 #ifdef HAS_CFS_PLUG_MEMDB_LOCK
446 .lock
= cfs_plug_memdb_lock
,
450 cfs_plug_memdb_t
*cfs_plug_memdb_new(
455 g_return_val_if_fail(name
!= NULL
, NULL
);
456 g_return_val_if_fail(memdb
!= NULL
, NULL
);
458 cfs_plug_memdb_t
*mdb
= g_new0(cfs_plug_memdb_t
, 1);
460 g_return_val_if_fail(mdb
!= NULL
, NULL
);
462 mdb
->plug
.ops
= &cfs_ops
;
464 mdb
->plug
.lookup_plug
= cfs_plug_memdb_lookup_plug
;
466 mdb
->plug
.destroy_plug
= cfs_plug_memdb_destroy
;
468 mdb
->plug
.name
= g_strdup(name
);