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 67 : static BDFSTech fstype_to_tech (const gchar *fstype) {
347 67 : if (g_strcmp0 (fstype, "exfat") == 0) {
348 3 : return BD_FS_TECH_EXFAT;
349 64 : } else if (g_strcmp0 (fstype, "ext2") == 0) {
350 3 : return BD_FS_TECH_EXT2;
351 61 : } else if (g_strcmp0 (fstype, "ext3") == 0) {
352 3 : return BD_FS_TECH_EXT3;
353 58 : } else if (g_strcmp0 (fstype, "ext4") == 0) {
354 11 : return BD_FS_TECH_EXT4;
355 47 : } else if (g_strcmp0 (fstype, "f2fs") == 0) {
356 3 : return BD_FS_TECH_F2FS;
357 44 : } else if (g_strcmp0 (fstype, "nilfs2") == 0) {
358 5 : return BD_FS_TECH_NILFS2;
359 39 : } else if (g_strcmp0 (fstype, "ntfs") == 0) {
360 4 : return BD_FS_TECH_NTFS;
361 35 : } else if (g_strcmp0 (fstype, "vfat") == 0) {
362 7 : return BD_FS_TECH_VFAT;
363 28 : } else if (g_strcmp0 (fstype, "xfs") == 0) {
364 12 : return BD_FS_TECH_XFS;
365 16 : } else if (g_strcmp0 (fstype, "btrfs") == 0) {
366 3 : return BD_FS_TECH_BTRFS;
367 13 : } else if (g_strcmp0 (fstype, "udf") == 0) {
368 7 : return BD_FS_TECH_UDF;
369 : } else {
370 6 : 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 115 : gboolean bd_fs_wipe (const gchar *device, gboolean all, gboolean force, GError **error) {
386 115 : blkid_probe probe = NULL;
387 115 : gint fd = 0;
388 115 : gint status = 0;
389 115 : guint64 progress_id = 0;
390 115 : gchar *msg = NULL;
391 115 : guint n_try = 0;
392 115 : gint mode = 0;
393 115 : GError *l_error = NULL;
394 :
395 115 : msg = g_strdup_printf ("Started wiping signatures from the device '%s'", device);
396 115 : progress_id = bd_utils_report_started (msg);
397 115 : g_free (msg);
398 :
399 115 : probe = blkid_new_probe ();
400 115 : 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 115 : mode = O_RDWR | O_CLOEXEC;
409 115 : if (!force)
410 113 : mode |= O_EXCL;
411 :
412 115 : fd = open (device, mode);
413 115 : if (fd == -1) {
414 5 : g_set_error (&l_error, BD_FS_ERROR, BD_FS_ERROR_FAIL,
415 : "Failed to open the device '%s': %s",
416 5 : device, strerror_l (errno, _C_LOCALE));
417 5 : blkid_free_probe (probe);
418 5 : bd_utils_report_finished (progress_id, l_error->message);
419 5 : g_propagate_error (error, l_error);
420 5 : 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 220 : for (n_try=5, status=-1; (status != 0) && (n_try > 0); n_try--) {
426 110 : status = blkid_probe_set_device (probe, fd, 0, 0);
427 110 : if (status != 0)
428 0 : g_usleep (100 * 1000); /* microseconds */
429 : }
430 110 : 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 110 : blkid_probe_enable_partitions (probe, 1);
441 110 : blkid_probe_set_partitions_flags (probe, BLKID_PARTS_MAGIC);
442 110 : blkid_probe_enable_superblocks (probe, 1);
443 110 : 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 152 : for (n_try=5, status=-1; (status != 0) && (n_try > 0); n_try--) {
448 110 : status = blkid_do_safeprobe (probe);
449 110 : if (status == 1)
450 68 : break;
451 42 : if (status < 0)
452 0 : g_usleep (100 * 1000); /* microseconds */
453 : }
454 110 : if (status == 1) {
455 68 : g_set_error (&l_error, BD_FS_ERROR, BD_FS_ERROR_NOFS,
456 : "No signature detected on the device '%s'", device);
457 68 : blkid_free_probe (probe);
458 68 : synced_close (fd);
459 68 : bd_utils_report_finished (progress_id, l_error->message);
460 68 : g_propagate_error (error, l_error);
461 68 : return FALSE;
462 : }
463 :
464 42 : blkid_reset_probe (probe);
465 42 : status = blkid_do_probe (probe);
466 :
467 42 : 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 42 : status = blkid_do_wipe (probe, FALSE);
478 42 : 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 62 : 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 42 : blkid_free_probe (probe);
501 42 : synced_close (fd);
502 :
503 42 : bd_utils_report_finished (progress_id, "Completed");
504 :
505 42 : 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 83 : gboolean bd_fs_clean (const gchar *device, gboolean force, GError **error) {
524 83 : gboolean ret = FALSE;
525 83 : GError *l_error = NULL;
526 :
527 83 : ret = bd_fs_wipe (device, TRUE, force, &l_error);
528 :
529 83 : if (!ret) {
530 69 : if (g_error_matches (l_error, BD_FS_ERROR, BD_FS_ERROR_NOFS)) {
531 : /* ignore 'empty device' error */
532 67 : g_clear_error (&l_error);
533 67 : 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 136 : gchar* bd_fs_get_fstype (const gchar *device, GError **error) {
556 136 : blkid_probe probe = NULL;
557 136 : gint fd = 0;
558 136 : gint status = 0;
559 136 : const gchar *value = NULL;
560 136 : gchar *fstype = NULL;
561 136 : size_t len = 0;
562 136 : guint n_try = 0;
563 :
564 136 : probe = blkid_new_probe ();
565 136 : 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 136 : fd = open (device, O_RDONLY|O_CLOEXEC);
572 136 : 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 272 : for (n_try=5, status=-1; (status != 0) && (n_try > 0); n_try--) {
583 136 : status = blkid_probe_set_device (probe, fd, 0, 0);
584 136 : if (status != 0)
585 0 : g_usleep (100 * 1000); /* microseconds */
586 : }
587 136 : 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 136 : blkid_probe_enable_partitions (probe, 1);
596 136 : blkid_probe_set_partitions_flags (probe, BLKID_PARTS_MAGIC);
597 136 : blkid_probe_enable_superblocks (probe, 1);
598 136 : 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 272 : for (n_try=5, status=-1; !(status == 0 || status == 1) && (n_try > 0); n_try--) {
604 136 : status = blkid_do_safeprobe (probe);
605 136 : if (status < 0)
606 0 : g_usleep (100 * 1000); /* microseconds */
607 : }
608 136 : 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 136 : } 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 125 : status = blkid_probe_lookup_value (probe, "USAGE", &value, &len);
623 125 : 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 125 : 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 125 : status = blkid_probe_lookup_value (probe, "TYPE", &value, &len);
640 125 : 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 125 : fstype = g_strdup (value);
649 125 : blkid_free_probe (probe);
650 125 : synced_close (fd);
651 :
652 125 : 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 2 : static gboolean xfs_quota_mount_options (const gchar *device, GString *options, GError **error) {
664 2 : g_autofree gchar *output = NULL;
665 2 : gboolean success = FALSE;
666 2 : const gchar *args[8] = {"xfs_db", "-r", device, "-c", "sb 0", "-c", "p qflags", NULL};
667 2 : guint64 flags = 0;
668 :
669 2 : success = bd_utils_exec_and_capture_output (args, NULL, &output, error);
670 2 : if (!success) {
671 : /* error is already populated */
672 0 : return FALSE;
673 : }
674 :
675 2 : 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 2 : flags = g_ascii_strtoull (output + 9, NULL, 16);
682 2 : if (flags & _XFS_UQUOTA_ACCT) {
683 1 : if (flags & _XFS_UQUOTA_ENFD)
684 1 : g_string_append_printf (options, "uquota,");
685 : else
686 0 : g_string_append_printf (options, "uqnoenforce,");
687 : }
688 :
689 2 : if (flags & _XFS_GQUOTA_ACCT) {
690 1 : if (flags & _XFS_GQUOTA_ENFD)
691 1 : g_string_append_printf (options, "gquota,");
692 : else
693 0 : g_string_append_printf (options, "gqnoenforce,");
694 : }
695 :
696 2 : if (flags & _XFS_PQUOTA_ACCT) {
697 1 : if (flags & _XFS_PQUOTA_ENFD)
698 1 : g_string_append_printf (options, "pquota,");
699 : else
700 0 : g_string_append_printf (options, "pqnoenforce,");
701 : }
702 :
703 2 : 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 24 : static gchar* fs_mount (const gchar *device, gchar *fstype, gboolean read_only, gboolean *unmount, GError **error) {
723 24 : gchar *mountpoint = NULL;
724 24 : gboolean ret = FALSE;
725 24 : GError *l_error = NULL;
726 24 : GString *options = NULL;
727 24 : g_autofree gchar *options_str = NULL;
728 :
729 24 : mountpoint = bd_fs_get_mountpoint (device, &l_error);
730 24 : if (!mountpoint) {
731 16 : if (l_error == NULL) {
732 : /* device is not mounted -- we need to mount it */
733 16 : mountpoint = g_dir_make_tmp ("blockdev.XXXXXX", NULL);
734 16 : 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 16 : options = g_string_new (NULL);
741 16 : if (g_strcmp0 (fstype, "xfs") == 0) {
742 2 : ret = xfs_quota_mount_options (device, options, &l_error);
743 2 : 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 16 : if (read_only)
750 8 : g_string_append_printf (options, "nosuid,nodev,ro");
751 : else
752 8 : g_string_append_printf (options, "nosuid,nodev");
753 16 : options_str = g_string_free (options, FALSE);
754 :
755 16 : ret = bd_fs_mount (device, mountpoint, fstype, options_str, NULL, &l_error);
756 16 : 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 16 : *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 24 : return mountpoint;
775 : }
776 :
777 16 : static gboolean fs_unmount (const gchar *device, const gchar *mountpoint, const gchar *operation, GError **error) {
778 16 : gboolean ret = FALSE;
779 16 : GError *local_error = NULL;
780 :
781 16 : ret = bd_fs_unmount (mountpoint, FALSE, FALSE, NULL, &local_error);
782 16 : 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 16 : 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 16 : 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 6 : static gboolean xfs_resize_device (const gchar *device, guint64 new_size, const BDExtraArg **extra, GError **error) {
811 6 : g_autofree gchar* mountpoint = NULL;
812 6 : gboolean ret = FALSE;
813 6 : gboolean success = FALSE;
814 6 : gboolean unmount = FALSE;
815 6 : GError *local_error = NULL;
816 6 : BDFSXfsInfo* xfs_info = NULL;
817 :
818 6 : xfs_info = bd_fs_xfs_get_info (device, error);
819 6 : if (!xfs_info) {
820 0 : return FALSE;
821 : }
822 :
823 6 : mountpoint = fs_mount (device, "xfs", FALSE, &unmount, error);
824 6 : if (!mountpoint)
825 0 : return FALSE;
826 :
827 6 : new_size = (new_size + xfs_info->block_size - 1) / xfs_info->block_size;
828 6 : bd_fs_xfs_info_free (xfs_info);
829 :
830 6 : success = bd_fs_xfs_resize (mountpoint, new_size, extra, error);
831 :
832 6 : if (unmount) {
833 2 : ret = fs_unmount (device, mountpoint, "resizing", &local_error);
834 2 : 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 6 : 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 103 : static gboolean device_operation (const gchar *device, const gchar *fstype, BDFSOpType op, guint64 new_size, const gchar *label, const gchar *uuid, GError **error) {
996 103 : const gchar* op_name = NULL;
997 103 : 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 103 : 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 103 : g_assert_true (op != BD_FS_GET_SIZE);
1004 :
1005 103 : if (!fstype) {
1006 49 : detected_fstype = bd_fs_get_fstype (device, error);
1007 49 : 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 54 : detected_fstype = g_strdup (fstype);
1022 :
1023 103 : if (g_strcmp0 (detected_fstype, "ext2") == 0 || g_strcmp0 (detected_fstype, "ext3") == 0
1024 99 : || g_strcmp0 (detected_fstype, "ext4") == 0) {
1025 17 : 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 1 : case BD_FS_LABEL_CHECK:
1035 1 : 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 86 : } else if (g_strcmp0 (detected_fstype, "xfs") == 0) {
1044 16 : switch (op) {
1045 6 : case BD_FS_RESIZE:
1046 6 : 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 1 : case BD_FS_LABEL_CHECK:
1054 1 : 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 70 : } else if (g_strcmp0 (detected_fstype, "vfat") == 0) {
1063 5 : 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 0 : case BD_FS_LABEL_CHECK:
1071 0 : return bd_fs_vfat_check_label (label, error);
1072 0 : case BD_FS_LABEL:
1073 0 : 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 65 : } else if (g_strcmp0 (detected_fstype, "ntfs") == 0) {
1082 16 : 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 1 : case BD_FS_LABEL_CHECK:
1090 1 : 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 49 : } else if (g_strcmp0 (detected_fstype, "f2fs") == 0) {
1101 7 : 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 1 : case BD_FS_LABEL_CHECK:
1111 1 : 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 42 : } else if (g_strcmp0 (detected_fstype, "nilfs2") == 0) {
1120 10 : 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 1 : case BD_FS_LABEL_CHECK:
1130 1 : 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 32 : } else if (g_strcmp0 (detected_fstype, "exfat") == 0) {
1139 11 : 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 1 : case BD_FS_LABEL_CHECK:
1149 1 : 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 21 : } else if (g_strcmp0 (detected_fstype, "btrfs") == 0) {
1158 14 : 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 1 : case BD_FS_LABEL_CHECK:
1168 1 : 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 7 : } else if (g_strcmp0 (detected_fstype, "udf") == 0) {
1177 7 : 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 1 : case BD_FS_LABEL_CHECK:
1187 1 : 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 6 : 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 0 : case BD_FS_LABEL_CHECK:
1210 0 : op_name = "Checking label format for";
1211 0 : break;
1212 1 : case BD_FS_UUID:
1213 1 : op_name = "Setting UUID of";
1214 1 : break;
1215 0 : case BD_FS_UUID_CHECK:
1216 0 : op_name = "Checking UUID format for";
1217 0 : break;
1218 0 : default:
1219 0 : g_assert_not_reached ();
1220 : }
1221 6 : g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOT_SUPPORTED,
1222 : "%s filesystem '%s' is not supported.", op_name, detected_fstype);
1223 6 : 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 24 : gboolean bd_fs_resize (const gchar *device, guint64 new_size, const gchar *fstype, GError **error) {
1246 24 : 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 8 : gboolean bd_fs_check_label (const gchar *fstype, const gchar *label, GError **error) {
1308 8 : if (!fstype) {
1309 0 : g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOFS,
1310 : "Filesystem type must be specified to check label format");
1311 0 : return FALSE;
1312 : }
1313 8 : 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 15 : gboolean bd_fs_set_label (const gchar *device, const gchar *label, const gchar *fstype, GError **error) {
1336 15 : 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 8 : gboolean bd_fs_check_uuid (const gchar *fstype, const gchar *uuid, GError **error) {
1355 8 : if (!fstype) {
1356 0 : g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOFS,
1357 : "Filesystem type must be specified to check UUID format");
1358 0 : return FALSE;
1359 : }
1360 8 : 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 56 : static gboolean query_fs_operation (const gchar *fs_type, BDFSOpType op, gchar **required_utility, BDFSResizeFlags *mode, BDFSMkfsOptionsFlags *options, GError **error) {
1621 : gboolean ret;
1622 56 : const BDFSInfo *fsinfo = NULL;
1623 56 : const gchar* op_name = NULL;
1624 56 : const gchar* exec_util = NULL;
1625 : BDFSTech tech;
1626 :
1627 56 : if (required_utility != NULL)
1628 56 : *required_utility = NULL;
1629 :
1630 56 : if (mode != NULL)
1631 5 : *mode = 0;
1632 :
1633 56 : if (options != NULL)
1634 22 : *options = 0;
1635 :
1636 56 : tech = fstype_to_tech (fs_type);
1637 56 : if (tech == BD_FS_TECH_GENERIC) {
1638 6 : g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOT_SUPPORTED,
1639 : "Filesystem '%s' is not supported.", fs_type);
1640 6 : return FALSE;
1641 : }
1642 50 : fsinfo = &fs_info[tech];
1643 :
1644 50 : 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 0 : case BD_FS_UUID:
1666 0 : op_name = "Setting UUID of";
1667 0 : exec_util = fsinfo->uuid_util;
1668 0 : 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 4 : case BD_FS_GET_FREE_SPACE:
1674 4 : op_name = "Getting free space on";
1675 4 : exec_util = fsinfo->info_util;
1676 4 : break;
1677 0 : case BD_FS_GET_INFO:
1678 0 : op_name = "Getting filesystem info of";
1679 0 : exec_util = fsinfo->info_util;
1680 0 : 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 50 : if (exec_util == NULL) {
1690 8 : g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_NOT_SUPPORTED,
1691 : "%s filesystem '%s' is not supported.", op_name, fs_type);
1692 8 : return FALSE;
1693 : }
1694 :
1695 42 : if (mode != NULL)
1696 3 : *mode = fs_features[tech].resize;
1697 :
1698 42 : if (options != NULL)
1699 22 : *options = fs_features[tech].mkfs;
1700 :
1701 42 : if (strlen (exec_util) == 0) { /* empty string if no util needed */
1702 0 : return TRUE;
1703 : }
1704 :
1705 42 : ret = bd_utils_check_util_version (exec_util, NULL, "", NULL, NULL);
1706 42 : if (!ret && required_utility != NULL)
1707 8 : *required_utility = g_strdup (exec_util);
1708 :
1709 42 : 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 0 : gboolean bd_fs_can_set_uuid (const gchar *type, gchar **required_utility, GError **error) {
1820 0 : 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 9 : 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 9 : 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 6 : 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 0 : gboolean bd_fs_can_get_info (const gchar *type, gchar **required_utility, GError **error) {
1884 0 : 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 : }
|