LCOV - code coverage report
Current view: top level - plugins/fs - generic.c (source / functions) Coverage Total Hit
Test: libblockdev Coverage Report Lines: 76.4 % 907 693
Test Date: 2026-01-26 13:19:28 Functions: 97.6 % 41 40
Legend: Lines: hit not hit

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2017  Red Hat, Inc.
       3              :  *
       4              :  * This library is free software; you can redistribute it and/or
       5              :  * modify it under the terms of the GNU Lesser General Public
       6              :  * License as published by the Free Software Foundation; either
       7              :  * version 2.1 of the License, or (at your option) any later version.
       8              :  *
       9              :  * This library 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 GNU
      12              :  * Lesser General Public License for more details.
      13              :  *
      14              :  * You should have received a copy of the GNU Lesser General Public
      15              :  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      16              :  *
      17              :  * Author: Vratislav Podzimek <vpodzime@redhat.com>
      18              :  */
      19              : 
      20              : #include <glib.h>
      21              : #include <glib/gstdio.h>
      22              : #include <blkid.h>
      23              : #include <string.h>
      24              : #include <sys/types.h>
      25              : #include <sys/stat.h>
      26              : #include <sys/ioctl.h>
      27              : #include <linux/fs.h>
      28              : #include <fcntl.h>
      29              : #include <errno.h>
      30              : 
      31              : #include <blockdev/utils.h>
      32              : 
      33              : #include "generic.h"
      34              : #include "mount.h"
      35              : #include "fs.h"
      36              : #include "common.h"
      37              : #include "ext.h"
      38              : #include "xfs.h"
      39              : #include "vfat.h"
      40              : #include "ntfs.h"
      41              : #include "f2fs.h"
      42              : 
      43              : 
      44              : 
      45              : typedef enum {
      46              :     BD_FS_MKFS,
      47              :     BD_FS_RESIZE,
      48              :     BD_FS_REPAIR,
      49              :     BD_FS_CHECK,
      50              :     BD_FS_LABEL,
      51              :     BD_FS_LABEL_CHECK,
      52              :     BD_FS_GET_SIZE,
      53              :     BD_FS_UUID,
      54              :     BD_FS_UUID_CHECK,
      55              :     BD_FS_GET_FREE_SPACE,
      56              :     BD_FS_GET_INFO,
      57              :     BD_FS_GET_MIN_SIZE,
      58              : } BDFSOpType;
      59              : 
      60              : static const BDFSFeatures fs_features[BD_FS_LAST_FS] = {
      61              :     /* padding for BD_FS_TECH_GENERIC and MOUNT to make accessing the FS techs simpler */
      62              :     { 0 }, { 0 },
      63              :     /* EXT2 */
      64              :     { .resize = BD_FS_ONLINE_GROW | BD_FS_OFFLINE_GROW | BD_FS_OFFLINE_SHRINK,
      65              :       .mkfs = BD_FS_MKFS_LABEL | BD_FS_MKFS_UUID | BD_FS_MKFS_DRY_RUN | BD_FS_MKFS_NODISCARD |
      66              :               BD_FS_MKFS_FORCE,
      67              :       .fsck = BD_FS_FSCK_CHECK | BD_FS_FSCK_REPAIR,
      68              :       .configure = BD_FS_SUPPORT_SET_LABEL | BD_FS_SUPPORT_SET_UUID,
      69              :       .features =  BD_FS_FEATURE_OWNERS,
      70              :       .partition_id = "0x83",
      71              :       .partition_type = "0fc63daf-8483-4772-8e79-3d69d8477de4",
      72              :       .min_size = 1 MiB,
      73              :       .max_size = 8 TiB },
      74              :     /* EXT3 */
      75              :     { .resize = BD_FS_ONLINE_GROW | BD_FS_OFFLINE_GROW | BD_FS_OFFLINE_SHRINK,
      76              :       .mkfs = BD_FS_MKFS_LABEL | BD_FS_MKFS_UUID | BD_FS_MKFS_DRY_RUN | BD_FS_MKFS_NODISCARD |
      77              :               BD_FS_MKFS_FORCE,
      78              :       .fsck = BD_FS_FSCK_CHECK | BD_FS_FSCK_REPAIR,
      79              :       .configure = BD_FS_SUPPORT_SET_LABEL | BD_FS_SUPPORT_SET_UUID,
      80              :       .features =  BD_FS_FEATURE_OWNERS,
      81              :       .partition_id = "0x83",
      82              :       .partition_type = "0fc63daf-8483-4772-8e79-3d69d8477de4",
      83              :       .min_size = 1 MiB,
      84              :       .max_size = 16 TiB },
      85              :     /* EXT4 */
      86              :     { .resize = BD_FS_ONLINE_GROW | BD_FS_OFFLINE_GROW | BD_FS_OFFLINE_SHRINK,
      87              :       .mkfs = BD_FS_MKFS_LABEL | BD_FS_MKFS_UUID | BD_FS_MKFS_DRY_RUN | BD_FS_MKFS_NODISCARD |
      88              :               BD_FS_MKFS_FORCE,
      89              :       .fsck = BD_FS_FSCK_CHECK | BD_FS_FSCK_REPAIR,
      90              :       .configure = BD_FS_SUPPORT_SET_LABEL | BD_FS_SUPPORT_SET_UUID,
      91              :       .features =  BD_FS_FEATURE_OWNERS,
      92              :       .partition_id = "0x83",
      93              :       .partition_type = "0fc63daf-8483-4772-8e79-3d69d8477de4",
      94              :       .min_size = 1 MiB,
      95              :       .max_size = 1 EiB },
      96              :     /* XFS */
      97              :     { .resize = BD_FS_ONLINE_GROW | BD_FS_OFFLINE_GROW,
      98              :       .mkfs = BD_FS_MKFS_LABEL | BD_FS_MKFS_UUID | BD_FS_MKFS_DRY_RUN | BD_FS_MKFS_NODISCARD |
      99              :               BD_FS_MKFS_FORCE,
     100              :       .fsck = BD_FS_FSCK_CHECK | BD_FS_FSCK_REPAIR,
     101              :       .configure = BD_FS_SUPPORT_SET_LABEL | BD_FS_SUPPORT_SET_UUID,
     102              :       .features =  BD_FS_FEATURE_OWNERS,
     103              :       .partition_id = "0x83",
     104              :       .partition_type = "0fc63daf-8483-4772-8e79-3d69d8477de4",
     105              :       .min_size = 300 MiB,
     106              :       .max_size = 16 EiB - 1 },
     107              :     /* VFAT */
     108              :     { .resize = BD_FS_OFFLINE_GROW | BD_FS_OFFLINE_SHRINK,
     109              :       .mkfs = BD_FS_MKFS_LABEL | BD_FS_MKFS_UUID | BD_FS_MKFS_FORCE | BD_FS_MKFS_NOPT,
     110              :       .fsck = BD_FS_FSCK_CHECK | BD_FS_FSCK_REPAIR,
     111              :       .configure = BD_FS_SUPPORT_SET_LABEL | BD_FS_SUPPORT_SET_UUID,
     112              :       .features = BD_FS_FEATURE_PARTITION_TABLE,
     113              :       .partition_id = "0x0c",
     114              :       .partition_type = "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7",
     115              :       .min_size = 1 MiB,
     116              :       .max_size = 1 TiB },
     117              :     /* NTFS */
     118              :     { .resize = BD_FS_OFFLINE_GROW | BD_FS_OFFLINE_SHRINK,
     119              :       .mkfs = BD_FS_MKFS_LABEL | BD_FS_MKFS_DRY_RUN,
     120              :       .fsck = BD_FS_FSCK_CHECK | BD_FS_FSCK_REPAIR,
     121              :       .configure = BD_FS_SUPPORT_SET_LABEL | BD_FS_SUPPORT_SET_UUID,
     122              :       .features = 0,
     123              :       .partition_id = "0x07",
     124              :       .partition_type = "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7",
     125              :       .min_size = 1 MiB,
     126              :       .max_size = 16 TiB },
     127              :     /* F2FS */
     128              :     { .resize = BD_FS_OFFLINE_GROW | BD_FS_OFFLINE_SHRINK,
     129              :       .mkfs = BD_FS_MKFS_LABEL | BD_FS_MKFS_NODISCARD | BD_FS_MKFS_FORCE,
     130              :       .fsck = BD_FS_FSCK_CHECK | BD_FS_FSCK_REPAIR,
     131              :       .configure =  0,
     132              :       .features = BD_FS_FEATURE_OWNERS,
     133              :       .partition_id = "0x83",
     134              :       .partition_type = "0fc63daf-8483-4772-8e79-3d69d8477de4",
     135              :       .min_size = 1 MiB,
     136              :       .max_size = 16 TiB },
     137              :     /* NILFS2 */
     138              :     { .resize = BD_FS_ONLINE_GROW | BD_FS_ONLINE_SHRINK,
     139              :       .mkfs = BD_FS_MKFS_LABEL | BD_FS_MKFS_DRY_RUN | BD_FS_MKFS_NODISCARD | BD_FS_MKFS_FORCE,
     140              :       .fsck = 0,
     141              :       .configure = BD_FS_SUPPORT_SET_LABEL | BD_FS_SUPPORT_SET_UUID,
     142              :       .features = BD_FS_FEATURE_OWNERS,
     143              :       .partition_id = "0x83",
     144              :       .partition_type = "0fc63daf-8483-4772-8e79-3d69d8477de4",
     145              :       .min_size = 1 MiB,
     146              :       .max_size = 16 TiB },
     147              :     /* EXFAT */
     148              :     { .resize = 0,
     149              :       .mkfs = BD_FS_MKFS_LABEL,
     150              :       .fsck = BD_FS_FSCK_CHECK | BD_FS_FSCK_REPAIR,
     151              :       .configure = BD_FS_SUPPORT_SET_LABEL | BD_FS_SUPPORT_SET_UUID,
     152              :       .features = 0,
     153              :       .partition_id = "0x07",
     154              :       .partition_type = "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7",
     155              :       .min_size = 3 MiB,
     156              :       .max_size = 512 TiB },
     157              :     /* BTRFS */
     158              :     { .resize = BD_FS_ONLINE_GROW | BD_FS_ONLINE_SHRINK,
     159              :       .mkfs = BD_FS_MKFS_LABEL | BD_FS_MKFS_UUID | BD_FS_MKFS_NODISCARD | BD_FS_MKFS_FORCE,
     160              :       .fsck = BD_FS_FSCK_CHECK | BD_FS_FSCK_REPAIR,
     161              :       .configure = BD_FS_SUPPORT_SET_LABEL | BD_FS_SUPPORT_SET_UUID,
     162              :       .features = BD_FS_FEATURE_OWNERS,
     163              :       .partition_id = "0x83",
     164              :       .partition_type = "0fc63daf-8483-4772-8e79-3d69d8477de4",
     165              :       .min_size = 256 MiB,
     166              :       .max_size = 16 EiB - 1 },
     167              :     /* UDF */
     168              :     { .resize = 0,
     169              :       .mkfs = BD_FS_MKFS_LABEL | BD_FS_MKFS_UUID,
     170              :       .fsck = 0,
     171              :       .configure = BD_FS_SUPPORT_SET_LABEL | BD_FS_SUPPORT_SET_UUID,
     172              :       .features = BD_FS_FEATURE_OWNERS | BD_FS_FEATURE_PARTITION_TABLE,
     173              :       .partition_id = "0x07",
     174              :       .partition_type = "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7",
     175              :       .min_size = 2 MiB,
     176              :       .max_size = 16 TiB },
     177              : };
     178              : 
     179              : /**
     180              :  * BDFSInfo:
     181              :  * @type: filesystem identifier, must be present
     182              :  * @mkfs_util: required utility for filesystem creation, "" if not needed and NULL for no support
     183              :  * @check_util: required utility for consistency checking, "" if not needed and NULL for no support
     184              :  * @repair_util: required utility for repair, "" if not needed and NULL for no support
     185              :  * @resize_util: required utility for resize, "" if not needed and NULL for no support
     186              :  * @label_util: required utility for labelling, "" if not needed and NULL for no support
     187              :  * @info_util: required utility for getting information about the filesystem, "" if not needed and NULL for no support
     188              :  * @uuid_util: required utility for setting UUID, "" if not needed and NULL for no support
     189              :  */
     190              : typedef struct BDFSInfo {
     191              :     const gchar *type;
     192              :     const gchar *mkfs_util;
     193              :     const gchar *check_util;
     194              :     const gchar *repair_util;
     195              :     const gchar *resize_util;
     196              :     const gchar *minsize_util;
     197              :     const gchar *label_util;
     198              :     const gchar *info_util;
     199              :     const gchar *uuid_util;
     200              : } BDFSInfo;
     201              : 
     202              : const BDFSInfo fs_info[BD_FS_LAST_FS] = {
     203              :     /* padding for BD_FS_TECH_GENERIC and MOUNT to make accessing the FS techs simpler */
     204              :     { 0 }, { 0 },
     205              :     /* EXT2 */
     206              :     { .type = "ext2",
     207              :       .mkfs_util = "mkfs.ext2",
     208              :       .check_util = "e2fsck",
     209              :       .repair_util = "e2fsck",
     210              :       .resize_util = "resize2fs",
     211              :       .minsize_util = "resize2fs",
     212              :       .label_util = "tune2fs",
     213              :       .info_util = "dumpe2fs",
     214              :       .uuid_util = "tune2fs" },
     215              :     /* EXT3 */
     216              :     { .type = "ext3",
     217              :       .mkfs_util = "mkfs.ext3",
     218              :       .check_util = "e2fsck",
     219              :       .repair_util = "e2fsck",
     220              :       .resize_util = "resize2fs",
     221              :       .minsize_util = "resize2fs",
     222              :       .label_util = "tune2fs",
     223              :       .info_util = "dumpe2fs",
     224              :       .uuid_util = "tune2fs" },
     225              :     /* EXT4 */
     226              :     { .type = "ext4",
     227              :       .mkfs_util = "mkfs.ext4",
     228              :       .check_util = "e2fsck",
     229              :       .repair_util = "e2fsck",
     230              :       .resize_util = "resize2fs",
     231              :       .minsize_util = "resize2fs",
     232              :       .label_util = "tune2fs",
     233              :       .info_util = "dumpe2fs",
     234              :       .uuid_util = "tune2fs" },
     235              :     /* XFS */
     236              :     { .type = "xfs",
     237              :       .mkfs_util = "mkfs.xfs",
     238              :       .check_util = "xfs_db",
     239              :       .repair_util = "xfs_repair",
     240              :       .resize_util = "xfs_growfs",
     241              :       .minsize_util = NULL,
     242              :       .label_util = "xfs_admin",
     243              :       .info_util = "xfs_admin",
     244              :       .uuid_util = "xfs_admin" },
     245              :     /* VFAT */
     246              :     { .type = "vfat",
     247              :       .mkfs_util = "mkfs.vfat",
     248              :       .check_util = "fsck.vfat",
     249              :       .repair_util = "fsck.vfat",
     250              :       .resize_util = "vfat-resize",
     251              :       .minsize_util = NULL,
     252              :       .label_util = "fatlabel",
     253              :       .info_util = "fsck.vfat",
     254              :       .uuid_util = "fatlabel" },
     255              :     /* NTFS */
     256              :     { .type = "ntfs",
     257              :       .mkfs_util = "mkfs.ntfs",
     258              :       .check_util = "ntfsfix",
     259              :       .repair_util = "ntfsfix",
     260              :       .resize_util = "ntfsresize",
     261              :       .minsize_util = "ntfsresize",
     262              :       .label_util = "ntfslabel",
     263              :       .info_util = "ntfsinfo",
     264              :       .uuid_util = "ntfslabel" },
     265              :     /* F2FS */
     266              :     { .type = "f2fs",
     267              :       .mkfs_util = "mkfs.f2fs",
     268              :       .check_util = "fsck.f2fs",
     269              :       .repair_util = "fsck.f2fs",
     270              :       .resize_util = "resize.f2fs",
     271              :       .minsize_util = NULL,
     272              :       .label_util = NULL,
     273              :       .info_util = "dump.f2fs",
     274              :       .uuid_util = NULL },
     275              :     /* NILFS2 */
     276              :     { .type = "nilfs2",
     277              :       .mkfs_util = "mkfs.nilfs2",
     278              :       .check_util = NULL,
     279              :       .repair_util = NULL,
     280              :       .resize_util = "nilfs-resize",
     281              :       .minsize_util = NULL,
     282              :       .label_util = "nilfs-tune",
     283              :       .info_util = "nilfs-tune",
     284              :       .uuid_util = "nilfs-tune" },
     285              :     /* EXFAT */
     286              :     { .type = "exfat",
     287              :       .mkfs_util = "mkfs.exfat",
     288              :       .check_util = "fsck.exfat",
     289              :       .repair_util = "fsck.exfat",
     290              :       .resize_util = NULL,
     291              :       .minsize_util = NULL,
     292              :       .label_util = "tune.exfat",
     293              :       .info_util = "tune.exfat",
     294              :       .uuid_util = "tune.exfat" },
     295              :     /* BTRFS */
     296              :     { .type = "btrfs",
     297              :       .mkfs_util = "mkfs.btrfs",
     298              :       .check_util = "btrfsck",
     299              :       .repair_util = "btrfsck",
     300              :       .resize_util = "btrfs",
     301              :       .minsize_util = NULL,
     302              :       .label_util = "btrfs",
     303              :       .info_util = "btrfs",
     304              :       .uuid_util = "btrfstune" },
     305              :     /* UDF */
     306              :     { .type = "udf",
     307              :       .mkfs_util = "mkudffs",
     308              :       .check_util = NULL,
     309              :       .repair_util = NULL,
     310              :       .resize_util = NULL,
     311              :       .minsize_util = NULL,
     312              :       .label_util = "udflabel",
     313              :       .info_util = "udfinfo",
     314              :       .uuid_util = "udflabel" },
     315              : };
     316              : 
     317              : /**
     318              :  * bd_fs_supported_filesystems:
     319              :  * @error: (out) (optional): currently unused
     320              :  *
     321              :  * Returns: (transfer container) (array zero-terminated=1): list of filesystems supported by this plugin
     322              :  *
     323              :  * Note: This returns filesystems supported by libblockdev, but not necessarily
     324              :  *       by the systems this is running on, for this information you need to
     325              :  *       run one of the `bd_fs_can_` functions.
     326              :  *
     327              :  * Tech category: always available
     328              :  */
     329            1 : const gchar** bd_fs_supported_filesystems (GError **error G_GNUC_UNUSED) {
     330            1 :     const gchar **filesystems = g_new0 (const gchar *, BD_FS_LAST_FS - BD_FS_OFFSET + 1);
     331            1 :     gint i = 0;
     332              : 
     333           12 :     for (i = 0; i < BD_FS_LAST_FS - BD_FS_OFFSET; i++)
     334           11 :         filesystems[i] = fs_info[i + BD_FS_OFFSET].type;
     335              : 
     336            1 :     return filesystems;
     337              : }
     338              : 
     339              : /**
     340              :  * fstype_to_tech: (skip)
     341              :  * @fstype: filesystem type to get tech for
     342              :  *
     343              :  * Returns %BDFSTech for specified @fstype. Returns
     344              :  * %BD_FS_TECH_GENERIC for unknown/unsupported filesystems.
     345              :  */
     346           71 : static BDFSTech fstype_to_tech (const gchar *fstype) {
     347           71 :     if (g_strcmp0 (fstype, "exfat") == 0) {
     348            3 :         return BD_FS_TECH_EXFAT;
     349           68 :     } else if (g_strcmp0 (fstype, "ext2") == 0) {
     350            3 :         return BD_FS_TECH_EXT2;
     351           65 :     } else if (g_strcmp0 (fstype, "ext3") == 0) {
     352            3 :         return BD_FS_TECH_EXT3;
     353           62 :     } else if (g_strcmp0 (fstype, "ext4") == 0) {
     354           13 :         return BD_FS_TECH_EXT4;
     355           49 :     } else if (g_strcmp0 (fstype, "f2fs") == 0) {
     356            4 :         return BD_FS_TECH_F2FS;
     357           45 :     } else if (g_strcmp0 (fstype, "nilfs2") == 0) {
     358            5 :         return BD_FS_TECH_NILFS2;
     359           40 :     } else if (g_strcmp0 (fstype, "ntfs") == 0) {
     360            4 :         return BD_FS_TECH_NTFS;
     361           36 :     } else if (g_strcmp0 (fstype, "vfat") == 0) {
     362            7 :         return BD_FS_TECH_VFAT;
     363           29 :     } else if (g_strcmp0 (fstype, "xfs") == 0) {
     364           12 :         return BD_FS_TECH_XFS;
     365           17 :     } else if (g_strcmp0 (fstype, "btrfs") == 0) {
     366            3 :         return BD_FS_TECH_BTRFS;
     367           14 :     } else if (g_strcmp0 (fstype, "udf") == 0) {
     368            7 :         return BD_FS_TECH_UDF;
     369              :     } else {
     370            7 :         return BD_FS_TECH_GENERIC;
     371              :     }
     372              : }
     373              : 
     374              : /**
     375              :  * bd_fs_wipe:
     376              :  * @device: the device to wipe signatures from
     377              :  * @all: whether to wipe all (%TRUE) signatures or just the first (%FALSE) one
     378              :  * @force: whether to wipe signatures on a mounted @device
     379              :  * @error: (out) (optional): place to store error (if any)
     380              :  *
     381              :  * Returns: whether signatures were successfully wiped on @device or not
     382              :  *
     383              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_WIPE
     384              :  */
     385          116 : gboolean bd_fs_wipe (const gchar *device, gboolean all, gboolean force, GError **error) {
     386          116 :     blkid_probe probe = NULL;
     387          116 :     gint fd = 0;
     388          116 :     gint status = 0;
     389          116 :     guint64 progress_id = 0;
     390          116 :     gchar *msg = NULL;
     391          116 :     guint n_try = 0;
     392          116 :     gint mode = 0;
     393          116 :     GError *l_error = NULL;
     394              : 
     395          116 :     msg = g_strdup_printf ("Started wiping signatures from the device '%s'", device);
     396          116 :     progress_id = bd_utils_report_started (msg);
     397          116 :     g_free (msg);
     398              : 
     399          116 :     probe = blkid_new_probe ();
     400          116 :     if (!probe) {
     401            0 :         g_set_error (&l_error, BD_FS_ERROR, BD_FS_ERROR_FAIL,
     402              :                      "Failed to create a new probe");
     403            0 :         bd_utils_report_finished (progress_id, l_error->message);
     404            0 :         g_propagate_error (error, l_error);
     405            0 :         return FALSE;
     406              :     }
     407              : 
     408          116 :     mode = O_RDWR | O_CLOEXEC;
     409          116 :     if (!force)
     410          114 :         mode |= O_EXCL;
     411              : 
     412          116 :     fd = open (device, mode);
     413          116 :     if (fd == -1) {
     414            4 :         g_set_error (&l_error, BD_FS_ERROR, BD_FS_ERROR_FAIL,
     415              :                      "Failed to open the device '%s': %s",
     416            4 :                      device, strerror_l (errno, _C_LOCALE));
     417            4 :         blkid_free_probe (probe);
     418            4 :         bd_utils_report_finished (progress_id, l_error->message);
     419            4 :         g_propagate_error (error, l_error);
     420            4 :         return FALSE;
     421              :     }
     422              : 
     423              :     /* we may need to try multiple times with some delays in case the device is
     424              :        busy at the very moment */
     425          224 :     for (n_try=5, status=-1; (status != 0) && (n_try > 0); n_try--) {
     426          112 :         status = blkid_probe_set_device (probe, fd, 0, 0);
     427          112 :         if (status != 0)
     428            0 :             g_usleep (100 * 1000); /* microseconds */
     429              :     }
     430          112 :     if (status != 0) {
     431            0 :         g_set_error (&l_error, BD_FS_ERROR, BD_FS_ERROR_FAIL,
     432              :                      "Failed to create a probe for the device '%s'", device);
     433            0 :         blkid_free_probe (probe);
     434            0 :         synced_close (fd);
     435            0 :         bd_utils_report_finished (progress_id, l_error->message);
     436            0 :         g_propagate_error (error, l_error);
     437            0 :         return FALSE;
     438              :     }
     439              : 
     440          112 :     blkid_probe_enable_partitions (probe, 1);
     441          112 :     blkid_probe_set_partitions_flags (probe, BLKID_PARTS_MAGIC);
     442          112 :     blkid_probe_enable_superblocks (probe, 1);
     443          112 :     blkid_probe_set_superblocks_flags (probe, BLKID_SUBLKS_MAGIC | BLKID_SUBLKS_BADCSUM);
     444              : 
     445              :     /* we may need to try multiple times with some delays in case the device is
     446              :        busy at the very moment */
     447          155 :     for (n_try=5, status=-1; (status != 0) && (n_try > 0); n_try--) {
     448          112 :         status = blkid_do_safeprobe (probe);
     449          112 :         if (status == 1)
     450           69 :             break;
     451           43 :         if (status < 0)
     452            0 :             g_usleep (100 * 1000); /* microseconds */
     453              :     }
     454          112 :     if (status == 1) {
     455           69 :         g_set_error (&l_error, BD_FS_ERROR, BD_FS_ERROR_NOFS,
     456              :                      "No signature detected on the device '%s'", device);
     457           69 :         blkid_free_probe (probe);
     458           69 :         synced_close (fd);
     459           69 :         bd_utils_report_finished (progress_id, l_error->message);
     460           69 :         g_propagate_error (error, l_error);
     461           69 :         return FALSE;
     462              :     }
     463              : 
     464           43 :     blkid_reset_probe (probe);
     465           43 :     status = blkid_do_probe (probe);
     466              : 
     467           43 :     if (status < 0) {
     468            0 :         g_set_error (&l_error, BD_FS_ERROR, BD_FS_ERROR_FAIL,
     469              :                      "Failed to probe the device '%s'", device);
     470            0 :         blkid_free_probe (probe);
     471            0 :         synced_close (fd);
     472            0 :         bd_utils_report_finished (progress_id, l_error->message);
     473            0 :         g_propagate_error (error, l_error);
     474            0 :         return FALSE;
     475              :     }
     476              : 
     477           43 :     status = blkid_do_wipe (probe, FALSE);
     478           43 :     if (status != 0) {
     479            0 :         g_set_error (&l_error, BD_FS_ERROR, BD_FS_ERROR_FAIL,
     480              :                      "Failed to wipe signatures on the device '%s'", device);
     481            0 :         blkid_free_probe (probe);
     482            0 :         synced_close (fd);
     483            0 :         bd_utils_report_finished (progress_id, l_error->message);
     484            0 :         g_propagate_error (error, l_error);
     485            0 :         return FALSE;
     486              :     }
     487           63 :     while (all && (blkid_do_probe (probe) == 0)) {
     488           20 :         status = blkid_do_wipe (probe, FALSE);
     489           20 :         if (status != 0) {
     490            0 :             g_set_error (&l_error, BD_FS_ERROR, BD_FS_ERROR_FAIL,
     491              :                          "Failed to wipe signatures on the device '%s'", device);
     492            0 :             blkid_free_probe (probe);
     493            0 :             synced_close (fd);
     494            0 :             bd_utils_report_finished (progress_id, l_error->message);
     495            0 :             g_propagate_error (error, l_error);
     496            0 :             return FALSE;
     497              :         }
     498              :     }
     499              : 
     500           43 :     blkid_free_probe (probe);
     501           43 :     synced_close (fd);
     502              : 
     503           43 :     bd_utils_report_finished (progress_id, "Completed");
     504              : 
     505           43 :     return TRUE;
     506              : }
     507              : 
     508              : /**
     509              :  * bd_fs_clean:
     510              :  * @device: the device to clean
     511              :  * @force: whether to wipe signatures on a mounted @device
     512              :  * @error: (out) (optional): place to store error (if any)
     513              :  *
     514              :  * Clean all signatures from @device.
     515              :  * Difference between this and bd_fs_wipe() is that this function doesn't
     516              :  * return error if @device is already empty. This will also always remove
     517              :  * all signatures from @device, not only the first one.
     518              :  *
     519              :  * Returns: whether @device was successfully cleaned or not
     520              :  *
     521              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_WIPE
     522              :  */
     523           84 : gboolean bd_fs_clean (const gchar *device, gboolean force, GError **error) {
     524           84 :   gboolean ret = FALSE;
     525           84 :   GError *l_error = NULL;
     526              : 
     527           84 :   ret = bd_fs_wipe (device, TRUE, force, &l_error);
     528              : 
     529           84 :   if (!ret) {
     530           70 :     if (g_error_matches (l_error, BD_FS_ERROR, BD_FS_ERROR_NOFS)) {
     531              :         /* ignore 'empty device' error */
     532           68 :         g_clear_error (&l_error);
     533           68 :         return TRUE;
     534              :     } else {
     535            2 :         g_propagate_error (error, l_error);
     536            2 :         return FALSE;
     537              :     }
     538              :   } else
     539           14 :       return TRUE;
     540              : }
     541              : 
     542              : /**
     543              :  * bd_fs_get_fstype:
     544              :  * @device: the device to probe
     545              :  * @error: (out) (optional): place to store error (if any)
     546              :  *
     547              :  * Get first signature on @device as a string.
     548              :  *
     549              :  * Returns: (transfer full): type of filesystem found on @device, %NULL in case
     550              :  *                           no signature has been detected or in case of error
     551              :  *                           (@error is set in this case)
     552              :  *
     553              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_QUERY
     554              :  */
     555          140 : gchar* bd_fs_get_fstype (const gchar *device,  GError **error) {
     556          140 :     blkid_probe probe = NULL;
     557          140 :     gint fd = 0;
     558          140 :     gint status = 0;
     559          140 :     const gchar *value = NULL;
     560          140 :     gchar *fstype = NULL;
     561          140 :     size_t len = 0;
     562          140 :     guint n_try = 0;
     563              : 
     564          140 :     probe = blkid_new_probe ();
     565          140 :     if (!probe) {
     566            0 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_FAIL,
     567              :                      "Failed to create a new probe");
     568            0 :         return NULL;
     569              :     }
     570              : 
     571          140 :     fd = open (device, O_RDONLY|O_CLOEXEC);
     572          140 :     if (fd == -1) {
     573            0 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_FAIL,
     574              :                      "Failed to open the device '%s': %s",
     575            0 :                      device, strerror_l (errno, _C_LOCALE));
     576            0 :         blkid_free_probe (probe);
     577            0 :         return NULL;
     578              :     }
     579              : 
     580              :     /* we may need to try multiple times with some delays in case the device is
     581              :        busy at the very moment */
     582          280 :     for (n_try=5, status=-1; (status != 0) && (n_try > 0); n_try--) {
     583          140 :         status = blkid_probe_set_device (probe, fd, 0, 0);
     584          140 :         if (status != 0)
     585            0 :             g_usleep (100 * 1000); /* microseconds */
     586              :     }
     587          140 :     if (status != 0) {
     588            0 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_FAIL,
     589              :                      "Failed to create a probe for the device '%s'", device);
     590            0 :         blkid_free_probe (probe);
     591            0 :         synced_close (fd);
     592            0 :         return NULL;
     593              :     }
     594              : 
     595          140 :     blkid_probe_enable_partitions (probe, 1);
     596          140 :     blkid_probe_set_partitions_flags (probe, BLKID_PARTS_MAGIC);
     597          140 :     blkid_probe_enable_superblocks (probe, 1);
     598          140 :     blkid_probe_set_superblocks_flags (probe, BLKID_SUBLKS_USAGE | BLKID_SUBLKS_TYPE |
     599              :                                               BLKID_SUBLKS_MAGIC | BLKID_SUBLKS_BADCSUM);
     600              : 
     601              :     /* we may need to try multiple times with some delays in case the device is
     602              :        busy at the very moment */
     603          280 :     for (n_try=5, status=-1; !(status == 0 || status == 1) && (n_try > 0); n_try--) {
     604          140 :         status = blkid_do_safeprobe (probe);
     605          140 :         if (status < 0)
     606            0 :             g_usleep (100 * 1000); /* microseconds */
     607              :     }
     608          140 :     if (status < 0) {
     609              :         /* -1 or -2 = error during probing*/
     610            0 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_FAIL,
     611              :                      "Failed to probe the device '%s'", device);
     612            0 :         blkid_free_probe (probe);
     613            0 :         synced_close (fd);
     614            0 :         return NULL;
     615          140 :     } else if (status == 1) {
     616              :         /* 1 = nothing detected */
     617           11 :         blkid_free_probe (probe);
     618           11 :         synced_close (fd);
     619           11 :         return NULL;
     620              :     }
     621              : 
     622          129 :     status = blkid_probe_lookup_value (probe, "USAGE", &value, &len);
     623          129 :     if (status != 0) {
     624            0 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_FAIL,
     625              :                      "Failed to get usage for the device '%s'", device);
     626            0 :         blkid_free_probe (probe);
     627            0 :         synced_close (fd);
     628            0 :         return NULL;
     629              :     }
     630              : 
     631          129 :     if (strncmp (value, "filesystem", 10) != 0) {
     632            0 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_INVAL,
     633              :                      "The signature on the device '%s' is of type '%s', not 'filesystem'", device, value);
     634            0 :         blkid_free_probe (probe);
     635            0 :         synced_close (fd);
     636            0 :         return NULL;
     637              :     }
     638              : 
     639          129 :     status = blkid_probe_lookup_value (probe, "TYPE", &value, &len);
     640          129 :     if (status != 0) {
     641            0 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_FAIL,
     642              :                      "Failed to get filesystem type for the device '%s'", device);
     643            0 :         blkid_free_probe (probe);
     644            0 :         synced_close (fd);
     645            0 :         return NULL;
     646              :     }
     647              : 
     648          129 :     fstype = g_strdup (value);
     649          129 :     blkid_free_probe (probe);
     650          129 :     synced_close (fd);
     651              : 
     652          129 :     return fstype;
     653              : }
     654              : 
     655              : /* taken from kernel source: fs/xfs/libxfs/xfs_log_format.h: */
     656              :  #define _XFS_UQUOTA_ACCT 0x0001  /* user quota accounting ON */
     657              :  #define _XFS_UQUOTA_ENFD 0x0002  /* user quota limits enforced */
     658              :  #define _XFS_GQUOTA_ACCT 0x0040  /* group quota accounting ON */
     659              :  #define _XFS_GQUOTA_ENFD 0x0080  /* group quota limits enforced */
     660              :  #define _XFS_PQUOTA_ACCT 0x0008  /* project quota accounting ON */
     661              :  #define _XFS_PQUOTA_ENFD 0x0200  /* project quota limits enforced */
     662              : 
     663            8 : static gboolean xfs_quota_mount_options (const gchar *device, GString *options, GError **error) {
     664            8 :     g_autofree gchar *output = NULL;
     665            8 :     gboolean success = FALSE;
     666            8 :     const gchar *args[8] = {"xfs_db", "-r", device, "-c", "sb 0", "-c", "p qflags", NULL};
     667            8 :     guint64 flags = 0;
     668              : 
     669            8 :     success = bd_utils_exec_and_capture_output (args, NULL, &output, error);
     670            8 :     if (!success) {
     671              :         /* error is already populated */
     672            0 :         return FALSE;
     673              :     }
     674              : 
     675            8 :     if (!g_str_has_prefix (output, "qflags = ")) {
     676            0 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_FAIL,
     677              :                      "Failed to parse XFS quota flags for %s from %s.", device, output);
     678            0 :         return FALSE;
     679              :     }
     680              : 
     681            8 :     flags = g_ascii_strtoull (output + 9, NULL, 16);
     682            8 :     if (flags & _XFS_UQUOTA_ACCT) {
     683            2 :         if (flags & _XFS_UQUOTA_ENFD)
     684            2 :             g_string_append_printf (options, "uquota,");
     685              :         else
     686            0 :             g_string_append_printf (options, "uqnoenforce,");
     687              :     }
     688              : 
     689            8 :     if (flags & _XFS_GQUOTA_ACCT) {
     690            2 :         if (flags & _XFS_GQUOTA_ENFD)
     691            2 :             g_string_append_printf (options, "gquota,");
     692              :         else
     693            0 :             g_string_append_printf (options, "gqnoenforce,");
     694              :     }
     695              : 
     696            8 :     if (flags & _XFS_PQUOTA_ACCT) {
     697            2 :         if (flags & _XFS_PQUOTA_ENFD)
     698            2 :             g_string_append_printf (options, "pquota,");
     699              :         else
     700            0 :             g_string_append_printf (options, "pqnoenforce,");
     701              :     }
     702              : 
     703            8 :     return TRUE;
     704              : }
     705              : 
     706              : /**
     707              :  * fs_mount:
     708              :  * @device: the device to mount for an FS operation
     709              :  * @fstype: (nullable): filesystem type on @device
     710              :  * @read_only: whether to mount @device ro or rw
     711              :  * @unmount: (out): whether caller should unmount the device (was mounted by us) or
     712              :  *                  not (was already mounted before)
     713              :  * @error: (out) (optional): place to store error (if any)
     714              :  *
     715              :  * This is just a helper function for FS operations that need @device to be mounted.
     716              :  * If the device is already mounted, this will just return the existing mountpoint.
     717              :  * If the device is not mounted, we will mount it to a temporary directory and set
     718              :  * @unmount to %TRUE.
     719              :  *
     720              :  * Returns: (transfer full): mountpoint @device is mounted at (or %NULL in case of error)
     721              :  */
     722           30 : static gchar* fs_mount (const gchar *device, gchar *fstype, gboolean read_only, gboolean *unmount, GError **error) {
     723           30 :     gchar *mountpoint = NULL;
     724           30 :     gboolean ret = FALSE;
     725           30 :     GError *l_error = NULL;
     726           30 :     GString *options = NULL;
     727           30 :     g_autofree gchar *options_str = NULL;
     728              : 
     729           30 :     mountpoint = bd_fs_get_mountpoint (device, &l_error);
     730           30 :     if (!mountpoint) {
     731           22 :         if (l_error == NULL) {
     732              :             /* device is not mounted -- we need to mount it */
     733           22 :             mountpoint = g_dir_make_tmp ("blockdev.XXXXXX", NULL);
     734           22 :             if (!mountpoint) {
     735            0 :                 g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_FAIL,
     736              :                              "Failed to create temporary directory for mounting '%s'.", device);
     737            0 :                 return NULL;
     738              :             }
     739              : 
     740           22 :             options = g_string_new (NULL);
     741           22 :             if (g_strcmp0 (fstype, "xfs") == 0) {
     742            8 :                 ret = xfs_quota_mount_options (device, options, &l_error);
     743            8 :                 if (!ret) {
     744            0 :                     bd_utils_log_format (BD_UTILS_LOG_INFO, "Failed to get XFS mount options: %s",
     745            0 :                                          l_error->message);
     746            0 :                     g_clear_error (&l_error);
     747              :                 }
     748              :             }
     749           22 :             if (read_only)
     750            8 :                 g_string_append_printf (options, "nosuid,nodev,ro");
     751              :             else
     752           14 :                 g_string_append_printf (options, "nosuid,nodev");
     753           22 :             options_str = g_string_free (options, FALSE);
     754              : 
     755           22 :             ret = bd_fs_mount (device, mountpoint, fstype, options_str, NULL, &l_error);
     756           22 :             if (!ret) {
     757            0 :                 g_propagate_prefixed_error (error, l_error, "Failed to mount '%s': ", device);
     758            0 :                 if (g_rmdir (mountpoint) != 0)
     759            0 :                     bd_utils_log_format (BD_UTILS_LOG_INFO, "Failed to remove temporary mountpoint '%s'",
     760              :                                          mountpoint);
     761            0 :                 g_free (mountpoint);
     762            0 :                 return NULL;
     763              :             } else
     764           22 :                 *unmount = TRUE;
     765              :         } else {
     766            0 :             g_propagate_prefixed_error (error, l_error,
     767              :                                         "Error when trying to get mountpoint for '%s': ", device);
     768            0 :             g_free (mountpoint);
     769            0 :             return NULL;
     770              :         }
     771              :     } else
     772            8 :         *unmount = FALSE;
     773              : 
     774           30 :     return mountpoint;
     775              : }
     776              : 
     777           22 : static gboolean fs_unmount (const gchar *device, const gchar *mountpoint, const gchar *operation, GError **error) {
     778           22 :     gboolean ret = FALSE;
     779           22 :     GError *local_error = NULL;
     780              : 
     781           22 :     ret = bd_fs_unmount (mountpoint, FALSE, FALSE, NULL, &local_error);
     782           22 :     if (!ret) {
     783            0 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_UNMOUNT_FAIL,
     784              :                      "Failed to unmount '%s' after %s it: %s",
     785            0 :                      device, operation, local_error->message);
     786            0 :         g_clear_error (&local_error);
     787            0 :         return FALSE;
     788              :     } else {
     789           22 :         if (g_rmdir (mountpoint) != 0)
     790            0 :             bd_utils_log_format (BD_UTILS_LOG_INFO, "Failed to remove temporary mountpoint '%s'",
     791              :                                  mountpoint);
     792              :     }
     793           22 :     return TRUE;
     794              : }
     795              : 
     796              : 
     797              : /**
     798              :  * xfs_resize_device:
     799              :  * @device: the device the file system of which to resize
     800              :  * @new_size: new requested size for the file system *in bytes*
     801              :  *            (if 0, the file system is adapted to the underlying block device)
     802              :  * @extra: (nullable) (array zero-terminated=1): extra options for the resize (right now
     803              :  *                                                 passed to the 'xfs_growfs' utility)
     804              :  * @error: (out) (optional): place to store error (if any)
     805              :  *
     806              :  * This is just a helper function for bd_fs_resize.
     807              :  *
     808              :  * Returns: whether the file system on @device was successfully resized or not
     809              :  */
     810           12 : static gboolean xfs_resize_device (const gchar *device, guint64 new_size, const BDExtraArg **extra, GError **error) {
     811           12 :     g_autofree gchar* mountpoint = NULL;
     812           12 :     gboolean ret = FALSE;
     813           12 :     gboolean success = FALSE;
     814           12 :     gboolean unmount = FALSE;
     815           12 :     GError *local_error = NULL;
     816           12 :     BDFSXfsInfo* xfs_info = NULL;
     817              : 
     818           12 :     xfs_info = bd_fs_xfs_get_info (device, error);
     819           12 :     if (!xfs_info) {
     820            0 :         return FALSE;
     821              :     }
     822              : 
     823           12 :     mountpoint = fs_mount (device, "xfs", FALSE, &unmount, error);
     824           12 :     if (!mountpoint)
     825            0 :         return FALSE;
     826              : 
     827           12 :     new_size = (new_size + xfs_info->block_size - 1) / xfs_info->block_size;
     828           12 :     bd_fs_xfs_info_free (xfs_info);
     829              : 
     830           12 :     success = bd_fs_xfs_resize (mountpoint, new_size, extra, error);
     831              : 
     832           12 :     if (unmount) {
     833            8 :         ret = fs_unmount (device, mountpoint, "resizing", &local_error);
     834            8 :         if (!ret) {
     835            0 :             if (success) {
     836              :                 /* resize was successful but unmount failed */
     837            0 :                 g_propagate_error (error, local_error);
     838            0 :                 return FALSE;
     839              :             } else
     840              :                 /* both resize and unmount were unsuccessful but the error
     841              :                    from the resize is more important so just ignore the
     842              :                    unmount error */
     843            0 :                 g_clear_error (&local_error);
     844              :         }
     845              :     }
     846              : 
     847           12 :     return success;
     848              : }
     849              : 
     850            0 : static gboolean f2fs_resize_device (const gchar *device, guint64 new_size, GError **error) {
     851            0 :     BDFSF2FSInfo *info = NULL;
     852            0 :     gboolean safe = FALSE;
     853              : 
     854            0 :     info = bd_fs_f2fs_get_info (device, error);
     855            0 :     if (!info) {
     856              :         /* error is already populated */
     857            0 :         return FALSE;
     858              :     }
     859              : 
     860              :     /* round to nearest sector_size multiple */
     861            0 :     new_size = (new_size + info->sector_size - 1) / info->sector_size;
     862              : 
     863              :     /* safe must be specified for shrining */
     864            0 :     safe = new_size < info->sector_count && new_size != 0;
     865            0 :     bd_fs_f2fs_info_free (info);
     866              : 
     867            0 :     return bd_fs_f2fs_resize (device, new_size, safe, NULL, error);
     868              : }
     869              : 
     870            2 : static gboolean nilfs2_resize_device (const gchar *device, guint64 new_size, GError **error) {
     871            2 :     g_autofree gchar* mountpoint = NULL;
     872            2 :     gboolean ret = FALSE;
     873            2 :     gboolean success = FALSE;
     874            2 :     gboolean unmount = FALSE;
     875            2 :     GError *local_error = NULL;
     876              : 
     877            2 :     mountpoint = fs_mount (device, "nilfs2", FALSE, &unmount, error);
     878            2 :     if (!mountpoint)
     879            0 :         return FALSE;
     880              : 
     881            2 :     success = bd_fs_nilfs2_resize (device, new_size, error);
     882              : 
     883            2 :     if (unmount) {
     884            2 :         ret = fs_unmount (device, mountpoint, "resizing", &local_error);
     885            2 :         if (!ret) {
     886            0 :             if (success) {
     887              :                 /* resize was successful but unmount failed */
     888            0 :                 g_propagate_error (error, local_error);
     889            0 :                 return FALSE;
     890              :             } else
     891              :                 /* both resize and unmount were unsuccessful but the error
     892              :                    from the resize is more important so just ignore the
     893              :                    unmount error */
     894            0 :                 g_clear_error (&local_error);
     895              :         }
     896              :     }
     897              : 
     898            2 :     return success;
     899              : }
     900              : 
     901           10 : static BDFSBtrfsInfo* btrfs_get_info (const gchar *device, GError **error) {
     902           10 :     g_autofree gchar* mountpoint = NULL;
     903           10 :     gboolean unmount = FALSE;
     904           10 :     gboolean ret = FALSE;
     905           10 :     GError *local_error = NULL;
     906           10 :     BDFSBtrfsInfo* btrfs_info = NULL;
     907              : 
     908           10 :     mountpoint = fs_mount (device, "btrfs", TRUE, &unmount, error);
     909           10 :     if (!mountpoint)
     910            0 :         return NULL;
     911              : 
     912           10 :     btrfs_info = bd_fs_btrfs_get_info (mountpoint, error);
     913              : 
     914           10 :     if (unmount) {
     915            8 :         ret = fs_unmount (device, mountpoint, "getting info", &local_error);
     916            8 :         if (!ret) {
     917            0 :             if (btrfs_info) {
     918              :                 /* info was successful but unmount failed */
     919            0 :                 g_propagate_error (error, local_error);
     920            0 :                 bd_fs_btrfs_info_free (btrfs_info);
     921            0 :                 return NULL;
     922              :             } else
     923              :                 /* both info and unmount were unsuccessful but the error
     924              :                    from the info is more important so just ignore the
     925              :                    unmount error */
     926            0 :                 g_clear_error (&local_error);
     927              :         }
     928              :     }
     929              : 
     930           10 :     return btrfs_info;
     931              : }
     932              : 
     933            4 : static gboolean btrfs_resize_device (const gchar *device, guint64 new_size, GError **error) {
     934            4 :     g_autofree gchar* mountpoint = NULL;
     935            4 :     gboolean ret = FALSE;
     936            4 :     gboolean success = FALSE;
     937            4 :     gboolean unmount = FALSE;
     938            4 :     GError *local_error = NULL;
     939              : 
     940            4 :     mountpoint = fs_mount (device, "btrfs", FALSE, &unmount, error);
     941            4 :     if (!mountpoint)
     942            0 :         return FALSE;
     943              : 
     944            4 :     success = bd_fs_btrfs_resize (mountpoint, new_size, NULL, error);
     945              : 
     946            4 :     if (unmount) {
     947            2 :         ret = fs_unmount (device, mountpoint, "resizing", &local_error);
     948            2 :         if (!ret) {
     949            0 :             if (success) {
     950              :                 /* resize was successful but unmount failed */
     951            0 :                 g_propagate_error (error, local_error);
     952            0 :                 return FALSE;
     953              :             } else
     954              :                 /* both resize and unmount were unsuccessful but the error
     955              :                    from the resize is more important so just ignore the
     956              :                    unmount error */
     957            0 :                 g_clear_error (&local_error);
     958              :         }
     959              :     }
     960              : 
     961            4 :     return success;
     962              : }
     963              : 
     964            2 : static gboolean btrfs_set_label (const gchar *device, const gchar *label, GError **error) {
     965            2 :     g_autofree gchar* mountpoint = NULL;
     966            2 :     gboolean ret = FALSE;
     967            2 :     gboolean success = FALSE;
     968            2 :     gboolean unmount = FALSE;
     969            2 :     GError *local_error = NULL;
     970              : 
     971            2 :     mountpoint = fs_mount (device, "btrfs", FALSE, &unmount, error);
     972            2 :     if (!mountpoint)
     973            0 :         return FALSE;
     974              : 
     975            2 :     success = bd_fs_btrfs_set_label (mountpoint, label, error);
     976              : 
     977            2 :     if (unmount) {
     978            2 :         ret = fs_unmount (device, mountpoint, "setting label", &local_error);
     979            2 :         if (!ret) {
     980            0 :             if (success) {
     981              :                 /* label was successful but unmount failed */
     982            0 :                 g_propagate_error (error, local_error);
     983            0 :                 return FALSE;
     984              :             } else
     985              :                 /* both label and unmount were unsuccessful but the error
     986              :                    from the label is more important so just ignore the
     987              :                    unmount error */
     988            0 :                 g_clear_error (&local_error);
     989              :         }
     990              :     }
     991              : 
     992            2 :     return success;
     993              : }
     994              : 
     995          123 : static gboolean device_operation (const gchar *device, const gchar *fstype, BDFSOpType op, guint64 new_size, const gchar *label, const gchar *uuid, GError **error) {
     996          123 :     const gchar* op_name = NULL;
     997          123 :     g_autofree gchar* detected_fstype = NULL;
     998              : 
     999              :     /* MKFS is covered as a special case, it's a bug to use this function for this case */
    1000          123 :     g_assert_true (op != BD_FS_MKFS);
    1001              : 
    1002              :     /* GET_SIZE is covered as a special case, it's a bug to use this function for this case */
    1003          123 :     g_assert_true (op != BD_FS_GET_SIZE);
    1004              : 
    1005          123 :     if (!fstype) {
    1006           53 :         detected_fstype = bd_fs_get_fstype (device, error);
    1007           53 :         if (!detected_fstype) {
    1008            0 :             if (error) {
    1009            0 :                 if (*error == NULL) {
    1010            0 :                     g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOFS,
    1011              :                                 "No filesystem detected on the device '%s'", device);
    1012            0 :                     return FALSE;
    1013              :                 } else {
    1014            0 :                     g_prefix_error (error, "Error when trying to detect filesystem on '%s': ", device);
    1015            0 :                     return FALSE;
    1016              :                 }
    1017              :             } else
    1018            0 :                 return FALSE;
    1019              :         }
    1020              :     } else
    1021           70 :         detected_fstype = g_strdup (fstype);
    1022              : 
    1023          123 :     if (g_strcmp0 (detected_fstype, "ext2") == 0 || g_strcmp0 (detected_fstype, "ext3") == 0
    1024          119 :                                                  || g_strcmp0 (detected_fstype, "ext4") == 0) {
    1025           18 :         switch (op) {
    1026            6 :             case BD_FS_RESIZE:
    1027            6 :                 return bd_fs_ext4_resize (device, new_size, NULL, error);
    1028            2 :             case BD_FS_REPAIR:
    1029            2 :                 return bd_fs_ext4_repair (device, TRUE, NULL, error);
    1030            3 :             case BD_FS_CHECK:
    1031            3 :                 return bd_fs_ext4_check (device, NULL, error);
    1032            2 :             case BD_FS_LABEL:
    1033            2 :                 return bd_fs_ext4_set_label (device, label, error);
    1034            2 :             case BD_FS_LABEL_CHECK:
    1035            2 :                 return bd_fs_ext4_check_label (label, error);
    1036            2 :             case BD_FS_UUID:
    1037            2 :                 return bd_fs_ext4_set_uuid (device, uuid, error);
    1038            1 :             case BD_FS_UUID_CHECK:
    1039            1 :                 return bd_fs_ext4_check_uuid (uuid, error);
    1040            0 :             default:
    1041            0 :                 g_assert_not_reached ();
    1042              :         }
    1043          105 :     } else if (g_strcmp0 (detected_fstype, "xfs") == 0) {
    1044           23 :         switch (op) {
    1045           12 :             case BD_FS_RESIZE:
    1046           12 :                 return xfs_resize_device (device, new_size, NULL, error);
    1047            2 :             case BD_FS_REPAIR:
    1048            2 :                 return bd_fs_xfs_repair (device, NULL, error);
    1049            2 :             case BD_FS_CHECK:
    1050            2 :                 return bd_fs_xfs_check (device, NULL, error);
    1051            2 :             case BD_FS_LABEL:
    1052            2 :                 return bd_fs_xfs_set_label (device, label, error);
    1053            2 :             case BD_FS_LABEL_CHECK:
    1054            2 :                 return bd_fs_xfs_check_label (label, error);
    1055            2 :             case BD_FS_UUID:
    1056            2 :                 return bd_fs_xfs_set_uuid (device, uuid, error);
    1057            1 :             case BD_FS_UUID_CHECK:
    1058            1 :                 return bd_fs_xfs_check_uuid (uuid, error);
    1059            0 :             default:
    1060            0 :                 g_assert_not_reached ();
    1061              :         }
    1062           82 :     } else if (g_strcmp0 (detected_fstype, "vfat") == 0) {
    1063            9 :         switch (op) {
    1064            2 :             case BD_FS_RESIZE:
    1065            2 :                 return bd_fs_vfat_resize (device, new_size, error);
    1066            0 :             case BD_FS_REPAIR:
    1067            0 :                 return bd_fs_vfat_repair (device, NULL, error);
    1068            0 :             case BD_FS_CHECK:
    1069            0 :                 return bd_fs_vfat_check (device, NULL, error);
    1070            2 :             case BD_FS_LABEL_CHECK:
    1071            2 :                 return bd_fs_vfat_check_label (label, error);
    1072            2 :             case BD_FS_LABEL:
    1073            2 :                 return bd_fs_vfat_set_label (device, label, error);
    1074            2 :             case BD_FS_UUID:
    1075            2 :                 return bd_fs_vfat_set_uuid (device, uuid, error);
    1076            1 :             case BD_FS_UUID_CHECK:
    1077            1 :                 return bd_fs_vfat_check_uuid (uuid, error);
    1078            0 :             default:
    1079            0 :                 g_assert_not_reached ();
    1080              :         }
    1081           73 :     } else if (g_strcmp0 (detected_fstype, "ntfs") == 0) {
    1082           17 :         switch (op) {
    1083            2 :             case BD_FS_RESIZE:
    1084            2 :                 return bd_fs_ntfs_resize (device, new_size, error);
    1085            6 :             case BD_FS_REPAIR:
    1086            6 :                 return bd_fs_ntfs_repair (device, NULL, error);
    1087            2 :             case BD_FS_CHECK:
    1088            2 :                 return bd_fs_ntfs_check (device, NULL, error);
    1089            2 :             case BD_FS_LABEL_CHECK:
    1090            2 :                 return bd_fs_ntfs_check_label (label, error);
    1091            2 :             case BD_FS_LABEL:
    1092            2 :                 return bd_fs_ntfs_set_label (device, label, error);
    1093            2 :             case BD_FS_UUID:
    1094            2 :                 return bd_fs_ntfs_set_uuid (device, uuid, error);
    1095            1 :             case BD_FS_UUID_CHECK:
    1096            1 :                 return bd_fs_ntfs_check_uuid (uuid, error);
    1097            0 :             default:
    1098            0 :                 g_assert_not_reached ();
    1099              :         }
    1100           56 :     } else if (g_strcmp0 (detected_fstype, "f2fs") == 0) {
    1101            8 :         switch (op) {
    1102            0 :             case BD_FS_RESIZE:
    1103            0 :                 return f2fs_resize_device (device, new_size, error);
    1104            2 :             case BD_FS_REPAIR:
    1105            2 :                 return bd_fs_f2fs_repair (device, NULL, error);
    1106            2 :             case BD_FS_CHECK:
    1107            2 :                 return bd_fs_f2fs_check (device, NULL, error);
    1108            1 :             case BD_FS_LABEL:
    1109            1 :                 break;
    1110            2 :             case BD_FS_LABEL_CHECK:
    1111            2 :                 return bd_fs_f2fs_check_label (label, error);
    1112            1 :             case BD_FS_UUID:
    1113            1 :                 break;
    1114            0 :             case BD_FS_UUID_CHECK:
    1115            0 :                 break;
    1116            0 :             default:
    1117            0 :                 g_assert_not_reached ();
    1118              :         }
    1119           48 :     } else if (g_strcmp0 (detected_fstype, "nilfs2") == 0) {
    1120           11 :         switch (op) {
    1121            2 :             case BD_FS_RESIZE:
    1122            2 :                 return nilfs2_resize_device (device, new_size, error);
    1123            1 :             case BD_FS_REPAIR:
    1124            1 :                 break;
    1125            1 :             case BD_FS_CHECK:
    1126            1 :                 break;
    1127            2 :             case BD_FS_LABEL:
    1128            2 :                 return bd_fs_nilfs2_set_label (device, label, error);
    1129            2 :             case BD_FS_LABEL_CHECK:
    1130            2 :                 return bd_fs_nilfs2_check_label (label, error);
    1131            2 :             case BD_FS_UUID:
    1132            2 :                 return bd_fs_nilfs2_set_uuid (device, uuid, error);
    1133            1 :             case BD_FS_UUID_CHECK:
    1134            1 :                 return bd_fs_nilfs2_check_uuid (uuid, error);
    1135            0 :             default:
    1136            0 :                 g_assert_not_reached ();
    1137              :         }
    1138           37 :     } else if (g_strcmp0 (detected_fstype, "exfat") == 0) {
    1139           12 :         switch (op) {
    1140            1 :             case BD_FS_RESIZE:
    1141            1 :                 break;
    1142            2 :             case BD_FS_REPAIR:
    1143            2 :                 return bd_fs_exfat_repair (device, NULL, error);
    1144            2 :             case BD_FS_CHECK:
    1145            2 :                 return bd_fs_exfat_check (device, NULL, error);
    1146            2 :             case BD_FS_LABEL:
    1147            2 :                 return bd_fs_exfat_set_label (device, label, error);
    1148            2 :             case BD_FS_LABEL_CHECK:
    1149            2 :                 return bd_fs_exfat_check_label (label, error);
    1150            2 :             case BD_FS_UUID:
    1151            2 :                 return bd_fs_exfat_set_uuid (device, uuid, error);
    1152            1 :             case BD_FS_UUID_CHECK:
    1153            1 :                 return bd_fs_exfat_check_uuid (uuid, error);
    1154            0 :             default:
    1155            0 :                 g_assert_not_reached ();
    1156              :         }
    1157           25 :     } else if (g_strcmp0 (detected_fstype, "btrfs") == 0) {
    1158           15 :         switch (op) {
    1159            4 :             case BD_FS_RESIZE:
    1160            4 :                 return btrfs_resize_device (device, new_size, error);
    1161            2 :             case BD_FS_REPAIR:
    1162            2 :                 return bd_fs_btrfs_repair (device, NULL, error);
    1163            2 :             case BD_FS_CHECK:
    1164            2 :                 return bd_fs_btrfs_check (device, NULL, error);
    1165            2 :             case BD_FS_LABEL:
    1166            2 :                 return btrfs_set_label (device, label, error);
    1167            2 :             case BD_FS_LABEL_CHECK:
    1168            2 :                 return bd_fs_btrfs_check_label (label, error);
    1169            2 :             case BD_FS_UUID:
    1170            2 :                 return bd_fs_btrfs_set_uuid (device, uuid, error);
    1171            1 :             case BD_FS_UUID_CHECK:
    1172            1 :                 return bd_fs_btrfs_check_uuid (uuid, error);
    1173            0 :             default:
    1174            0 :                 g_assert_not_reached ();
    1175              :         }
    1176           10 :     } else if (g_strcmp0 (detected_fstype, "udf") == 0) {
    1177            8 :         switch (op) {
    1178            1 :             case BD_FS_RESIZE:
    1179            1 :                 break;
    1180            0 :             case BD_FS_REPAIR:
    1181            0 :                 break;
    1182            0 :             case BD_FS_CHECK:
    1183            0 :                 break;
    1184            2 :             case BD_FS_LABEL:
    1185            2 :                 return bd_fs_udf_set_label (device, label, error);
    1186            2 :             case BD_FS_LABEL_CHECK:
    1187            2 :                 return bd_fs_udf_check_label (label, error);
    1188            2 :             case BD_FS_UUID:
    1189            2 :                 return bd_fs_udf_set_uuid (device, uuid, error);
    1190            1 :             case BD_FS_UUID_CHECK:
    1191            1 :                 return bd_fs_udf_check_uuid (uuid, error);
    1192            0 :             default:
    1193            0 :                 g_assert_not_reached ();
    1194              :         }
    1195              :     }
    1196            8 :     switch (op) {
    1197            2 :         case BD_FS_RESIZE:
    1198            2 :             op_name = "Resizing";
    1199            2 :             break;
    1200            1 :         case BD_FS_REPAIR:
    1201            1 :             op_name = "Repairing";
    1202            1 :             break;
    1203            1 :         case BD_FS_CHECK:
    1204            1 :             op_name = "Checking";
    1205            1 :             break;
    1206            1 :         case BD_FS_LABEL:
    1207            1 :             op_name = "Setting the label of";
    1208            1 :             break;
    1209            1 :         case BD_FS_LABEL_CHECK:
    1210            1 :             op_name = "Checking label format for";
    1211            1 :             break;
    1212            1 :         case BD_FS_UUID:
    1213            1 :             op_name = "Setting UUID of";
    1214            1 :             break;
    1215            1 :         case BD_FS_UUID_CHECK:
    1216            1 :             op_name = "Checking UUID format for";
    1217            1 :             break;
    1218            0 :         default:
    1219            0 :             g_assert_not_reached ();
    1220              :     }
    1221            8 :     g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOT_SUPPORTED,
    1222              :                  "%s filesystem '%s' is not supported.", op_name, detected_fstype);
    1223            8 :     return FALSE;
    1224              : }
    1225              : 
    1226              : /**
    1227              :  * bd_fs_resize:
    1228              :  * @device: the device the file system of which to resize
    1229              :  * @new_size: new requested size for the file system (if 0, the file system is
    1230              :  *            adapted to the underlying block device)
    1231              :  * @fstype: (nullable): the filesystem type on @device or %NULL to detect
    1232              :  * @error: (out) (optional): place to store error (if any)
    1233              :  *
    1234              :  * Resize filesystem on @device. This calls other fs resize functions from this
    1235              :  * plugin based on provided or detected filesystem (e.g. bd_fs_xfs_resize for XFS).
    1236              :  * This function will return an error for unknown/unsupported filesystems.
    1237              :  *
    1238              :  * Note: This function will mount @device for filesystems that can be resized only
    1239              :  *       when mounted (like XFS or Btrfs).
    1240              :  *
    1241              :  * Returns: whether the file system on @device was successfully resized or not
    1242              :  *
    1243              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_RESIZE
    1244              :  */
    1245           30 : gboolean bd_fs_resize (const gchar *device, guint64 new_size, const gchar *fstype, GError **error) {
    1246           30 :     return device_operation (device, fstype, BD_FS_RESIZE, new_size, NULL, NULL, error);
    1247              : }
    1248              : 
    1249              : /**
    1250              :  * bd_fs_repair:
    1251              :  * @device: the device the file system of which to repair
    1252              :  * @fstype: (nullable): the filesystem type on @device or %NULL to detect
    1253              :  * @error: (out) (optional): place to store error (if any)
    1254              :  *
    1255              :  * Repair filesystem on @device. This calls other fs repair functions from this
    1256              :  * plugin based on detected filesystem (e.g. bd_fs_xfs_repair for XFS). This
    1257              :  * function will return an error for unknown/unsupported filesystems.
    1258              :  *
    1259              :  * Most filesystem tools typically require the filesystem not to be mounted.
    1260              :  *
    1261              :  * Returns: whether the file system on @device was successfully repaired or not
    1262              :  *
    1263              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_REPAIR
    1264              :  */
    1265           17 : gboolean bd_fs_repair (const gchar *device, const gchar *fstype, GError **error) {
    1266           17 :     return device_operation (device, fstype, BD_FS_REPAIR, 0, NULL, NULL, error);
    1267              :  }
    1268              : 
    1269              : /**
    1270              :  * bd_fs_check:
    1271              :  * @device: the device the file system of which to check
    1272              :  * @fstype: (nullable): the filesystem type on @device or %NULL to detect
    1273              :  * @error: (out) (optional): place to store error (if any)
    1274              :  *
    1275              :  * Check filesystem on @device avoiding any modifications or repairs.
    1276              :  * This calls other fs check functions from this plugin based on detected
    1277              :  * filesystem (e.g. bd_fs_xfs_check for XFS). This function will return
    1278              :  * an error for unknown/unsupported filesystems.
    1279              :  *
    1280              :  * Note that depending on a corresponding filesystem type and configured
    1281              :  * features running this function on a mounted filesystem may result
    1282              :  * in false errors reported.
    1283              :  *
    1284              :  * Returns: whether the file system on @device passed the consistency check or not
    1285              :  *
    1286              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_CHECK
    1287              :  */
    1288           14 : gboolean bd_fs_check (const gchar *device, const gchar *fstype, GError **error) {
    1289           14 :     return device_operation (device, fstype, BD_FS_CHECK, 0, NULL, NULL, error);
    1290              : }
    1291              : 
    1292              : /**
    1293              :  * bd_fs_check_label:
    1294              :  * @fstype: the filesystem type to check @label for
    1295              :  * @label: label to check
    1296              :  * @error: (out) (optional): place to store error (if any)
    1297              :  *
    1298              :  * This calls other fs check label functions from this plugin based on the provided
    1299              :  * filesystem (e.g. bd_fs_xfs_check_label for XFS). This function will return
    1300              :  * an error for unknown/unsupported filesystems.
    1301              :  *
    1302              :  * Returns: whether @label is a valid label for the @fstype file system or not
    1303              :  *          (reason is provided in @error)
    1304              :  *
    1305              :  * Tech category: always available
    1306              :  */
    1307           20 : gboolean bd_fs_check_label (const gchar *fstype, const gchar *label, GError **error) {
    1308           20 :     if (!fstype || g_strcmp0 (fstype, "") == 0) {
    1309            1 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOFS,
    1310              :                      "Filesystem type must be specified to check label format");
    1311            1 :         return FALSE;
    1312              :     }
    1313           19 :     return device_operation (NULL, fstype, BD_FS_LABEL_CHECK, 0, label, NULL, error);
    1314              : }
    1315              : 
    1316              : 
    1317              : /**
    1318              :  * bd_fs_set_label:
    1319              :  * @device: the device with file system to set the label for
    1320              :  * @label: label to set
    1321              :  * @fstype: (nullable): the filesystem type on @device or %NULL to detect
    1322              :  * @error: (out) (optional): place to store error (if any)
    1323              :  *
    1324              :  * Set label for filesystem on @device. This calls other fs label functions from this
    1325              :  * plugin based on detected filesystem (e.g. bd_fs_xfs_set_label for XFS). This
    1326              :  * function will return an error for unknown/unsupported filesystems.
    1327              :  *
    1328              :  * Note: This function will mount @device for filesystems that need to be mounted
    1329              :  *       to set label (like btrfs).
    1330              :  *
    1331              :  * Returns: whether the file system on @device was successfully relabeled or not
    1332              :  *
    1333              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_SET_LABEL
    1334              :  */
    1335           17 : gboolean bd_fs_set_label (const gchar *device, const gchar *label, const gchar *fstype, GError **error) {
    1336           17 :     return device_operation (device, fstype, BD_FS_LABEL, 0, label, NULL, error);
    1337              : }
    1338              : 
    1339              : /**
    1340              :  * bd_fs_check_uuid:
    1341              :  * @fstype: the filesystem type to check @uuid for
    1342              :  * @uuid: uuid to check
    1343              :  * @error: (out) (optional): place to store error (if any)
    1344              :  *
    1345              :  * This calls other fs check uuid functions from this plugin based on the provided
    1346              :  * filesystem (e.g. bd_fs_xfs_check_uuid for XFS). This function will return
    1347              :  * an error for unknown/unsupported filesystems.
    1348              :  *
    1349              :  * Returns: whether @uuid is a valid UUID for the @fstype file system or not
    1350              :  *          (reason is provided in @error)
    1351              :  *
    1352              :  * Tech category: always available
    1353              :  */
    1354           10 : gboolean bd_fs_check_uuid (const gchar *fstype, const gchar *uuid, GError **error) {
    1355           10 :     if (!fstype || g_strcmp0 (fstype, "") == 0) {
    1356            1 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOFS,
    1357              :                      "Filesystem type must be specified to check UUID format");
    1358            1 :         return FALSE;
    1359              :     }
    1360            9 :     return device_operation (NULL, fstype, BD_FS_UUID_CHECK, 0, NULL, uuid, error);
    1361              : }
    1362              : 
    1363              : /**
    1364              :  * bd_fs_set_uuid:
    1365              :  * @device: the device with file system to set the UUID for
    1366              :  * @uuid: (nullable): UUID to set or %NULL to generate a new one
    1367              :  * @fstype: (nullable): the filesystem type on @device or %NULL to detect
    1368              :  * @error: (out) (optional): place to store error (if any)
    1369              :  *
    1370              :  * Set UUID for filesystem on @device. This calls other fs UUID functions from this
    1371              :  * plugin based on detected filesystem (e.g. bd_fs_xfs_set_uuid for XFS). This
    1372              :  * function will return an error for unknown/unsupported filesystems.
    1373              :  *
    1374              :  * Returns: whether the UUID on the file system on @device was successfully changed or not
    1375              :  *
    1376              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_SET_UUID
    1377              :  */
    1378           17 : gboolean bd_fs_set_uuid (const gchar *device, const gchar *uuid, const gchar *fstype, GError **error) {
    1379           17 :     return device_operation (device, fstype, BD_FS_UUID, 0, NULL, uuid, error);
    1380              : }
    1381              : 
    1382              : /**
    1383              :  * bd_fs_get_size:
    1384              :  * @device: the device with file system to get size for
    1385              :  * @fstype: (nullable): the filesystem type on @device or %NULL to detect
    1386              :  * @error: (out) (optional): place to store error (if any)
    1387              :  *
    1388              :  * Get size for filesystem on @device. This calls other fs info functions from this
    1389              :  * plugin based on detected filesystem (e.g. bd_fs_xfs_get_info for XFS). This
    1390              :  * function will return an error for unknown/unsupported filesystems.
    1391              :  *
    1392              :  * Note: This function will mount @device for filesystems that need to be mounted
    1393              :  *       to gather information (like btrfs).
    1394              :  *
    1395              :  * Returns: size of filesystem on @device, 0 in case of error.
    1396              :  *
    1397              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_QUERY
    1398              :  */
    1399           35 : guint64 bd_fs_get_size (const gchar *device, const gchar *fstype, GError **error) {
    1400           35 :     g_autofree gchar* detected_fstype = NULL;
    1401           35 :     guint64 size = 0;
    1402              : 
    1403           35 :     if (!fstype) {
    1404           28 :         detected_fstype = bd_fs_get_fstype (device, error);
    1405           28 :         if (!detected_fstype) {
    1406            0 :             if (error) {
    1407            0 :                 if (*error == NULL) {
    1408            0 :                     g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOFS,
    1409              :                                 "No filesystem detected on the device '%s'", device);
    1410            0 :                     return 0;
    1411              :                 } else {
    1412            0 :                     g_prefix_error (error, "Error when trying to detect filesystem on '%s': ", device);
    1413            0 :                     return 0;
    1414              :                 }
    1415              :             } else
    1416            0 :                 return 0;
    1417              :         }
    1418              :     } else
    1419            7 :         detected_fstype = g_strdup (fstype);
    1420              : 
    1421           35 :     if (g_strcmp0 (detected_fstype, "ext2") == 0 || g_strcmp0 (detected_fstype, "ext3") == 0
    1422           25 :                                                  || g_strcmp0 (detected_fstype, "ext4") == 0) {
    1423           15 :         BDFSExt4Info* info = bd_fs_ext4_get_info (device, error);
    1424           15 :         if (info) {
    1425           15 :             size = info->block_size * info->block_count;
    1426           15 :             bd_fs_ext4_info_free (info);
    1427              :         }
    1428           15 :         return size;
    1429              : 
    1430           20 :     } else if (g_strcmp0 (detected_fstype, "xfs") == 0) {
    1431            0 :         BDFSXfsInfo *info = bd_fs_xfs_get_info (device, error);
    1432            0 :         if (info) {
    1433            0 :             size = info->block_size * info->block_count;
    1434            0 :             bd_fs_xfs_info_free (info);
    1435              :         }
    1436            0 :         return size;
    1437           20 :     } else if (g_strcmp0 (detected_fstype, "vfat") == 0) {
    1438            5 :         BDFSVfatInfo *info = bd_fs_vfat_get_info (device, error);
    1439            5 :         if (info) {
    1440            5 :             size = info->cluster_size * info->cluster_count;
    1441            5 :             bd_fs_vfat_info_free (info);
    1442              :         }
    1443            5 :         return size;
    1444           15 :     } else if (g_strcmp0 (detected_fstype, "ntfs") == 0) {
    1445            2 :         BDFSNtfsInfo *info = bd_fs_ntfs_get_info (device, error);
    1446            2 :         if (info) {
    1447            2 :             size = info->size;
    1448            2 :             bd_fs_ntfs_info_free (info);
    1449              :         }
    1450            2 :         return size;
    1451           13 :     } else if (g_strcmp0 (detected_fstype, "f2fs") == 0) {
    1452            0 :         BDFSF2FSInfo *info = bd_fs_f2fs_get_info (device, error);
    1453            0 :         if (info) {
    1454            0 :             size = info->sector_size * info->sector_count;
    1455            0 :             bd_fs_f2fs_info_free (info);
    1456              :         }
    1457            0 :         return size;
    1458           13 :     } else if (g_strcmp0 (detected_fstype, "nilfs2") == 0) {
    1459            5 :         BDFSNILFS2Info *info = bd_fs_nilfs2_get_info (device, error);
    1460            5 :         if (info) {
    1461            5 :             size = info->size;
    1462            5 :             bd_fs_nilfs2_info_free (info);
    1463              :         }
    1464            5 :         return size;
    1465            8 :     } else if (g_strcmp0 (detected_fstype, "exfat") == 0) {
    1466            0 :         BDFSExfatInfo *info = bd_fs_exfat_get_info (device, error);
    1467            0 :         if (info) {
    1468            0 :             size = info->sector_size * info->sector_count;
    1469            0 :             bd_fs_exfat_info_free (info);
    1470              :         }
    1471            0 :         return size;
    1472            8 :     } else if (g_strcmp0 (detected_fstype, "btrfs") == 0) {
    1473            8 :         BDFSBtrfsInfo *info = btrfs_get_info (device, error);
    1474            8 :         if (info) {
    1475            8 :             size = info->size;
    1476            8 :             bd_fs_btrfs_info_free (info);
    1477              :         }
    1478            8 :         return size;
    1479            0 :     } else if (g_strcmp0 (detected_fstype, "udf") == 0) {
    1480            0 :         BDFSUdfInfo *info = bd_fs_udf_get_info (device, error);
    1481            0 :         if (info) {
    1482            0 :             size = info->block_size * info->block_count;
    1483            0 :             bd_fs_udf_info_free (info);
    1484              :         }
    1485            0 :         return size;
    1486              :     } else {
    1487            0 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOT_SUPPORTED,
    1488              :                     "Getting size of filesystem '%s' is not supported.", detected_fstype);
    1489            0 :         return 0;
    1490              :     }
    1491              : }
    1492              : 
    1493              : /**
    1494              :  * bd_fs_get_free_space:
    1495              :  * @device: the device with file system to get free space for
    1496              :  * @fstype: (nullable): the filesystem type on @device or %NULL to detect
    1497              :  * @error: (out) (optional): place to store error (if any)
    1498              :  *
    1499              :  * Get free space for filesystem on @device. This calls other fs info functions from this
    1500              :  * plugin based on detected filesystem (e.g. bd_fs_ext4_get_info for ext4). This
    1501              :  * function will return an error for unknown/unsupported filesystems.
    1502              :  *
    1503              :  * Returns: free space of filesystem on @device, 0 in case of error.
    1504              :  *
    1505              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_QUERY
    1506              :  */
    1507           15 : guint64 bd_fs_get_free_space (const gchar *device, const gchar *fstype, GError **error) {
    1508           15 :     g_autofree gchar* detected_fstype = NULL;
    1509           15 :     guint64 size = 0;
    1510              : 
    1511           15 :     if (!fstype) {
    1512            8 :         detected_fstype = bd_fs_get_fstype (device, error);
    1513            8 :         if (!detected_fstype) {
    1514            0 :             if (error) {
    1515            0 :                 if (*error == NULL) {
    1516            0 :                     g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOFS,
    1517              :                                 "No filesystem detected on the device '%s'", device);
    1518            0 :                     return 0;
    1519              :                 } else {
    1520            0 :                     g_prefix_error (error, "Error when trying to detect filesystem on '%s': ", device);
    1521            0 :                     return 0;
    1522              :                 }
    1523              :             } else
    1524            0 :                 return 0;
    1525              :         }
    1526              :     } else
    1527            7 :         detected_fstype = g_strdup (fstype);
    1528              : 
    1529           15 :     if (g_strcmp0 (detected_fstype, "ext2") == 0 || g_strcmp0 (detected_fstype, "ext3") == 0
    1530           11 :                                                  || g_strcmp0 (detected_fstype, "ext4") == 0) {
    1531            6 :         BDFSExt4Info* info = bd_fs_ext4_get_info (device, error);
    1532            6 :         if (info) {
    1533            6 :             size = info->block_size * info->free_blocks;
    1534            6 :             bd_fs_ext4_info_free (info);
    1535              :         }
    1536            6 :         return size;
    1537              : 
    1538            9 :     } else if (g_strcmp0 (detected_fstype, "vfat") == 0) {
    1539            2 :         BDFSVfatInfo *info = bd_fs_vfat_get_info (device, error);
    1540            2 :         if (info) {
    1541            2 :             size = info->cluster_size * info->free_cluster_count;
    1542            2 :             bd_fs_vfat_info_free (info);
    1543              :         }
    1544            2 :         return size;
    1545            7 :     } else if (g_strcmp0 (detected_fstype, "ntfs") == 0) {
    1546            2 :         BDFSNtfsInfo *info = bd_fs_ntfs_get_info (device, error);
    1547            2 :         if (info) {
    1548            2 :             size = info->free_space;
    1549            2 :             bd_fs_ntfs_info_free (info);
    1550              :         }
    1551            2 :         return size;
    1552            5 :     } else if (g_strcmp0 (detected_fstype, "nilfs2") == 0) {
    1553            2 :         BDFSNILFS2Info *info = bd_fs_nilfs2_get_info (device, error);
    1554            2 :         if (info) {
    1555            2 :             size = info->block_size * info->free_blocks;
    1556            2 :             bd_fs_nilfs2_info_free (info);
    1557              :         }
    1558            2 :         return size;
    1559            3 :     } else if (g_strcmp0 (detected_fstype, "btrfs") == 0) {
    1560            2 :         BDFSBtrfsInfo *info = btrfs_get_info (device, error);
    1561            2 :         if (info) {
    1562            2 :             size = info->free_space;
    1563            2 :             bd_fs_btrfs_info_free (info);
    1564              :         }
    1565            2 :         return size;
    1566              :     } else {
    1567            1 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOT_SUPPORTED,
    1568              :                     "Getting free space on filesystem '%s' is not supported.", detected_fstype);
    1569            1 :         return 0;
    1570              :     }
    1571              : }
    1572              : 
    1573              : /**
    1574              :  * bd_fs_get_min_size:
    1575              :  * @device: the device with file system to get minimum size for
    1576              :  * @fstype: (nullable): the filesystem type on @device or %NULL to detect
    1577              :  * @error: (out) (optional): place to store error (if any)
    1578              :  *
    1579              :  * Get minimum size for filesystem on @device. This calls other fs info functions from this
    1580              :  * plugin based on detected filesystem (e.g. bd_fs_ext4_get_min_size for ext4). This
    1581              :  * function will return an error for unknown/unsupported filesystems.
    1582              :  *
    1583              :  * Returns: minimum size of filesystem on @device, 0 in case of error.
    1584              :  *
    1585              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_RESIZE
    1586              :  */
    1587            5 : guint64 bd_fs_get_min_size (const gchar *device, const gchar *fstype, GError **error) {
    1588            5 :     g_autofree gchar* detected_fstype = NULL;
    1589              : 
    1590            5 :     if (!fstype) {
    1591            5 :         detected_fstype = bd_fs_get_fstype (device, error);
    1592            5 :         if (!detected_fstype) {
    1593            0 :             if (error) {
    1594            0 :                 if (*error == NULL) {
    1595            0 :                     g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOFS,
    1596              :                                 "No filesystem detected on the device '%s'", device);
    1597            0 :                     return 0;
    1598              :                 } else {
    1599            0 :                     g_prefix_error (error, "Error when trying to detect filesystem on '%s': ", device);
    1600            0 :                     return 0;
    1601              :                 }
    1602              :             } else
    1603            0 :                 return 0;
    1604              :         }
    1605              :     } else
    1606            0 :         detected_fstype = g_strdup (fstype);
    1607              : 
    1608            5 :     if (g_strcmp0 (detected_fstype, "ext2") == 0 || g_strcmp0 (detected_fstype, "ext3") == 0
    1609            3 :                                                  || g_strcmp0 (detected_fstype, "ext4") == 0)
    1610            3 :         return bd_fs_ext2_get_min_size (device, error);
    1611            2 :     else if (g_strcmp0 (detected_fstype, "ntfs") == 0) {
    1612            1 :         return bd_fs_ntfs_get_min_size (device, error);
    1613              :     } else {
    1614            1 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOT_SUPPORTED,
    1615              :                     "Getting minimum size of filesystem '%s' is not supported.", detected_fstype);
    1616            1 :         return 0;
    1617              :     }
    1618              : }
    1619              : 
    1620           60 : static gboolean query_fs_operation (const gchar *fs_type, BDFSOpType op, gchar **required_utility, BDFSResizeFlags *mode, BDFSMkfsOptionsFlags *options, GError **error) {
    1621              :     gboolean ret;
    1622           60 :     const BDFSInfo *fsinfo = NULL;
    1623           60 :     const gchar* op_name = NULL;
    1624           60 :     const gchar* exec_util = NULL;
    1625              :     BDFSTech tech;
    1626              : 
    1627           60 :     if (required_utility != NULL)
    1628           60 :         *required_utility = NULL;
    1629              : 
    1630           60 :     if (mode != NULL)
    1631            5 :         *mode = 0;
    1632              : 
    1633           60 :     if (options != NULL)
    1634           22 :         *options = 0;
    1635              : 
    1636           60 :     tech = fstype_to_tech (fs_type);
    1637           60 :     if (tech == BD_FS_TECH_GENERIC) {
    1638            7 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOT_SUPPORTED,
    1639              :                      "Filesystem '%s' is not supported.", fs_type);
    1640            7 :         return FALSE;
    1641              :     }
    1642           53 :     fsinfo = &fs_info[tech];
    1643              : 
    1644           53 :     switch (op) {
    1645           22 :         case BD_FS_MKFS:
    1646           22 :             op_name = "Creating";
    1647           22 :             exec_util = fsinfo->mkfs_util;
    1648           22 :             break;
    1649            4 :         case BD_FS_RESIZE:
    1650            4 :             op_name = "Resizing";
    1651            4 :             exec_util = fsinfo->resize_util;
    1652            4 :             break;
    1653            5 :         case BD_FS_REPAIR:
    1654            5 :             op_name = "Repairing";
    1655            5 :             exec_util = fsinfo->repair_util;
    1656            5 :             break;
    1657            5 :         case BD_FS_CHECK:
    1658            5 :             op_name = "Checking";
    1659            5 :             exec_util = fsinfo->check_util;
    1660            5 :             break;
    1661            2 :         case BD_FS_LABEL:
    1662            2 :             op_name = "Setting the label of";
    1663            2 :             exec_util = fsinfo->label_util;
    1664            2 :             break;
    1665            3 :         case BD_FS_UUID:
    1666            3 :             op_name = "Setting UUID of";
    1667            3 :             exec_util = fsinfo->uuid_util;
    1668            3 :             break;
    1669            2 :         case BD_FS_GET_SIZE:
    1670            2 :             op_name = "Getting size of";
    1671            2 :             exec_util = fsinfo->info_util;
    1672            2 :             break;
    1673            2 :         case BD_FS_GET_FREE_SPACE:
    1674            2 :             op_name = "Getting free space on";
    1675            2 :             exec_util = fsinfo->info_util;
    1676            2 :             break;
    1677            2 :         case BD_FS_GET_INFO:
    1678            2 :             op_name = "Getting filesystem info of";
    1679            2 :             exec_util = fsinfo->info_util;
    1680            2 :             break;
    1681            6 :         case BD_FS_GET_MIN_SIZE:
    1682            6 :             op_name = "Getting minimum size of";
    1683            6 :             exec_util = fsinfo->minsize_util;
    1684            6 :             break;
    1685            0 :         default:
    1686            0 :             g_assert_not_reached ();
    1687              :     }
    1688              : 
    1689           53 :     if (exec_util == NULL) {
    1690            9 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOT_SUPPORTED,
    1691              :                      "%s filesystem '%s' is not supported.", op_name, fs_type);
    1692            9 :         return FALSE;
    1693              :     }
    1694              : 
    1695           44 :     if (mode != NULL)
    1696            3 :         *mode = fs_features[tech].resize;
    1697              : 
    1698           44 :     if (options != NULL)
    1699           22 :         *options = fs_features[tech].mkfs;
    1700              : 
    1701           44 :     if (strlen (exec_util) == 0) { /* empty string if no util needed */
    1702            0 :         return TRUE;
    1703              :     }
    1704              : 
    1705           44 :     ret = bd_utils_check_util_version (exec_util, NULL, "", NULL, NULL);
    1706           44 :     if (!ret && required_utility != NULL)
    1707            9 :         *required_utility = g_strdup (exec_util);
    1708              : 
    1709           44 :     return ret;
    1710              : }
    1711              : 
    1712              : /**
    1713              :  * bd_fs_can_mkfs:
    1714              :  * @type: the filesystem type to be tested for installed mkfs support
    1715              :  * @options: (out): flags for allowed mkfs options (i.e. support for setting label or UUID when creating the filesystem)
    1716              :  * @required_utility: (out) (transfer full): the utility binary which is required for creating (if missing returns %FALSE but no @error)
    1717              :  * @error: (out) (optional): place to store error (if any)
    1718              :  *
    1719              :  * Searches for the required utility to create the given filesystem and returns whether
    1720              :  * it is installed. The options flags indicate what additional options can be specified for @type.
    1721              :  * Unknown filesystems result in errors.
    1722              :  *
    1723              :  * Returns: whether filesystem mkfs tool is available
    1724              :  *
    1725              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_QUERY
    1726              :  */
    1727           22 : gboolean bd_fs_can_mkfs (const gchar *type, BDFSMkfsOptionsFlags *options, gchar **required_utility, GError **error) {
    1728           22 :     return query_fs_operation (type, BD_FS_MKFS, required_utility, NULL, options, error);
    1729              : }
    1730              : 
    1731              : /**
    1732              :  * bd_fs_can_resize:
    1733              :  * @type: the filesystem type to be tested for installed resize support
    1734              :  * @mode: (out): flags for allowed resizing (i.e. growing/shrinking support for online/offline)
    1735              :  * @required_utility: (out) (transfer full): the utility binary which is required for resizing (if missing i.e. returns FALSE but no error)
    1736              :  * @error: (out) (optional): place to store error (if any)
    1737              :  *
    1738              :  * Searches for the required utility to resize the given filesystem and returns whether
    1739              :  * it is installed. The mode flags indicate if growing and/or shrinking resize is available if
    1740              :  * mounted/unmounted.
    1741              :  * Unknown filesystems or filesystems which do not support resizing result in errors.
    1742              :  *
    1743              :  * Returns: whether filesystem resize is available
    1744              :  *
    1745              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_QUERY
    1746              :  */
    1747            5 : gboolean bd_fs_can_resize (const gchar *type, BDFSResizeFlags *mode, gchar **required_utility, GError **error) {
    1748            5 :     return query_fs_operation (type, BD_FS_RESIZE, required_utility, mode, NULL, error);
    1749              : }
    1750              : 
    1751              : /**
    1752              :  * bd_fs_can_check:
    1753              :  * @type: the filesystem type to be tested for installed consistency check support
    1754              :  * @required_utility: (out) (transfer full): the utility binary which is required for checking (if missing i.e. returns FALSE but no error)
    1755              :  * @error: (out) (optional): place to store error (if any)
    1756              :  *
    1757              :  * Searches for the required utility to check the given filesystem and returns whether
    1758              :  * it is installed.
    1759              :  * Unknown filesystems or filesystems which do not support checking result in errors.
    1760              :  *
    1761              :  * Returns: whether filesystem check is available
    1762              :  *
    1763              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_QUERY
    1764              :  */
    1765            5 : gboolean bd_fs_can_check (const gchar *type, gchar **required_utility, GError **error) {
    1766            5 :     return query_fs_operation (type, BD_FS_CHECK, required_utility, NULL, NULL, error);
    1767              : }
    1768              : 
    1769              : /**
    1770              :  * bd_fs_can_repair:
    1771              :  * @type: the filesystem type to be tested for installed repair support
    1772              :  * @required_utility: (out) (transfer full): the utility binary which is required for repairing (if missing i.e. return FALSE but no error)
    1773              :  * @error: (out) (optional): place to store error (if any)
    1774              :  *
    1775              :  * Searches for the required utility to repair the given filesystem and returns whether
    1776              :  * it is installed.
    1777              :  * Unknown filesystems or filesystems which do not support reparing result in errors.
    1778              :  *
    1779              :  * Returns: whether filesystem repair is available
    1780              :  *
    1781              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_QUERY
    1782              :  */
    1783            5 : gboolean bd_fs_can_repair (const gchar *type, gchar **required_utility, GError **error) {
    1784            5 :     return query_fs_operation (type, BD_FS_REPAIR, required_utility, NULL, NULL, error);
    1785              : }
    1786              : 
    1787              : /**
    1788              :  * bd_fs_can_set_label:
    1789              :  * @type: the filesystem type to be tested for installed label support
    1790              :  * @required_utility: (out) (transfer full): the utility binary which is required for relabeling (if missing i.e. return FALSE but no error)
    1791              :  * @error: (out) (optional): place to store error (if any)
    1792              :  *
    1793              :  * Searches for the required utility to set the label of the given filesystem and returns whether
    1794              :  * it is installed.
    1795              :  * Unknown filesystems or filesystems which do not support setting the label result in errors.
    1796              :  *
    1797              :  * Returns: whether setting filesystem label is available
    1798              :  *
    1799              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_QUERY
    1800              :  */
    1801            3 : gboolean bd_fs_can_set_label (const gchar *type, gchar **required_utility, GError **error) {
    1802            3 :     return query_fs_operation (type, BD_FS_LABEL, required_utility, NULL, NULL, error);
    1803              : }
    1804              : 
    1805              : /**
    1806              :  * bd_fs_can_set_uuid:
    1807              :  * @type: the filesystem type to be tested for installed UUID support
    1808              :  * @required_utility: (out) (transfer full): the utility binary which is required for setting UUID (if missing i.e. return FALSE but no error)
    1809              :  * @error: (out) (optional): place to store error (if any)
    1810              :  *
    1811              :  * Searches for the required utility to set the UUID of the given filesystem and returns whether
    1812              :  * it is installed.
    1813              :  * Unknown filesystems or filesystems which do not support setting the UUID result in errors.
    1814              :  *
    1815              :  * Returns: whether setting filesystem UUID is available
    1816              :  *
    1817              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_QUERY
    1818              :  */
    1819            4 : gboolean bd_fs_can_set_uuid (const gchar *type, gchar **required_utility, GError **error) {
    1820            4 :     return query_fs_operation (type, BD_FS_UUID, required_utility, NULL, NULL, error);
    1821              : }
    1822              : 
    1823              : /**
    1824              :  * bd_fs_can_get_size:
    1825              :  * @type: the filesystem type to be tested for installed size querying support
    1826              :  * @required_utility: (out) (transfer full): the utility binary which is required
    1827              :  *                                           for size querying (if missing i.e. return FALSE but no error)
    1828              :  * @error: (out) (optional): place to store error (if any)
    1829              :  *
    1830              :  * Searches for the required utility to get size of the given filesystem and
    1831              :  * returns whether it is installed.
    1832              :  * Unknown filesystems or filesystems which do not support size querying result in errors.
    1833              :  *
    1834              :  * Returns: whether getting filesystem size is available
    1835              :  *
    1836              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_QUERY
    1837              :  */
    1838            3 : gboolean bd_fs_can_get_size (const gchar *type, gchar **required_utility, GError **error) {
    1839            3 :     return query_fs_operation (type, BD_FS_GET_SIZE, required_utility, NULL, NULL, error);
    1840              : }
    1841              : 
    1842              : /**
    1843              :  * bd_fs_can_get_free_space:
    1844              :  * @type: the filesystem type to be tested for installed free space querying support
    1845              :  * @required_utility: (out) (transfer full): the utility binary which is required
    1846              :  *                                           for free space querying (if missing i.e. return FALSE but no error)
    1847              :  * @error: (out) (optional): place to store error (if any)
    1848              :  *
    1849              :  * Searches for the required utility to get free space of the given filesystem and
    1850              :  * returns whether it is installed.
    1851              :  * Unknown filesystems or filesystems which do not support free space querying result in errors.
    1852              :  *
    1853              :  * Returns: whether getting filesystem free space is available
    1854              :  *
    1855              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_QUERY
    1856              :  */
    1857            6 : gboolean bd_fs_can_get_free_space (const gchar *type, gchar **required_utility, GError **error) {
    1858              :     /* some filesystems can't tell us free space even if we have the tools */
    1859            6 :     if (g_strcmp0 (type, "xfs") == 0 || g_strcmp0 (type, "f2fs") == 0 || g_strcmp0 (type, "exfat") == 0 || g_strcmp0 (type, "udf") == 0) {
    1860            3 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOT_SUPPORTED,
    1861              :                      "Getting free space on filesystem '%s' is not supported.", type);
    1862            3 :         return FALSE;
    1863              :     }
    1864              : 
    1865            3 :     return query_fs_operation (type, BD_FS_GET_FREE_SPACE, required_utility, NULL, NULL, error);
    1866              : }
    1867              : 
    1868              : /**
    1869              :  * bd_fs_can_get_info:
    1870              :  * @type: the filesystem type to be tested for info querying support
    1871              :  * @required_utility: (out) (transfer full): the utility binary which is required
    1872              :  *                                           for info querying (if missing i.e. return FALSE but no error)
    1873              :  * @error: (out) (optional): place to store error (if any)
    1874              :  *
    1875              :  * Searches for the required utility to get info of the given filesystem and
    1876              :  * returns whether it is installed.
    1877              :  * Unknown filesystems or filesystems which do not support info querying result in errors.
    1878              :  *
    1879              :  * Returns: whether getting filesystem info is available
    1880              :  *
    1881              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_QUERY
    1882              :  */
    1883            3 : gboolean bd_fs_can_get_info (const gchar *type, gchar **required_utility, GError **error) {
    1884            3 :     return query_fs_operation (type, BD_FS_GET_INFO, required_utility, NULL, NULL, error);
    1885              : }
    1886              : 
    1887              : /**
    1888              :  * bd_fs_can_get_min_size:
    1889              :  * @type: the filesystem type to be tested for installed minimum size querying support
    1890              :  * @required_utility: (out) (transfer full): the utility binary which is required
    1891              :  *                                           for size querying (if missing i.e. return FALSE but no error)
    1892              :  * @error: (out) (optional): place to store error (if any)
    1893              :  *
    1894              :  * Searches for the required utility to get minimum size of the given filesystem and
    1895              :  * returns whether it is installed.
    1896              :  * Unknown filesystems or filesystems which do not support minimum size querying result in errors.
    1897              :  *
    1898              :  * Returns: whether getting filesystem size is available
    1899              :  *
    1900              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_QUERY
    1901              :  */
    1902            7 : gboolean bd_fs_can_get_min_size (const gchar *type, gchar **required_utility, GError **error) {
    1903            7 :     return query_fs_operation (type, BD_FS_GET_MIN_SIZE, required_utility, NULL, NULL, error);
    1904              : }
    1905              : 
    1906            7 : static gboolean fs_freeze (const char *mountpoint, gboolean freeze, GError **error) {
    1907            7 :     gint fd = -1;
    1908            7 :     gint status = 0;
    1909              : 
    1910            7 :     if (!bd_fs_is_mountpoint (mountpoint, error)) {
    1911            3 :         if (error) {
    1912            3 :             if (*error != NULL) {
    1913            0 :                 g_prefix_error (error, "Failed to check mountpoint '%s': ", mountpoint);
    1914            0 :                 return FALSE;
    1915              :             } else {
    1916            3 :                 g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOT_MOUNTED,
    1917              :                             "'%s' doesn't appear to be a mountpoint.", mountpoint);
    1918            3 :                 return FALSE;
    1919              :             }
    1920              :         } else
    1921            0 :             return FALSE;
    1922              :     }
    1923              : 
    1924            4 :     fd = open (mountpoint, O_RDONLY);
    1925            4 :     if (fd == -1) {
    1926            0 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_FAIL,
    1927              :                      "Failed to open the mountpoint '%s': %s",
    1928            0 :                      mountpoint, strerror_l (errno, _C_LOCALE));
    1929            0 :         return FALSE;
    1930              :     }
    1931              : 
    1932            4 :     if (freeze)
    1933            3 :         status = ioctl (fd, FIFREEZE, 0);
    1934              :     else
    1935            1 :         status = ioctl (fd, FITHAW, 0);
    1936              : 
    1937            4 :     if (status != 0) {
    1938            2 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_FAIL,
    1939              :                      "Failed to %s '%s': %s.",
    1940              :                      freeze ? "freeze" : "unfreeze", mountpoint,
    1941            2 :                      strerror_l (errno, _C_LOCALE));
    1942            2 :         close (fd);
    1943            2 :         return FALSE;
    1944              :     }
    1945              : 
    1946            2 :     close (fd);
    1947              : 
    1948            2 :     return TRUE;
    1949              : }
    1950              : 
    1951              : /**
    1952              :  * bd_fs_freeze:
    1953              :  * @mountpoint: mountpoint of the device (filesystem) to freeze
    1954              :  * @error: (out) (optional): place to store error (if any)
    1955              :  *
    1956              :  * Freezes filesystem mounted on @mountpoint. The filesystem must
    1957              :  * support freezing.
    1958              :  *
    1959              :  * Returns: whether @mountpoint was successfully freezed or not
    1960              :  *
    1961              :  */
    1962            4 : gboolean bd_fs_freeze (const gchar *mountpoint, GError **error) {
    1963            4 :     return fs_freeze (mountpoint, TRUE, error);
    1964              : }
    1965              : 
    1966              : /**
    1967              :  * bd_fs_unfreeze:
    1968              :  * @mountpoint: mountpoint of the device (filesystem) to un-freeze
    1969              :  * @error: (out) (optional): place to store error (if any)
    1970              :  *
    1971              :  * Un-freezes filesystem mounted on @mountpoint. The filesystem must
    1972              :  * support freezing.
    1973              :  *
    1974              :  * Returns: whether @mountpoint was successfully unfreezed or not
    1975              :  *
    1976              :  */
    1977            3 : gboolean bd_fs_unfreeze (const gchar *mountpoint, GError **error) {
    1978            3 :     return fs_freeze (mountpoint, FALSE, error);
    1979              : }
    1980              : 
    1981              : extern BDExtraArg** bd_fs_exfat_mkfs_options (BDFSMkfsOptions *options, const BDExtraArg **extra);
    1982              : extern BDExtraArg** bd_fs_ext2_mkfs_options (BDFSMkfsOptions *options, const BDExtraArg **extra);
    1983              : extern BDExtraArg** bd_fs_ext3_mkfs_options (BDFSMkfsOptions *options, const BDExtraArg **extra);
    1984              : extern BDExtraArg** bd_fs_ext4_mkfs_options (BDFSMkfsOptions *options, const BDExtraArg **extra);
    1985              : extern BDExtraArg** bd_fs_f2fs_mkfs_options (BDFSMkfsOptions *options, const BDExtraArg **extra);
    1986              : extern BDExtraArg** bd_fs_nilfs2_mkfs_options (BDFSMkfsOptions *options, const BDExtraArg **extra);
    1987              : extern BDExtraArg** bd_fs_ntfs_mkfs_options (BDFSMkfsOptions *options, const BDExtraArg **extra);
    1988              : extern BDExtraArg** bd_fs_vfat_mkfs_options (BDFSMkfsOptions *options, const BDExtraArg **extra);
    1989              : extern BDExtraArg** bd_fs_xfs_mkfs_options (BDFSMkfsOptions *options, const BDExtraArg **extra);
    1990              : extern BDExtraArg** bd_fs_btrfs_mkfs_options (BDFSMkfsOptions *options, const BDExtraArg **extra);
    1991              : extern BDExtraArg** bd_fs_udf_mkfs_options (BDFSMkfsOptions *options, const BDExtraArg **extra);
    1992              : 
    1993              : /**
    1994              :  * bd_fs_mkfs:
    1995              :  * @device: the device to create the new filesystem on
    1996              :  * @fstype: name of the filesystem to create (e.g. "ext4")
    1997              :  * @options: additional options like label or UUID for the filesystem
    1998              :  * @extra: (nullable) (array zero-terminated=1): extra mkfs options not provided in @options
    1999              :  * @error: (out) (optional): place to store error (if any)
    2000              :  *
    2001              :  * This is a helper function for creating filesystems with extra options.
    2002              :  * This is the same as running a filesystem-specific function like %bd_fs_ext4_mkfs
    2003              :  * and manually specifying the extra command line options. %BDFSMkfsOptions
    2004              :  * removes the need to specify supported options for selected filesystems,
    2005              :  * make sure to check whether @fstype supports these options (see %bd_fs_can_mkfs)
    2006              :  * for details.
    2007              :  *
    2008              :  * When specifying additional mkfs options using @extra, it's caller's
    2009              :  * responsibility to make sure these options do not conflict with options
    2010              :  * specified using @options. Extra options are added after the @options and
    2011              :  * there are no additional checks for duplicate and/or conflicting options.
    2012              :  *
    2013              :  * Returns: whether @fstype was successfully created on @device or not.
    2014              :  *
    2015              :  * Tech category: %BD_FS_TECH_GENERIC-%BD_FS_TECH_MODE_MKFS
    2016              :  *
    2017              :  */
    2018           53 : gboolean bd_fs_mkfs (const gchar *device, const gchar *fstype, BDFSMkfsOptions *options, const BDExtraArg **extra, GError **error) {
    2019           53 :     BDExtraArg **extra_args = NULL;
    2020           53 :     gboolean ret = FALSE;
    2021              : 
    2022           53 :     if (g_strcmp0 (fstype, "exfat") == 0) {
    2023            1 :         extra_args = bd_fs_exfat_mkfs_options (options, extra);
    2024            1 :         ret = bd_fs_exfat_mkfs (device, (const BDExtraArg **) extra_args, error);
    2025           52 :     } else if (g_strcmp0 (fstype, "ext2") == 0) {
    2026            5 :         extra_args = bd_fs_ext2_mkfs_options (options, extra);
    2027            5 :         ret = bd_fs_ext2_mkfs (device, (const BDExtraArg **) extra_args, error);
    2028           47 :     } else if (g_strcmp0 (fstype, "ext3") == 0) {
    2029            4 :         extra_args = bd_fs_ext3_mkfs_options (options, extra);
    2030            4 :         ret = bd_fs_ext3_mkfs (device, (const BDExtraArg **) extra_args, error);
    2031           43 :     } else if (g_strcmp0 (fstype, "ext4") == 0) {
    2032            4 :         extra_args = bd_fs_ext4_mkfs_options (options, extra);
    2033            4 :         ret = bd_fs_ext4_mkfs (device, (const BDExtraArg **) extra_args, error);
    2034           39 :     } else if (g_strcmp0 (fstype, "f2fs") == 0) {
    2035            6 :         extra_args = bd_fs_f2fs_mkfs_options (options, extra);
    2036            6 :         ret = bd_fs_f2fs_mkfs (device, (const BDExtraArg **) extra_args, error);
    2037           33 :     } else if (g_strcmp0 (fstype, "nilfs2") == 0) {
    2038            8 :         extra_args = bd_fs_nilfs2_mkfs_options (options, extra);
    2039            8 :         ret = bd_fs_nilfs2_mkfs (device, (const BDExtraArg **) extra_args, error);
    2040           25 :     } else if (g_strcmp0 (fstype, "ntfs") == 0) {
    2041            4 :         extra_args = bd_fs_ntfs_mkfs_options (options, extra);
    2042            4 :         ret = bd_fs_ntfs_mkfs (device, (const BDExtraArg **) extra_args, error);
    2043           21 :     } else if (g_strcmp0 (fstype, "vfat") == 0) {
    2044            4 :         extra_args = bd_fs_vfat_mkfs_options (options, extra);
    2045            4 :         ret = bd_fs_vfat_mkfs (device, (const BDExtraArg **) extra_args, error);
    2046           17 :     } else if (g_strcmp0 (fstype, "xfs") == 0) {
    2047            8 :         extra_args = bd_fs_xfs_mkfs_options (options, extra);
    2048            8 :         ret = bd_fs_xfs_mkfs (device, (const BDExtraArg **) extra_args, error);
    2049            9 :     } else if (g_strcmp0 (fstype, "btrfs") == 0) {
    2050            6 :         extra_args = bd_fs_btrfs_mkfs_options (options, extra);
    2051            6 :         ret = bd_fs_btrfs_mkfs (device, (const BDExtraArg **) extra_args, error);
    2052            3 :     } else if (g_strcmp0 (fstype, "udf") == 0) {
    2053            2 :         extra_args = bd_fs_udf_mkfs_options (options, extra);
    2054            2 :         ret = bd_fs_udf_mkfs (device, NULL, NULL, 0, (const BDExtraArg **) extra_args, error);
    2055              :     } else {
    2056            1 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOT_SUPPORTED,
    2057              :                      "Filesystem '%s' is not supported.", fstype);
    2058            1 :         return FALSE;
    2059              :     }
    2060              : 
    2061           52 :     bd_extra_arg_list_free (extra_args);
    2062           52 :     return ret;
    2063              : }
    2064              : 
    2065              : /**
    2066              :  * bd_fs_features:
    2067              :  * @fstype: name of the filesystem to get features for (e.g. "ext4")
    2068              :  * @error: (allow-none): (out): place to store error (if any)
    2069              :  *
    2070              :  * Returns (transfer-none): features supported by @fstype, see %BDFSFeatures for more information.
    2071              :  *
    2072              :  * Tech category: always available
    2073              :  *
    2074              :  */
    2075           11 : const BDFSFeatures* bd_fs_features (const gchar *fstype, GError **error) {
    2076           11 :     BDFSTech tech = fstype_to_tech (fstype);
    2077              : 
    2078           11 :     if (tech == BD_FS_TECH_GENERIC) {
    2079            0 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOT_SUPPORTED,
    2080              :                      "Filesystem '%s' is not supported.", fstype);
    2081            0 :         return NULL;
    2082              :     }
    2083              : 
    2084           11 :     return &fs_features[tech];
    2085              : }
        

Generated by: LCOV version 2.0-1