From a2b111e34af4ffbb4ab3bac084ead4b1601c6f88 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Mon, 17 Oct 2011 11:53:39 +0200 Subject: [PATCH] =?utf8?q?Bug=2041862=20=E2=80=94=20Add=20label=20changing?= =?utf8?q?=20for=20previously=20supported=20file=20systems?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Add support for label changing on vfat, ntfs, xfs, reiserfs, and nilfs2 file systems. Instead of having another huge if-then-else ladder as in udisks1, use a lookup table _fs_info. For now this contains the commands for label changing and erasing, but will be extended in the future to contain the commands for creating and checking file systems. https://bugs.freedesktop.org/show_bug.cgi?id=41862 --- src/Makefile.am | 1 + src/udiskslinuxfilesystem.c | 77 +++++++++++++++++++++++----- src/udiskslinuxfsinfo.c | 119 ++++++++++++++++++++++++++++++++++++++++++++ src/udiskslinuxfsinfo.h | 40 +++++++++++++++ 4 files changed, 225 insertions(+), 12 deletions(-) create mode 100644 src/udiskslinuxfsinfo.c create mode 100644 src/udiskslinuxfsinfo.h diff --git a/src/Makefile.am b/src/Makefile.am index 2b57111..b47c4a3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -59,6 +59,7 @@ libudisks_daemon_la_SOURCES = \ udiskslinuxdrive.h udiskslinuxdrive.c \ udiskslinuxdriveata.h udiskslinuxdriveata.c \ udiskslinuxmanager.h udiskslinuxmanager.c \ + udiskslinuxfsinfo.h udiskslinuxfsinfo.c \ udisksbasejob.h udisksbasejob.c \ udisksspawnedjob.h udisksspawnedjob.c \ udisksthreadedjob.h udisksthreadedjob.c \ diff --git a/src/udiskslinuxfilesystem.c b/src/udiskslinuxfilesystem.c index 833c469..d2e54e9 100644 --- a/src/udiskslinuxfilesystem.c +++ b/src/udiskslinuxfilesystem.c @@ -34,6 +34,7 @@ #include "udiskslogging.h" #include "udiskslinuxfilesystem.h" #include "udiskslinuxblockobject.h" +#include "udiskslinuxfsinfo.h" #include "udisksdaemon.h" #include "udiskscleanup.h" #include "udisksdaemonutil.h" @@ -445,6 +446,20 @@ prepend_default_mount_options (const FSMountOptions *fsmo, return (char **) g_ptr_array_free (options, FALSE); } +static gchar * +subst_str (const gchar *str, + const gchar *from, + const gchar *to) +{ + gchar **parts; + gchar *result; + + parts = g_strsplit (str, from, 0); + result = g_strjoinv (to, parts); + g_strfreev (parts); + return result; +} + /* ---------------------------------------------------------------------------------------------------- */ /* @@ -1437,15 +1452,17 @@ handle_set_label (UDisksFilesystem *filesystem, UDisksDaemon *daemon; const gchar *probed_fs_usage; const gchar *probed_fs_type; - gboolean supports_online; + const FSInfo *fs_info; UDisksBaseJob *job; gchar *escaped_label; const gchar *action_id; + gchar *command; + gchar *tmp; object = NULL; daemon = NULL; - supports_online = FALSE; escaped_label = NULL; + command = NULL; object = UDISKS_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (filesystem))); daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object)); @@ -1454,11 +1471,19 @@ handle_set_label (UDisksFilesystem *filesystem, probed_fs_usage = udisks_block_get_id_usage (block); probed_fs_type = udisks_block_get_id_type (block); - /* TODO: add support for other fstypes */ - if (!(g_strcmp0 (probed_fs_usage, "filesystem") == 0 && - (g_strcmp0 (probed_fs_type, "ext2") == 0 || - g_strcmp0 (probed_fs_type, "ext3") == 0 || - g_strcmp0 (probed_fs_type, "ext4") == 0))) + if (g_strcmp0 (probed_fs_usage, "filesystem") != 0) + { + g_dbus_method_invocation_return_error (invocation, + UDISKS_ERROR, + UDISKS_ERROR_NOT_SUPPORTED, + "Cannot change label on device of type %s", + probed_fs_usage); + goto out; + } + + fs_info = get_fs_info (probed_fs_type); + + if (fs_info == NULL || fs_info->command_change_label == NULL) { g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, @@ -1468,12 +1493,29 @@ handle_set_label (UDisksFilesystem *filesystem, probed_fs_type); goto out; } - supports_online = TRUE; + + /* VFAT does not allow some characters; as mlabel hangs with interactive + * question in this case, check in advance */ + if (g_strcmp0 (probed_fs_type, "vfat") == 0) + { + for (tmp = "\"*/:<>?\\|"; *tmp; ++tmp) + { + if (strchr (label, *tmp) != NULL) + { + g_dbus_method_invocation_return_error (invocation, + UDISKS_ERROR, + UDISKS_ERROR_NOT_SUPPORTED, + "character '%c' not supported in VFAT labels", + *tmp); + goto out; + } + } + } /* Fail if the device is already mounted and the tools/drivers doesn't * support changing the label in that case */ - if (filesystem != NULL && !supports_online) + if (filesystem != NULL && !fs_info->supports_online_label_rename) { const gchar * const *existing_mount_points; existing_mount_points = udisks_filesystem_get_mount_points (filesystem); @@ -1505,14 +1547,24 @@ handle_set_label (UDisksFilesystem *filesystem, goto out; escaped_label = g_shell_quote (label); + + if (fs_info->command_clear_label != NULL && strlen (label) == 0) + { + command = subst_str (fs_info->command_clear_label, "$DEVICE", udisks_block_get_device (block)); + } + else + { + tmp = subst_str (fs_info->command_change_label, "$DEVICE", udisks_block_get_device (block)); + command = subst_str (tmp, "$LABEL", escaped_label); + g_free (tmp); + } + job = udisks_daemon_launch_spawned_job (daemon, NULL, /* cancellable */ 0, /* uid_t run_as_uid */ 0, /* uid_t run_as_euid */ NULL, /* input_string */ - "e2label %s %s", - udisks_block_get_device (block), - escaped_label); + "%s", command); g_signal_connect (job, "completed", G_CALLBACK (on_set_label_job_completed), @@ -1520,6 +1572,7 @@ handle_set_label (UDisksFilesystem *filesystem, out: g_free (escaped_label); + g_free (command); return TRUE; /* returning TRUE means that we handled the method invocation */ } diff --git a/src/udiskslinuxfsinfo.c b/src/udiskslinuxfsinfo.c new file mode 100644 index 0000000..8a485dc --- /dev/null +++ b/src/udiskslinuxfsinfo.c @@ -0,0 +1,119 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2011 Martin Pitt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include + +#include "config.h" +#include "udiskslinuxfsinfo.h" + +const FSInfo _fs_info[] = + { + { + "ext2", + "e2label $DEVICE $LABEL", + NULL, + TRUE, + }, + { + "ext3", + "e2label $DEVICE $LABEL", + NULL, + TRUE, + }, + { + "ext4", + "e2label $DEVICE $LABEL", + NULL, + TRUE, + }, + { + "vfat", + "mlabel -i $DEVICE ::$LABEL", + "mlabel -i $DEVICE -c ::", + FALSE, + }, + { + "ntfs", + "ntfslabel $DEVICE $LABEL", + NULL, + FALSE, + }, + { + "xfs", + "xfs_admin -L $LABEL $DEVICE", + "xfs_admin -L -- $DEVICE", + FALSE, + }, + { + "reiserfs", + "reiserfstune -l $LABEL $DEVICE", + NULL, + FALSE, + }, + { + "nilfs2", + "nilfs-tune -L $LABEL $DEVICE", + NULL, + FALSE, + }, + { + "btrfs", + NULL, + NULL, + FALSE, + }, + { + "minix", + NULL, + NULL, + FALSE, + }, + { + "swap", + NULL, + NULL, + FALSE, + }, + }; + +/** + * get_fs_info: + * + * Look up #FSInfo record for a particular file system. + * @fstype: file system type name + * + * Returns: (transfer none): #FSInfo struct for @fstype, or %NULL if that file + * system is unknown. Do not free or modify. + */ +const FSInfo * +get_fs_info (const gchar *fstype) +{ + gint n; + g_return_val_if_fail (fstype != NULL, NULL); + + for (n = 0; n < sizeof(_fs_info)/sizeof(FSInfo); n++) + { + if (strcmp (_fs_info[n].fstype, fstype) == 0) + return &_fs_info[n]; + } + + return NULL; +} diff --git a/src/udiskslinuxfsinfo.h b/src/udiskslinuxfsinfo.h new file mode 100644 index 0000000..bb34082 --- /dev/null +++ b/src/udiskslinuxfsinfo.h @@ -0,0 +1,40 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2011 Martin Pitt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __UDISKS_LINUX_FSINFO_H__ +#define __UDISKS_LINUX_FSINFO_H__ + +#include + +G_BEGIN_DECLS + +typedef struct +{ + const gchar *fstype; + const gchar *command_change_label; /* should have $DEVICE and $LABEL */ + const gchar *command_clear_label; /* should have $DEVICE; if NULL, call command_change_label with $LABEL == '' */ + gboolean supports_online_label_rename; +} FSInfo; + +const FSInfo *get_fs_info (const gchar *fstype); + +G_END_DECLS + +#endif /* __UDISKS_LINUX_FSINFO_H__ */ -- 2.7.4