|
28 | 28 | #include "check_deps.h"
|
29 | 29 |
|
30 | 30 | #define BTRFS_MIN_VERSION "3.18.2"
|
| 31 | +// HACK: btrfsutil issue? |
| 32 | +#define BTRFS_FSID_SIZE 16 |
31 | 33 |
|
32 | 34 | /**
|
33 | 35 | * SECTION: btrfs
|
@@ -212,23 +214,6 @@ static BDBtrfsDeviceInfo* get_device_info_from_match (GMatchInfo *match_info) {
|
212 | 214 | return ret;
|
213 | 215 | }
|
214 | 216 |
|
215 |
| -static BDBtrfsSubvolumeInfo* get_subvolume_info_from_match (GMatchInfo *match_info) { |
216 |
| - BDBtrfsSubvolumeInfo *ret = g_new(BDBtrfsSubvolumeInfo, 1); |
217 |
| - gchar *item = NULL; |
218 |
| - |
219 |
| - item = g_match_info_fetch_named (match_info, "id"); |
220 |
| - ret->id = g_ascii_strtoull (item, NULL, 0); |
221 |
| - g_free (item); |
222 |
| - |
223 |
| - item = g_match_info_fetch_named (match_info, "parent_id"); |
224 |
| - ret->parent_id = g_ascii_strtoull (item, NULL, 0); |
225 |
| - g_free (item); |
226 |
| - |
227 |
| - ret->path = g_match_info_fetch_named (match_info, "path"); |
228 |
| - |
229 |
| - return ret; |
230 |
| -} |
231 |
| - |
232 | 217 | static BDBtrfsFilesystemInfo* get_filesystem_info_from_match (GMatchInfo *match_info) {
|
233 | 218 | BDBtrfsFilesystemInfo *ret = g_new(BDBtrfsFilesystemInfo, 1);
|
234 | 219 | gchar *item = NULL;
|
@@ -608,112 +593,51 @@ BDBtrfsDeviceInfo** bd_btrfs_list_devices (const gchar *device, GError **error)
|
608 | 593 | * Tech category: %BD_BTRFS_TECH_SUBVOL-%BD_BTRFS_TECH_MODE_QUERY
|
609 | 594 | */
|
610 | 595 | BDBtrfsSubvolumeInfo** bd_btrfs_list_subvolumes (const gchar *mountpoint, gboolean snapshots_only, GError **error) {
|
611 |
| - const gchar *argv[7] = {"btrfs", "subvol", "list", "-p", NULL, NULL, NULL}; |
612 |
| - gchar *output = NULL; |
613 |
| - gboolean success = FALSE; |
614 |
| - gchar **lines = NULL; |
615 |
| - gchar **line_p = NULL; |
616 |
| - gchar const * const pattern = "ID\\s+(?P<id>\\d+)\\s+gen\\s+\\d+\\s+(cgen\\s+\\d+\\s+)?" \ |
617 |
| - "parent\\s+(?P<parent_id>\\d+)\\s+top\\s+level\\s+\\d+\\s+" \ |
618 |
| - "(otime\\s+(\\d{4}-\\d{2}-\\d{2}\\s+\\d\\d:\\d\\d:\\d\\d|-)\\s+)?"\ |
619 |
| - "path\\s+(?P<path>\\S+)"; |
620 |
| - GRegex *regex = NULL; |
621 |
| - GMatchInfo *match_info = NULL; |
622 |
| - guint64 i = 0; |
623 |
| - guint64 y = 0; |
624 |
| - guint64 next_sorted_idx = 0; |
625 |
| - GPtrArray *subvol_infos; |
626 |
| - BDBtrfsSubvolumeInfo* item = NULL; |
627 |
| - BDBtrfsSubvolumeInfo* swap_item = NULL; |
| 596 | + struct btrfs_util_subvolume_iterator *iter; |
| 597 | + enum btrfs_util_error err; |
| 598 | + char *path; |
| 599 | + char empty_uuid[BTRFS_FSID_SIZE] = {0}; |
| 600 | + struct btrfs_util_subvolume_info info; |
628 | 601 | BDBtrfsSubvolumeInfo** ret = NULL;
|
629 |
| - GError *l_error = NULL; |
630 |
| - |
631 |
| - if (!check_deps (&avail_deps, DEPS_BTRFS_MASK, deps, DEPS_LAST, &deps_check_lock, error) || |
632 |
| - !check_module_deps (&avail_module_deps, MODULE_DEPS_BTRFS_MASK, module_deps, MODULE_DEPS_LAST, &deps_check_lock, error)) |
633 |
| - return NULL; |
634 |
| - |
635 |
| - if (snapshots_only) { |
636 |
| - argv[4] = "-s"; |
637 |
| - argv[5] = mountpoint; |
638 |
| - } else |
639 |
| - argv[4] = mountpoint; |
| 602 | + GPtrArray *subvol_infos; |
640 | 603 |
|
641 |
| - regex = g_regex_new (pattern, G_REGEX_EXTENDED, 0, error); |
642 |
| - if (!regex) { |
643 |
| - bd_utils_log_format (BD_UTILS_LOG_WARNING, "Failed to create new GRegex"); |
644 |
| - /* error is already populated */ |
| 604 | + err = btrfs_util_create_subvolume_iterator (mountpoint, 5, 0, &iter); |
| 605 | + if (err) { |
| 606 | + g_set_error (error, BD_BTRFS_ERROR, BD_BTRFS_ERROR_NOT_FOUND, "%s: %m", btrfs_util_strerror (err)); |
645 | 607 | return NULL;
|
646 | 608 | }
|
647 | 609 |
|
648 |
| - success = bd_utils_exec_and_capture_output (argv, NULL, &output, &l_error); |
649 |
| - if (!success) { |
650 |
| - g_regex_unref (regex); |
651 |
| - if (g_error_matches (l_error, BD_UTILS_EXEC_ERROR, BD_UTILS_EXEC_ERROR_NOOUT)) { |
652 |
| - /* no output -> no subvolumes */ |
653 |
| - g_clear_error (&l_error); |
654 |
| - return g_new0 (BDBtrfsSubvolumeInfo*, 1); |
655 |
| - } else { |
656 |
| - g_propagate_error (error, l_error); |
657 |
| - return NULL; |
658 |
| - } |
659 |
| - } |
660 |
| - |
661 |
| - lines = g_strsplit (output, "\n", 0); |
662 |
| - g_free (output); |
663 |
| - |
664 | 610 | subvol_infos = g_ptr_array_new ();
|
665 |
| - for (line_p = lines; *line_p; line_p++) { |
666 |
| - success = g_regex_match (regex, *line_p, 0, &match_info); |
667 |
| - if (!success) { |
668 |
| - g_match_info_free (match_info); |
| 611 | + while (!(err = btrfs_util_subvolume_iterator_next_info (iter, &path, &info))) { |
| 612 | + /* See uapi/linux/btrfs.h */ |
| 613 | + if (snapshots_only && memcmp (info.parent_uuid, empty_uuid, BTRFS_FSID_SIZE) == 0) |
669 | 614 | continue;
|
670 |
| - } |
671 | 615 |
|
672 |
| - g_ptr_array_add (subvol_infos, get_subvolume_info_from_match (match_info)); |
673 |
| - g_match_info_free (match_info); |
| 616 | + BDBtrfsSubvolumeInfo *subvol = g_new (BDBtrfsSubvolumeInfo, 1); |
| 617 | + subvol->id = info.id; |
| 618 | + subvol->parent_id = info.parent_id; |
| 619 | + subvol->path = g_strdup (path); |
| 620 | + g_ptr_array_add (subvol_infos, subvol); |
| 621 | + |
| 622 | + free (path); |
674 | 623 | }
|
675 | 624 |
|
676 |
| - g_strfreev (lines); |
677 |
| - g_regex_unref (regex); |
| 625 | + btrfs_util_destroy_subvolume_iterator (iter); |
678 | 626 |
|
679 |
| - if (subvol_infos->len == 0) { |
680 |
| - g_set_error (error, BD_BTRFS_ERROR, BD_BTRFS_ERROR_PARSE, "Failed to parse information about subvolumes"); |
681 |
| - g_ptr_array_free (subvol_infos, TRUE); |
| 627 | + if (err) { |
| 628 | + g_set_error (error, BD_BTRFS_ERROR, BD_BTRFS_ERROR_NOT_FOUND, "%s: %m", btrfs_util_strerror (err)); |
682 | 629 | return NULL;
|
683 | 630 | }
|
684 | 631 |
|
685 | 632 | /* now we know how much space to allocate for the result (subvols + NULL) */
|
686 | 633 | ret = g_new0 (BDBtrfsSubvolumeInfo*, subvol_infos->len + 1);
|
687 | 634 |
|
688 |
| - /* we need to sort the subvolumes in a way that no child subvolume appears |
689 |
| - in the list before its parent (sub)volume */ |
690 |
| - |
691 |
| - /* let's start by moving all top-level (sub)volumes to the beginning */ |
692 |
| - for (i=0; i < subvol_infos->len; i++) { |
693 |
| - item = (BDBtrfsSubvolumeInfo*) g_ptr_array_index (subvol_infos, i); |
694 |
| - if (item->parent_id == BD_BTRFS_MAIN_VOLUME_ID) |
695 |
| - /* top-level (sub)volume */ |
696 |
| - ret[next_sorted_idx++] = item; |
697 |
| - } |
698 |
| - /* top-level (sub)volumes are now processed */ |
699 |
| - for (i=0; i < next_sorted_idx; i++) |
700 |
| - g_ptr_array_remove_fast (subvol_infos, ret[i]); |
701 |
| - |
702 |
| - /* now sort the rest in a way that we search for an already sorted parent or sibling */ |
| 635 | + guint64 i = 0; |
| 636 | + BDBtrfsSubvolumeInfo* item = NULL; |
703 | 637 | for (i=0; i < subvol_infos->len; i++) {
|
704 | 638 | item = (BDBtrfsSubvolumeInfo*) g_ptr_array_index (subvol_infos, i);
|
705 |
| - ret[next_sorted_idx] = item; |
706 |
| - /* move the item towards beginning of the array checking if some parent |
707 |
| - or sibling has been already processed/sorted before or we reached the |
708 |
| - top-level (sub)volumes */ |
709 |
| - for (y=next_sorted_idx; (y > 0 && (ret[y-1]->id != item->parent_id) && (ret[y-1]->parent_id != item->parent_id) && (ret[y-1]->parent_id != BD_BTRFS_MAIN_VOLUME_ID)); y--) { |
710 |
| - swap_item = ret[y-1]; |
711 |
| - ret[y-1] = ret[y]; |
712 |
| - ret[y] = swap_item; |
713 |
| - } |
714 |
| - next_sorted_idx++; |
| 639 | + ret[i] = item; |
715 | 640 | }
|
716 |
| - ret[next_sorted_idx] = NULL; |
717 | 641 |
|
718 | 642 | /* now just free the pointer array */
|
719 | 643 | g_ptr_array_free (subvol_infos, TRUE);
|
|
0 commit comments