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