]> git.proxmox.com Git - pve-cluster.git/blame - data/src/memdb.c
add check for int overflow on vmids
[pve-cluster.git] / data / src / memdb.c
CommitLineData
fe000966
DM
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 <stdio.h>
26#include <stdlib.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <fcntl.h>
30#include <sys/file.h>
31#include <unistd.h>
32#include <dirent.h>
33#include <string.h>
34#include <errno.h>
35#include <glib.h>
36
37#include "cfs-utils.h"
38#include "memdb.h"
39#include "status.h"
40
41#define CFS_LOCK_TIMEOUT (60*2)
42
43memdb_tree_entry_t *
44memdb_tree_entry_new(
45 const char *name)
46{
47 g_return_val_if_fail(name != NULL, NULL);
48
49 memdb_tree_entry_t *te = g_malloc0(sizeof(memdb_tree_entry_t) + strlen(name) + 1);
50 g_return_val_if_fail(te != NULL, NULL);
51
52 strcpy(te->name, name);
53
54 return te;
55}
56
57memdb_tree_entry_t *
58memdb_tree_entry_copy(
59 memdb_tree_entry_t *te,
60 gboolean with_data)
61{
62 g_return_val_if_fail(te != NULL, NULL);
63
64 memdb_tree_entry_t *cpy = memdb_tree_entry_new(te->name);
65
66 cpy->parent = te->parent;
67 cpy->inode = te->inode;
68 cpy->version = te->version;
69 cpy->writer = te->writer;
70 cpy->mtime = te->mtime;
71 cpy->type = te->type;
72 cpy->size = te->size;
73
74 if (with_data && te->size && te->type == DT_REG) {
75 cpy->data.value = g_memdup(te->data.value, te->size);
76 } else {
77 cpy->data.value = NULL;
78 }
79
80 return cpy;
81}
82
83void
84memdb_tree_entry_free(
85 memdb_tree_entry_t *te)
86{
87 g_return_if_fail(te != NULL);
88
89 if (te->type == DT_REG) {
90 if (te->data.value)
91 g_free(te->data.value);
92 }
93
94 if (te->type == DT_DIR) {
95 if (te->data.entries)
96 g_hash_table_destroy(te->data.entries);
97 }
98
99 g_free(te);
100}
101
102void
103memdb_lock_info_free(memdb_lock_info_t *li)
104{
105 g_return_if_fail(li != NULL);
106
107 if (li->path)
108 g_free(li->path);
109
110 g_free(li);
111}
112
113static gint
114memdb_tree_compare(
115 gconstpointer v1,
116 gconstpointer v2)
117{
118 guint64 a = ((const memdb_tree_entry_t *)v1)->inode;
119 guint64 b = ((const memdb_tree_entry_t *)v2)->inode;
120
121 if (a == b)
122 return 0;
123
124 if (a > b)
125 return 1;
126
127 return -1;
128}
129
130static void
131split_path(
132 const char *path,
133 char **dirname,
134 char **basename)
135{
136 char *dup = g_strdup (path);
137 int len = strlen (dup) - 1;
138 while (len >= 0 && dup[len] == '/') dup[len--] = 0;
139
140 char *dn = g_path_get_dirname (dup);
141 char *bn = g_path_get_basename (dup);
142
143 g_free (dup);
144
145 *dirname = dn;
146 *basename = bn;
147}
148
149static memdb_tree_entry_t *
150memdb_lookup_dir_entry(
151 memdb_t *memdb,
152 const char *name,
153 memdb_tree_entry_t *parent)
154{
155
156 g_return_val_if_fail(memdb != NULL, NULL);
157 g_return_val_if_fail(name != NULL, NULL);
158 g_return_val_if_fail(parent != NULL, NULL);
159 g_return_val_if_fail(parent->type == DT_DIR, NULL);
160
161 GHashTable *ht = parent->data.entries;
162
163 g_return_val_if_fail(ht != NULL, NULL);
164
165 return g_hash_table_lookup(ht, name);
166}
167
168static memdb_tree_entry_t *
169memdb_lookup_path(
170 memdb_t *memdb,
171 const char *path,
172 memdb_tree_entry_t **parent)
173{
174 g_return_val_if_fail(memdb != NULL, NULL);
175 g_return_val_if_fail(path != NULL, NULL);
176 g_return_val_if_fail(parent != NULL, NULL);
177
178 memdb_tree_entry_t *cdir = memdb->root;
179 *parent = NULL;
180
181 if (path[0] == 0 || ((path[0] == '.' || path[0] == '/') && path[1] == 0))
182 return cdir;
183
184 gchar **set = g_strsplit_set(path, "/", 0);
185
186 int i = 0;
187 char *name;
188
189 while ((name = set[i++])) {
190
191 if (name[0] == 0) continue;
192
193 *parent = cdir;
194 if ((cdir = memdb_lookup_dir_entry(memdb, name, cdir)) == NULL)
195 break;
196 }
197
198 g_strfreev(set);
199
200 return cdir;
201}
202
203
204static gboolean
205name_is_vm_config(
206 const char *name,
207 guint32 *vmid_ret)
208{
209 if (!name || name[0] < '1' || name[0] > '9')
210 return FALSE;
211
212 char *end = NULL;
213 guint32 vmid = strtoul(name, &end, 10);
214
215 if (!end || end[0] != '.' || end[1] != 'c'|| end[2] != 'o' || end[3] != 'n' ||
487ec85c 216 end[4] != 'f' || end[5] != 0 || errno == ERANGE)
fe000966
DM
217 return FALSE;
218
219 if (vmid_ret)
220 *vmid_ret = vmid;
221
222 return TRUE;
223}
224
225static gboolean
226valid_nodename(
227 const char *nodename)
228{
229 g_return_val_if_fail(nodename != NULL, FALSE);
230
231 /* LDH rule (letters, digits, hyphen) */
232
233 int len = strlen(nodename);
ba2e1b39
DM
234
235 if (len < 1) {
236 return FALSE;
237 }
238
fe000966
DM
239 for (int i = 0; i < len; i ++) {
240 char c = nodename[i];
241 if ((c >= 'A' && c <= 'Z') ||
242 (c >= 'a' && c <= 'z') ||
ba2e1b39 243 (c >= '0' && c <= '9') ||
fe000966
DM
244 (i != 0 && i != (len-1) && c == '-'))
245 continue;
246 return FALSE;
247 }
248
249 return TRUE;
250}
251
252static char*
253dir_contain_vm_config(
254 const char *dirname,
255 int *vmtype_ret)
256{
257 if (!dirname)
258 return NULL;
259
260 if (strncmp(dirname, "nodes/", 6) != 0)
261 return NULL;
262
263 dirname += 6;
264
265 char *nodename = NULL;
266
267 char **sa = g_strsplit(dirname, "/", 2);
268 if (sa[0] && sa[1] && valid_nodename(sa[0])) {
269 if (strcmp(sa[1], "qemu-server") == 0) {
270 *vmtype_ret = VMTYPE_QEMU;
271 nodename = g_strdup(sa[0]);
272 } else if (strcmp(sa[1], "openvz") == 0) {
273 *vmtype_ret = VMTYPE_OPENVZ;
274 nodename = g_strdup(sa[0]);
7f66b436
DM
275 } else if (strcmp(sa[1], "lxc") == 0) {
276 *vmtype_ret = VMTYPE_LXC;
277 nodename = g_strdup(sa[0]);
fe000966
DM
278 }
279 }
280
281 g_strfreev(sa);
282
283 return nodename;
284}
285
286static char *
287path_contain_vm_config(
288 const char *path,
289 int *vmtype_ret,
290 guint32 *vmid_ret)
291{
292 if (!path)
293 return NULL;
294
295 char *dirname = NULL;
296 char *base = NULL;
297 char *nodename = NULL;
298
299 split_path(path, &dirname, &base);
300
6e73d5c2
DM
301 if (name_is_vm_config(base, vmid_ret))
302 nodename = dir_contain_vm_config(dirname, vmtype_ret);
7f66b436 303
fe000966
DM
304 if (dirname) g_free (dirname);
305 if (base) g_free (base);
306
307 return nodename;
308}
309
310static gboolean
311vmlist_add_dir(
312 memdb_t *memdb,
313 GHashTable *vmlist,
314 const char *nodename,
315 const int vmtype,
316 memdb_tree_entry_t *subdir)
317{
318 g_return_val_if_fail(memdb != NULL, FALSE);
319 g_return_val_if_fail(vmlist != NULL, FALSE);
320 g_return_val_if_fail(subdir != NULL, FALSE);
321 g_return_val_if_fail(subdir->type == DT_DIR, FALSE);
322 g_return_val_if_fail(subdir->data.entries != NULL, FALSE);
323
324 gboolean ret = TRUE;
325
326 GHashTable *ht = subdir->data.entries;
327 GHashTableIter iter;
328 gpointer key, value;
329
330 g_hash_table_iter_init (&iter, ht);
331
332 while (g_hash_table_iter_next (&iter, &key, &value)) {
333
334 memdb_tree_entry_t *node_te = (memdb_tree_entry_t *)value;
335
6e73d5c2
DM
336 if (node_te->type != DT_REG)
337 continue;
7f66b436 338
6e73d5c2
DM
339 guint32 vmid = 0;
340 if (!name_is_vm_config(node_te->name, &vmid))
341 continue;
7f66b436 342
6e73d5c2
DM
343 if (!vmlist_hash_insert_vm(vmlist, vmtype, vmid, nodename, FALSE))
344 ret = FALSE;
fe000966
DM
345 }
346
347 return ret;
348}
349
350
351gboolean
352memdb_lock_expired(
353 memdb_t *memdb,
354 const char *path,
355 const guchar csum[32])
356{
357 g_return_val_if_fail(memdb != NULL, FALSE);
358 g_return_val_if_fail(memdb->locks != NULL, FALSE);
359 g_return_val_if_fail(path != NULL, FALSE);
360 g_return_val_if_fail(csum != NULL, FALSE);
361
362 memdb_lock_info_t *li;
363 uint32_t ctime = time(NULL);
364
365 if ((li = g_hash_table_lookup(memdb->locks, path))) {
366 if (memcmp(csum, li->csum, 32) != 0) {
367 li->ltime = ctime;
368 memcpy(li->csum, csum, 32);
369 g_critical("wrong lock csum - reset timeout");
370 return FALSE;
371 }
372 if ((ctime > li->ltime) && ((ctime - li->ltime) > CFS_LOCK_TIMEOUT))
373 return TRUE;
374 } else {
375 li = g_new0(memdb_lock_info_t, 1);
376 li->path = g_strdup(path);
377 li->ltime = ctime;
378 memcpy(li->csum, csum, 32);
379 g_hash_table_replace(memdb->locks, li->path, li);
380 }
381
382 return FALSE;
383}
384
385void
386memdb_update_locks(memdb_t *memdb)
387{
388 g_return_if_fail(memdb != NULL);
389 g_return_if_fail(memdb->locks != NULL);
390
391 memdb_tree_entry_t *te, *parent;
392
393 if (!(te = memdb_lookup_path(memdb, "priv/lock", &parent)))
394 return;
395
396 if (te->type != DT_DIR)
397 return;
398
399
400 GHashTable *old = memdb->locks;
401 memdb->locks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
402 (GDestroyNotify)memdb_lock_info_free);
403 GHashTableIter iter;
404 GHashTable *ht = te->data.entries;
405
406 gpointer key, value;
407
408 g_hash_table_iter_init (&iter, ht);
409 while (g_hash_table_iter_next (&iter, &key, &value)) {
410
411 memdb_tree_entry_t *lock_te = (memdb_tree_entry_t *)value;
412 if (lock_te->type != DT_DIR)
413 continue;
414
415 memdb_lock_info_t *li;
416 li = g_new0(memdb_lock_info_t, 1);
417 li->path = g_strdup_printf("priv/lock/%s", lock_te->name);
418
419 guchar csum[32];
420 if (memdb_tree_entry_csum(lock_te, csum)) {
421 memcpy(li->csum, csum, 32);
422 memdb_lock_info_t *oldli;
423 if ((oldli = g_hash_table_lookup(memdb->locks, lock_te->name)) &&
424 (memcmp(csum, oldli->csum, 32) == 0)) {
425 li->ltime = oldli->ltime;
426 } else {
427 li->ltime = time(NULL);
428 }
429 g_hash_table_insert(memdb->locks, li->path, li);
430 } else {
431 memdb_lock_info_free(li);
432 }
433 }
434
435 if (old)
436 g_hash_table_destroy(old);
437
438}
439
440gboolean
441memdb_recreate_vmlist(
442 memdb_t *memdb)
443{
444 g_return_val_if_fail(memdb != NULL, FALSE);
445
446 memdb_tree_entry_t *te, *parent;
447
448 if (!(te = memdb_lookup_path(memdb, "nodes", &parent)))
449 return TRUE;
450
451 if (te->type != DT_DIR)
452 return TRUE;
453
454 GHashTable *vmlist = vmlist_hash_new();
455
456 GHashTable *ht = te->data.entries;
457
458 gboolean ret = TRUE;
459
460 GHashTableIter iter;
461 gpointer key, value;
462
463 g_hash_table_iter_init (&iter, ht);
464
465 while (g_hash_table_iter_next (&iter, &key, &value)) {
466
467 memdb_tree_entry_t *node_te = (memdb_tree_entry_t *)value;
468 if (node_te->type != DT_DIR)
469 continue;
470
471 if (!valid_nodename(node_te->name))
472 continue;
473
474 if ((te = g_hash_table_lookup(node_te->data.entries, "qemu-server"))) {
475 if (!vmlist_add_dir(memdb, vmlist, node_te->name, VMTYPE_QEMU, te))
476 ret = FALSE;
477 }
478 if ((te = g_hash_table_lookup(node_te->data.entries, "openvz"))) {
479 if (!vmlist_add_dir(memdb, vmlist, node_te->name, VMTYPE_OPENVZ, te))
480 ret = FALSE;
481 }
7f66b436
DM
482 if ((te = g_hash_table_lookup(node_te->data.entries, "lxc"))) {
483 if (!vmlist_add_dir(memdb, vmlist, node_te->name, VMTYPE_LXC, te))
484 ret = FALSE;
485 }
fe000966
DM
486 }
487
488 /* always update list - even if we detected duplicates */
489 cfs_status_set_vmlist(vmlist);
490
491 return ret;
492}
493
494memdb_t *
495memdb_open(const char *dbfilename)
496{
497 memdb_t *memdb = g_new0(memdb_t, 1);
498
89fde9ac 499 g_mutex_init(&memdb->mutex);
fe000966
DM
500
501 memdb->dbfilename = g_strdup(dbfilename);
502
503 memdb->root = memdb_tree_entry_new("");
504 memdb->root->data.entries = g_hash_table_new(g_str_hash, g_str_equal);
505 memdb->root->type = DT_DIR;
506
507 memdb->index = g_hash_table_new_full(g_int64_hash, g_int64_equal, NULL,
508 (GDestroyNotify)memdb_tree_entry_free);
509
510 g_hash_table_replace(memdb->index, &memdb->root->inode, memdb->root);
511
512 memdb->locks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
513 (GDestroyNotify)memdb_lock_info_free);
514
515 if (!(memdb->bdb = bdb_backend_open(dbfilename, memdb->root, memdb->index))) {
516 memdb_close(memdb);
517 return NULL;
518 }
519
520 record_memdb_reload();
521
522 if (!memdb_recreate_vmlist(memdb)) {
523 memdb_close(memdb);
524 return NULL;
525 }
526
527 memdb_update_locks(memdb);
528
529 cfs_debug("memdb open '%s' successful (version = %016zX)",
530 dbfilename, memdb->root->version);
531
532 return memdb;
533}
534
535void
536memdb_close(memdb_t *memdb)
537{
538 g_return_if_fail(memdb != NULL);
539
89fde9ac 540 g_mutex_lock (&memdb->mutex);
fe000966
DM
541
542 if (memdb->bdb)
543 bdb_backend_close(memdb->bdb);
544
545 if (memdb->index)
546 g_hash_table_destroy(memdb->index);
547
548 if (memdb->locks)
549 g_hash_table_destroy(memdb->locks);
550
551 if (memdb->dbfilename)
552 g_free(memdb->dbfilename);
553
554 memdb->index = NULL;
555 memdb->bdb = NULL;
556 memdb->dbfilename = NULL;
557
89fde9ac 558 g_mutex_unlock (&memdb->mutex);
fe000966 559
89fde9ac 560 g_mutex_clear (&memdb->mutex);
fe000966
DM
561
562 g_free(memdb);
563}
564
565int memdb_mkdir(
566 memdb_t *memdb,
567 const char *path,
568 guint32 writer,
569 guint32 mtime)
570{
571 g_return_val_if_fail(memdb != NULL, -EINVAL);
572 g_return_val_if_fail(path != NULL, -EINVAL);
573
574 int ret = -EACCES;
575
576 char *dirname = NULL;
577 char *base = NULL;
578
89fde9ac 579 g_mutex_lock (&memdb->mutex);
fe000966
DM
580
581 if (memdb->errors) {
582 ret = -EIO;
583 goto ret;
584 }
585
586 split_path(path, &dirname, &base);
587
588 memdb_tree_entry_t *parent, *unused;
589
590 if (!(parent = memdb_lookup_path(memdb, dirname, &unused))) {
591 ret = -ENOENT;
592 goto ret;
593 }
594
595 if (parent->type != DT_DIR) {
596 ret = -ENOTDIR;
597 goto ret;
598 }
599
600 /* do not allow '.' and '..' */
601 if ((base[0] == 0) ||
602 (base[0] == '.' && base[1] == 0) ||
603 (base[0] == '.' && base[1] == '.' && base[2] == 0)) {
604 ret = -EACCES;
605 goto ret;
606 }
607
608 memdb_tree_entry_t *te;
609 if ((te = memdb_lookup_dir_entry(memdb, base, parent))) {
610 ret = -EEXIST;
611 goto ret;
612 }
613
614 memdb->root->version++;
615 memdb->root->mtime = mtime;
616 memdb->root->writer = writer;
617
618 te = memdb_tree_entry_new(base);
619 te->parent = parent->inode;
620 te->data.entries = g_hash_table_new(g_str_hash, g_str_equal);
621 te->inode = te->version = memdb->root->version;
622 te->writer = writer;
623 te->type = DT_DIR;
624 te->mtime = mtime;
625
626 g_hash_table_replace(parent->data.entries, te->name, te);
627 g_hash_table_replace(memdb->index, &te->inode, te);
628
629 cfs_debug("memdb_mkdir %s %s %016zX", dirname, base, memdb->root->version);
630
631 if (bdb_backend_write(memdb->bdb, te->inode, te->parent, te->version,
632 te->writer, te->mtime, 0, DT_DIR, te->name, NULL, 0)) {
633 memdb->errors = 1;
634 ret = -EIO;
635 goto ret;
636 }
637
638 if (strcmp(dirname, "priv/lock") == 0) {
639 g_hash_table_remove(memdb->locks, path);
640 guchar csum[32];
641 if (memdb_tree_entry_csum(te, csum)) {
642 memdb_lock_expired(memdb, path, csum); // insert a new entry
643 }
644 }
645
646 ret = 0;
647
648 ret:
89fde9ac 649 g_mutex_unlock (&memdb->mutex);
fe000966
DM
650
651 if (dirname) g_free (dirname);
652 if (base) g_free (base);
653
654 return ret;
655}
656
657int
658memdb_read(
659 memdb_t *memdb,
660 const char *path,
661 gpointer *data_ret)
662{
663 g_return_val_if_fail(memdb != NULL, -EINVAL);
664 g_return_val_if_fail(path != NULL, -EINVAL);
665 g_return_val_if_fail(data_ret != NULL, -EINVAL);
666
667 memdb_tree_entry_t *te, *parent;
668
89fde9ac 669 g_mutex_lock (&memdb->mutex);
fe000966
DM
670
671 if ((te = memdb_lookup_path(memdb, path, &parent))) {
672 if (te->type == DT_REG) {
673 *data_ret = g_memdup(te->data.value, te->size);
674 guint32 size = te->size;
89fde9ac 675 g_mutex_unlock (&memdb->mutex);
fe000966
DM
676 return size;
677 }
678 }
679
89fde9ac 680 g_mutex_unlock (&memdb->mutex);
fe000966
DM
681
682 return -ENOENT;
683}
684
685static int
686memdb_pwrite(
687 memdb_t *memdb,
688 const char *path,
689 guint32 writer,
690 guint32 mtime,
691 gconstpointer data,
692 size_t count,
693 off_t offset,
694 gboolean truncate,
695 gboolean create)
696{
697 g_return_val_if_fail(memdb != NULL, -EINVAL);
698 g_return_val_if_fail(path != NULL, -EINVAL);
699 g_return_val_if_fail(count == 0 || data != NULL, -EINVAL);
700
701 int ret = -EACCES;
702
703 char *dirname = NULL;
704 char *base = NULL;
705 char *nodename = NULL;
706
89fde9ac 707 g_mutex_lock (&memdb->mutex);
fe000966
DM
708
709 if (memdb->errors) {
710 ret = -EIO;
711 goto ret;
712 }
713
714 if ((offset + count) > MEMDB_MAX_FILE_SIZE) {
715 ret = -EFBIG;
716 goto ret;
717 }
718
719 split_path(path, &dirname, &base);
720
721 memdb_tree_entry_t *parent, *unused;
722 if (!(parent = memdb_lookup_path(memdb, dirname, &unused))) {
723 ret = -ENOENT;
724 goto ret;
725 }
726 if (parent->type != DT_DIR) {
727 ret = -ENOTDIR;
728 goto ret;
729 }
730
731 /* do not allow '.' and '..' */
732 if ((base[0] == 0) ||
733 (base[0] == '.' && base[1] == 0) ||
734 (base[0] == '.' && base[1] == '.' && base[2] == 0)) {
735 ret = -EACCES;
736 goto ret;
737 }
738
739 guint32 vmid = 0;
740 int vmtype = 0;
741
742 if ((nodename = path_contain_vm_config(path, &vmtype, &vmid))) {
743 if (vmlist_different_vm_exists(vmtype, vmid, nodename)) {
744 ret = -EEXIST;
745 goto ret;
746 }
747 }
748
749 gpointer olddata = NULL;
750
751 memdb_tree_entry_t *te, *old;
752 if ((old = te = memdb_lookup_dir_entry(memdb, base, parent))) {
753 if (te->type != DT_REG) {
754 ret = -ENOTDIR;
755 goto ret;
756 }
757
758 if (create) {
759 ret = -EEXIST;
760 goto ret;
761 }
762
763 memdb->root->version++;
764 memdb->root->mtime = mtime;
765 memdb->root->writer = writer;
766
767 olddata = te->data.value;
768 } else {
769
770 if (!create) {
771 ret = -ENOENT;
772 goto ret;
773 }
774
775 memdb->root->version++;
776 memdb->root->mtime = mtime;
777 memdb->root->writer = writer;
778
779 te = memdb_tree_entry_new(base);
780 te->parent = parent->inode;
781 te->type = DT_REG;
782 te->inode = memdb->root->version;
783 }
784
785 te->version = memdb->root->version;
786 te->writer = writer;
787 te->mtime = mtime;
788
789 size_t newsize = offset + count;
790
791 gpointer newdata = NULL;
792
793 if (olddata) {
794
795 if (newsize > te->size) {
796 newdata = g_malloc0(newsize);
797 memcpy(newdata, olddata, te->size);
798
799 } else {
800
801 if (!truncate) {
802 newsize = te->size;
803 }
804 newdata = g_malloc0(newsize);
805 memcpy(newdata, olddata, newsize);
806 }
807
808 if (count && data)
809 memcpy(newdata + offset, data, count);
810
811 } else {
812
813 if (count && data) {
814 newdata = g_malloc0(newsize);
815 memcpy(newdata + offset, data, count);
816 }
817 }
818
819 te->size = newsize;
820 te->data.value = newdata;
821
822 g_free(olddata);
823
824 if (!old) {
825 g_hash_table_replace(parent->data.entries, te->name, te);
826 g_hash_table_replace(memdb->index, &te->inode, te);
827 }
828
829 record_memdb_change(path);
830
831 cfs_debug("memdb_pwrite %s %s %016zX %016zX", dirname, te->name, te->inode, te->version);
832
833 if (bdb_backend_write(memdb->bdb, te->inode, te->parent, te->version,
834 te->writer, te->mtime, te->size, te->type, te->name,
835 te->data.value, 0)) {
836 memdb->errors = 1;
837 ret = -EIO;
838 goto ret;
839 }
840
841 if (nodename)
842 vmlist_register_vm(vmtype, vmid, nodename);
843
844 ret = count;
845
846 ret:
89fde9ac 847 g_mutex_unlock (&memdb->mutex);
fe000966
DM
848
849 if (nodename) g_free (nodename);
850 if (dirname) g_free (dirname);
851 if (base) g_free (base);
852
853 return ret;
854}
855
856int
857memdb_mtime(
858 memdb_t *memdb,
859 const char *path,
860 guint32 writer,
861 guint32 mtime)
862{
863 g_return_val_if_fail(memdb != NULL, -EINVAL);
864 g_return_val_if_fail(path != NULL, -EINVAL);
865
866 int ret = -EACCES;
867
868 char *dirname = NULL;
869 char *base = NULL;
870
89fde9ac 871 g_mutex_lock (&memdb->mutex);
fe000966
DM
872
873 if (memdb->errors) {
874 ret = -EIO;
875 goto ret;
876 }
877
878 split_path(path, &dirname, &base);
879
880 memdb_tree_entry_t *parent, *unused;
881 if (!(parent = memdb_lookup_path(memdb, dirname, &unused))) {
882 ret = -ENOENT;
883 goto ret;
884 }
885 if (parent->type != DT_DIR) {
886 ret = -ENOTDIR;
887 goto ret;
888 }
889
890 /* do not allow '.' and '..' */
891 if ((base[0] == 0) ||
892 (base[0] == '.' && base[1] == 0) ||
893 (base[0] == '.' && base[1] == '.' && base[2] == 0)) {
894 ret = -EACCES;
895 goto ret;
896 }
897
898 memdb_tree_entry_t *te;
899 if (!(te = memdb_lookup_dir_entry(memdb, base, parent))) {
900 ret = -ENOENT;
901 goto ret;
902 }
903
894bce1a
DM
904 int is_lock = (strcmp(dirname, "priv/lock") == 0) && (te->type == DT_DIR);
905
fe000966 906 /* NOTE: we use utime(0,0) to trigger 'unlock', so we do not
7f66b436 907 * allow to change mtime for locks (only if mtime is newer).
fe000966
DM
908 * See README for details about locks.
909 */
894bce1a
DM
910 if (is_lock) {
911 if (mtime < te->mtime) {
fe000966
DM
912 cfs_debug("dir is locked");
913 ret = -EACCES;
914 goto ret;
894bce1a
DM
915 } else {
916 /* only allow lock updates if the writer is the same */
917 if (te->writer != writer) {
918 ret = -EACCES;
919 goto ret;
920 }
921 }
fe000966
DM
922 }
923
fe000966
DM
924 memdb->root->version++;
925 memdb->root->mtime = mtime;
926 memdb->root->writer = writer;
927
928 te->version = memdb->root->version;
929 te->writer = writer;
930 te->mtime = mtime;
931
932 record_memdb_change(path);
933
934 cfs_debug("memdb_mtime %s %s %016zX %016zX", dirname, te->name, te->inode, te->version);
935
936 if (bdb_backend_write(memdb->bdb, te->inode, te->parent, te->version,
937 te->writer, te->mtime, te->size, te->type, te->name,
938 te->data.value, 0)) {
939 memdb->errors = 1;
940 ret = -EIO;
941 goto ret;
942 }
943
894bce1a
DM
944 if (is_lock) {
945 cfs_debug("update cfs lock");
946 g_hash_table_remove(memdb->locks, path);
947 guchar csum[32];
948 if (memdb_tree_entry_csum(te, csum)) {
949 memdb_lock_expired(memdb, path, csum); // insert a new entry
950 }
951 }
952
fe000966
DM
953 ret = 0;
954
955 ret:
89fde9ac 956 g_mutex_unlock (&memdb->mutex);
fe000966
DM
957
958 if (dirname) g_free (dirname);
959 if (base) g_free (base);
960
961 return ret;
962}
963
964int
965memdb_create(
966 memdb_t *memdb,
967 const char *path,
968 guint32 writer,
969 guint32 mtime)
970{
971 return memdb_pwrite(memdb, path, writer, mtime, NULL, 0, 0, FALSE, TRUE);
972}
973
974int
975memdb_write(
976 memdb_t *memdb,
977 const char *path,
978 guint32 writer,
979 guint32 mtime,
980 gconstpointer data,
981 size_t count,
982 off_t offset,
983 gboolean truncate)
984{
985 return memdb_pwrite(memdb, path, writer, mtime, data, count, offset, truncate, FALSE);
986}
987
988memdb_tree_entry_t *
989memdb_getattr(
990 memdb_t *memdb,
991 const char *path)
992{
993 memdb_tree_entry_t *te, *parent;
994
89fde9ac 995 g_mutex_lock (&memdb->mutex);
fe000966
DM
996
997 if ((te = memdb_lookup_path(memdb, path, &parent))) {
998
999 memdb_tree_entry_t *cpy = memdb_tree_entry_copy(te, 0);
1000
89fde9ac 1001 g_mutex_unlock (&memdb->mutex);
fe000966
DM
1002
1003 return cpy;
1004 }
1005
89fde9ac 1006 g_mutex_unlock (&memdb->mutex);
fe000966
DM
1007
1008 return NULL;
1009}
1010
1011GList *
1012memdb_readdir(
1013 memdb_t *memdb,
1014 const char *path)
1015{
1016 g_return_val_if_fail(memdb != NULL, NULL);
1017 g_return_val_if_fail(path != NULL, NULL);
fe000966
DM
1018
1019 memdb_tree_entry_t *te, *parent;
1020
1021 GList *list = NULL;
1022
89fde9ac 1023 g_mutex_lock (&memdb->mutex);
fe000966
DM
1024
1025 if (!(te = memdb_lookup_path(memdb, path, &parent)))
1026 goto ret;
1027
1028 if (te->type != DT_DIR)
1029 goto ret;
1030
1031 GHashTable *ht = te->data.entries;
1032
1033 GHashTableIter iter;
1034 gpointer key, value;
1035
1036 g_hash_table_iter_init (&iter, ht);
1037
1038 while (g_hash_table_iter_next (&iter, &key, &value)) {
1039
1040 te = (memdb_tree_entry_t *)value;
1041
1042 memdb_tree_entry_t *cpy = memdb_tree_entry_copy(te, 0);
1043
1044 list = g_list_append(list, cpy);
1045 }
1046
1047 ret:
89fde9ac 1048 g_mutex_unlock (&memdb->mutex);
fe000966
DM
1049
1050 return list;
1051}
1052
1053void
1054memdb_dirlist_free(GList *dirlist)
1055{
1056 GList *l = dirlist;
1057
1058 while (l) {
1059 if (l->data)
1060 g_free (l->data);
1061
1062 l = g_list_next(l);
1063 }
1064
1065 if (dirlist)
1066 g_list_free(dirlist);
1067}
1068
1069static int
1070unlink_tree_entry(
1071 memdb_t *memdb,
1072 memdb_tree_entry_t *parent,
1073 memdb_tree_entry_t *te)
1074{
1075 g_return_val_if_fail(parent != NULL, -EACCES);
1076 g_return_val_if_fail(parent->inode == te->parent, -EACCES);
1077
1078 if (te->type == DT_DIR)
1079 if (g_hash_table_size(te->data.entries))
1080 return -ENOTEMPTY;
1081
1082 if (!g_hash_table_steal(parent->data.entries, te->name)) {
1083 cfs_critical("internal error - can't delete entry");
1084 memdb->errors = 1;
1085 return -EIO;
1086 }
1087
1088 if (!g_hash_table_steal(memdb->index, &te->inode)) {
1089 cfs_critical("internal error - can't delete entry");
1090 memdb->errors = 1;
1091 return -EIO;
1092 }
1093
1094 return 0;
1095}
1096
1097int
1098memdb_rename(
1099 memdb_t *memdb,
1100 const char *from,
1101 const char *to,
1102 guint32 writer,
1103 guint32 mtime)
1104{
1105 int ret = -EACCES;
1106
1107 char *nodename = NULL;
1108 char *dirname = NULL;
1109 char *base = NULL;
1110
c3d1300b
DM
1111 guint32 vmid = 0;
1112 guint32 from_vmid = 0;
1113 int vmtype = 0;
1114 int from_vmtype = 0;
1115 char *from_node = NULL;
1116
89fde9ac 1117 g_mutex_lock (&memdb->mutex);
fe000966
DM
1118
1119 if (memdb->errors) {
1120 ret = -EIO;
1121 goto ret;
1122 }
1123
1124 memdb_tree_entry_t *from_te, *from_parent;
1125 memdb_tree_entry_t *to_te, *to_parent;
1126 memdb_tree_entry_t *target_te, *target_parent;
1127
1128 guint64 delete_inode = 0;
1129
1130 if (!(from_te = memdb_lookup_path(memdb, from, &from_parent))) {
1131 ret = -ENOENT;
1132 goto ret;
1133 }
1134
1135 if (!from_parent) { /* can't rename root */
1136 ret = -EACCES;
1137 goto ret;
1138 }
1139
c3d1300b 1140 from_node = path_contain_vm_config(from, &from_vmtype, &from_vmid);
fe000966 1141
6e73d5c2 1142 if (from_te->type == DT_REG && (nodename = path_contain_vm_config(to, &vmtype, &vmid))) {
e6be001a 1143 if (vmlist_different_vm_exists(vmtype, vmid, nodename)) {
8c6a4084 1144 if (!(from_node && vmid == from_vmid)) {
b382cba9
DM
1145 ret = -EEXIST;
1146 goto ret;
6e73d5c2 1147 }
fe000966
DM
1148 }
1149 }
1150
1151 /* we do not allow rename for locks */
1152 if (from_te->type == DT_DIR && path_is_lockdir(from)) {
1153 ret = -EACCES;
1154 goto ret;
1155 }
1156
1157 if ((to_te = memdb_lookup_path(memdb, to, &to_parent))) {
1158
1159 if ((ret = unlink_tree_entry(memdb, to_parent, to_te)) != 0)
1160 goto ret;
1161
1162 base = strdup(to_te->name);
1163
1164 delete_inode = to_te->inode;
1165
1166 target_te = to_parent;
1167
1168 memdb_tree_entry_free(to_te);
1169
1170 } else {
1171
1172 split_path(to, &dirname, &base);
1173
1174 if (!(target_te = memdb_lookup_path(memdb, dirname, &target_parent))) {
1175 ret = -ENOENT;
1176 goto ret;
1177 }
1178
1179 if (target_te->type != DT_DIR) {
1180 ret = -ENOTDIR;
1181 goto ret;
1182 }
1183 }
1184
1185 record_memdb_change(from);
1186 record_memdb_change(to);
1187
1188 /* NOTE: unlink_tree_entry() make sure that we can only
1189 rename emtpy directories */
1190
1191 if ((ret = unlink_tree_entry(memdb, from_parent, from_te)) != 0)
1192 goto ret;
1193
1194 memdb->root->version++;
1195 memdb->root->mtime = mtime;
1196 memdb->root->writer = writer;
1197
1198 memdb_tree_entry_t *new = memdb_tree_entry_new(base);
1199 new->parent = target_te->inode;
1200 new->inode = from_te->inode;
1201 new->version = memdb->root->version;
1202 new->writer = writer;
1203 new->mtime = mtime;
1204 new->size = from_te->size;
1205 new->type = from_te->type;
1206 new->data = from_te->data;
1207
1208 g_free(from_te);
1209
1210 g_hash_table_replace(target_te->data.entries, new->name, new);
1211 g_hash_table_replace(memdb->index, &new->inode, new);
1212
1213 if (bdb_backend_write(memdb->bdb, new->inode, new->parent,
1214 new->version, new->writer, new->mtime,
1215 new->size, new->type, new->name,
1216 new->data.value, delete_inode)) {
1217 memdb->errors = 1;
1218 ret = -EIO;
1219 goto ret;
1220 }
1221
1222 if (new->type == DT_REG) {
1223
1224 if (from_vmid)
1225 vmlist_delete_vm(from_vmid);
1226
1227 if (nodename)
1228 vmlist_register_vm(vmtype, vmid, nodename);
1229
1230 } else if (new->type == DT_DIR) {
1231 /* directories are alwayse empty (see unlink_tree_entry) */
1232 }
1233
1234 ret = 0;
1235
1236 ret:
89fde9ac 1237 g_mutex_unlock (&memdb->mutex);
fe000966 1238
b382cba9 1239 if (from_node) g_free(from_node);
fe000966
DM
1240 if (nodename) g_free (nodename);
1241 if (dirname) g_free (dirname);
1242 if (base) g_free (base);
1243
1244 return ret;
1245}
1246
1247int
1248memdb_delete(
1249 memdb_t *memdb,
1250 const char *path,
1251 guint32 writer,
1252 guint32 mtime)
1253{
1254 memdb_tree_entry_t *te, *parent;
1255
89fde9ac 1256 g_mutex_lock (&memdb->mutex);
fe000966
DM
1257
1258 int ret = -EACCES;
1259
1260 if (memdb->errors) {
1261 ret = -EIO;
1262 goto ret;
1263 }
1264
1265 if (!(te = memdb_lookup_path(memdb, path, &parent))) {
1266 ret = -ENOENT;
1267 goto ret;
1268 }
1269
1270 if (!parent) { /* cant remove root */
1271 ret = -EACCES;
1272 goto ret;
1273 }
1274
1275 if (te->type == DT_DIR) {
1276 if (g_hash_table_size(te->data.entries)) {
1277 ret = -ENOTEMPTY;
1278 goto ret;
1279 }
1280
1281 g_hash_table_remove(memdb->locks, path);
1282 }
1283
1284 record_memdb_change(path);
1285
1286 if ((ret = unlink_tree_entry(memdb, parent, te)) != 0)
1287 goto ret;
1288
1289 memdb->root->version++;
1290 memdb->root->mtime = mtime;
1291 memdb->root->writer = writer;
1292
1293 if (bdb_backend_write(memdb->bdb, 0, 0, memdb->root->version, writer, mtime, 0,
1294 DT_REG, NULL, NULL, te->inode)) {
1295 memdb->errors = 1;
1296 memdb_tree_entry_free(te);
1297 ret = -EIO;
1298 goto ret;
1299 }
1300
1301 memdb_tree_entry_free(te);
1302
1303 int vmtype = 0;
1304 guint32 vmid = 0;
1305 char *nodename;
1306 if ((nodename = path_contain_vm_config(path, &vmtype, &vmid))) {
1307 g_free(nodename);
1308 vmlist_delete_vm(vmid);
1309 }
1310
1311 ret = 0;
1312
1313 ret:
89fde9ac 1314 g_mutex_unlock (&memdb->mutex);
fe000966
DM
1315
1316 return ret;
1317}
1318
1319int
1320memdb_statfs(
1321 memdb_t *memdb,
1322 struct statvfs *stbuf)
1323{
1324 g_return_val_if_fail(memdb != NULL, -EINVAL);
1325 g_return_val_if_fail(stbuf != NULL, -EINVAL);
1326
89fde9ac 1327 g_mutex_lock (&memdb->mutex);
fe000966
DM
1328
1329 GHashTableIter iter;
1330 gpointer key, value;
1331
1332 size_t size = 0;
1333 size_t files = 0;
1334
1335 g_hash_table_iter_init (&iter, memdb->index);
1336
1337 while (g_hash_table_iter_next (&iter, &key, &value)) {
1338 memdb_tree_entry_t *te = (memdb_tree_entry_t *)value;
1339 files++;
1340 size += te->size;
1341 }
1342
89fde9ac 1343 g_mutex_unlock (&memdb->mutex);
fe000966
DM
1344
1345 stbuf->f_bsize = MEMDB_BLOCKSIZE;
1346 stbuf->f_blocks = MEMDB_BLOCKS;
1347 stbuf->f_bfree = stbuf->f_bavail = stbuf->f_blocks -
1348 ((size + stbuf->f_bsize - 1)/stbuf->f_bsize);
1349 stbuf->f_files = MEMDB_MAX_INODES;
1350 stbuf->f_ffree = stbuf->f_files - files;
1351
1352 stbuf->f_namemax = 256;
1353
1354 return 0;
1355}
1356
1357void
1358tree_entry_debug(memdb_tree_entry_t *te)
1359{
1360 g_return_if_fail(te != NULL);
1361
1362 // same as tree_entry_print(), but use cfs_debug() instead of g_print()
1363
1364 cfs_debug("%016zX %c %016zX %016zX %08X %08X %08X %s\n",
1365 te->inode, te->type == DT_DIR ? 'D' : 'R', te->parent, te->version,
1366 te->writer, te->mtime, te->size, te->name);
1367}
1368
1369void
1370tree_entry_print(memdb_tree_entry_t *te)
1371{
1372 g_return_if_fail(te != NULL);
1373
1374 g_print("%016zX %c %016zX %016zX %08X %08X %08X %s\n",
1375 te->inode, te->type == DT_DIR ? 'D' : 'R', te->parent, te->version,
1376 te->writer, te->mtime, te->size, te->name);
1377}
1378
1379void
1380memdb_dump(memdb_t *memdb)
1381{
1382 g_return_if_fail(memdb != NULL);
1383
89fde9ac 1384 g_mutex_lock (&memdb->mutex);
fe000966
DM
1385
1386 GList *list = g_hash_table_get_values(memdb->index);
1387
1388 list = g_list_sort(list, memdb_tree_compare);
1389
1390 g_print("%16s %c %16s %16s %8s %8s %8s %s\n",
1391 "INODE", 'T', "PARENT", "VERSION", "WRITER", "MTIME", "SIZE", "NAME");
1392
1393 GList *l = list;
1394 while (l) {
1395 memdb_tree_entry_t *te = (memdb_tree_entry_t *)l->data;
1396
1397 tree_entry_print(te);
1398
1399 l = g_list_next(l);
1400 }
1401
1402 g_list_free(list);
1403
89fde9ac 1404 g_mutex_unlock (&memdb->mutex);
fe000966
DM
1405}
1406
1407void
1408memdb_dump_index (memdb_index_t *idx)
1409{
1410 g_return_if_fail(idx != NULL);
1411
1412 g_print ("INDEX DUMP %016zX\n", idx->version);
1413
1414 int i;
1415 for (i = 0; i < idx->size; i++) {
1416 g_print ("%016zX %016zX%016zX%016zX%016zX\n", idx->entries[i].inode,
1417 *((guint64 *)idx->entries[i].digest),
1418 *((guint64 *)(idx->entries[i].digest + 8)),
1419 *((guint64 *)(idx->entries[i].digest + 16)),
1420 *((guint64 *)(idx->entries[i].digest + 24)));
1421 }
1422}
1423
1424memdb_index_t *
1425memdb_index_copy(memdb_index_t *idx)
1426{
1427 g_return_val_if_fail(idx != NULL, NULL);
1428
1429 int bytes = sizeof(memdb_index_t) + idx->size*sizeof(memdb_index_extry_t);
1430 if (idx->bytes != bytes) {
1431 cfs_critical("memdb index contains wrong number of bytes");
1432 return NULL;
1433 }
1434
1435 memdb_index_t *copy = (memdb_index_t *)g_memdup(idx, bytes);
1436
1437 return copy;
1438}
1439
1440gboolean
1441memdb_tree_entry_csum(
1442 memdb_tree_entry_t *te,
1443 guchar csum[32])
1444{
1445 g_return_val_if_fail(te != NULL, FALSE);
1446 g_return_val_if_fail(csum != NULL, FALSE);
1447
1448 GChecksum *sha256 = g_checksum_new(G_CHECKSUM_SHA256);
1449
1450 g_checksum_update(sha256, (unsigned char*)&te->inode, sizeof(te->inode));
1451 g_checksum_update(sha256, (unsigned char*)&te->version, sizeof(te->version));
1452 g_checksum_update(sha256, (unsigned char*)&te->writer, sizeof(te->writer));
1453 g_checksum_update(sha256, (unsigned char*)&te->mtime, sizeof(te->mtime));
1454 g_checksum_update(sha256, (unsigned char*)&te->size, sizeof(te->size));
1455 g_checksum_update(sha256, (unsigned char*)&te->type, sizeof(te->type));
1456 g_checksum_update(sha256, (unsigned char*)&te->parent, sizeof(te->parent));
1457 g_checksum_update(sha256, (unsigned char*)te->name, strlen(te->name));
1458
1459 if (te->type == DT_REG && te->size)
1460 g_checksum_update(sha256, (unsigned char*)te->data.value, te->size);
1461
1462 size_t csum_len = 32;
1463 g_checksum_get_digest(sha256, csum, &csum_len);
1464 g_checksum_free(sha256);
1465
1466 return TRUE;
1467}
1468
1469gboolean
1470memdb_compute_checksum(
1471 GHashTable *index,
1472 memdb_tree_entry_t *root,
1473 guchar *csum,
1474 size_t csum_len)
1475{
1476 g_return_val_if_fail(index != NULL, FALSE);
1477 g_return_val_if_fail(root != NULL, FALSE);
1478
1479 GChecksum *sha256 = g_checksum_new(G_CHECKSUM_SHA256);
1480
1481 GList *list = g_hash_table_get_values(index);
1482
1483 list = g_list_sort(list, memdb_tree_compare);
1484
1485 GList *l = list;
1486 while (l) {
1487 memdb_tree_entry_t *te = (memdb_tree_entry_t *)l->data;
1488
1489 g_checksum_update(sha256, (unsigned char*)&te->inode, sizeof(te->inode));
1490 g_checksum_update(sha256, (unsigned char*)&te->version, sizeof(te->version));
1491 g_checksum_update(sha256, (unsigned char*)&te->writer, sizeof(te->writer));
1492 g_checksum_update(sha256, (unsigned char*)&te->mtime, sizeof(te->mtime));
1493 g_checksum_update(sha256, (unsigned char*)&te->size, sizeof(te->size));
1494 g_checksum_update(sha256, (unsigned char*)&te->type, sizeof(te->type));
1495 g_checksum_update(sha256, (unsigned char*)&te->parent, sizeof(te->parent));
1496 g_checksum_update(sha256, (unsigned char*)te->name, strlen(te->name));
1497
1498 if (te->type == DT_REG && te->size)
1499 g_checksum_update(sha256, (unsigned char*)te->data.value, te->size);
1500
1501 l = g_list_next(l);
1502 }
1503
1504 g_list_free(list);
1505
1506 g_checksum_get_digest(sha256, csum, &csum_len);
1507
1508 cfs_debug("checksum: %s", g_checksum_get_string(sha256));
1509
1510 g_checksum_free(sha256);
1511
1512 return TRUE;
1513}
1514
1515memdb_index_t *
1516memdb_encode_index(
1517 GHashTable *index,
1518 memdb_tree_entry_t *root)
1519{
1520 g_return_val_if_fail(index != NULL, NULL);
1521 g_return_val_if_fail(root != NULL, NULL);
1522
1523 memdb_index_t *idx = NULL;
1524
1525 int count = g_hash_table_size(index);
1526 if (!count) {
1527 cfs_critical("memdb index has no entires");
1528 return NULL;
1529 }
1530
1531 int bytes = sizeof(memdb_index_t) + count*sizeof(memdb_index_extry_t);
1532 idx = g_malloc0(bytes);
1533
1534 idx->size = count;
1535 idx->bytes = bytes;
1536 idx->version = root->version;
1537 idx->mtime = root->mtime;
1538 idx->writer = root->writer;
1539
1540 GChecksum *sha256 = g_checksum_new(G_CHECKSUM_SHA256);
1541
1542 GList *list = g_hash_table_get_values(index);
1543
1544 list = g_list_sort(list, memdb_tree_compare);
1545
1546 int ind = 0;
1547 GList *l = list;
1548 while (l) {
1549 memdb_tree_entry_t *te = (memdb_tree_entry_t *)l->data;
1550
1551 if (te->inode > idx->last_inode)
1552 idx->last_inode = te->inode;
1553
1554 idx->entries[ind].inode = te->inode;
1555
1556 g_checksum_reset (sha256);
1557
1558 g_checksum_update(sha256, (unsigned char*)&te->version, sizeof(te->version));
1559 g_checksum_update(sha256, (unsigned char*)&te->writer, sizeof(te->writer));
1560 g_checksum_update(sha256, (unsigned char*)&te->mtime, sizeof(te->mtime));
1561 g_checksum_update(sha256, (unsigned char*)&te->size, sizeof(te->size));
1562 g_checksum_update(sha256, (unsigned char*)&te->type, sizeof(te->type));
1563 g_checksum_update(sha256, (unsigned char*)&te->parent, sizeof(te->parent));
1564 g_checksum_update(sha256, (unsigned char*)te->name, strlen(te->name));
1565
1566 if (te->type == DT_REG && te->size)
1567 g_checksum_update(sha256, (unsigned char*)te->data.value, te->size);
1568
1569 gsize len = 32;
1570 g_checksum_get_digest(sha256, (guint8 *)idx->entries[ind].digest, &len);
1571
1572 ind++;
1573
1574 l = g_list_next(l);
1575 }
1576
1577 g_list_free(list);
1578
1579 g_checksum_free(sha256);
1580
1581 return idx;
1582}