diff --git a/src/udiskslinuxfilesystem.c b/src/udiskslinuxfilesystem.c index b637b6db4..6d820c704 100644 --- a/src/udiskslinuxfilesystem.c +++ b/src/udiskslinuxfilesystem.c @@ -40,6 +40,10 @@ #include #include +#include +#include +#include +#include #include "udiskslogging.h" #include "udiskslinuxfilesystem.h" @@ -419,45 +423,68 @@ static gboolean is_in_filesystem_file (const gchar *filesystems_file, const gchar *fstype) { - gchar *filesystems = NULL; - GError *error = NULL; gboolean ret = FALSE; + int fd = -1; + struct stat sb; + void *addr = NULL; + gchar *contents = NULL; gchar **lines = NULL; guint n; - if (!g_file_get_contents (filesystems_file, - &filesystems, - NULL, /* gsize *out_length */ - &error)) + fd = open (filesystems_file, O_RDONLY); + if (fd == -1) { - udisks_warning ("Error reading %s: %s (%s %d)", - filesystems_file, - error->message, - g_quark_to_string (error->domain), - error->code); - g_clear_error (&error); + if (errno != ENOENT) + udisks_warning ("Error opening %s: %m", filesystems_file); + goto out; + } + + if (fstat (fd, &sb) == -1) + { + udisks_warning ("Error stating %s: %m", filesystems_file); goto out; } - lines = g_strsplit (filesystems, "\n", -1); - for (n = 0; lines != NULL && lines[n] != NULL && !ret; n++) + if (sb.st_size > 0) { - gchar **tokens; - gint num_tokens; - g_strdelimit (lines[n], " \t", ' '); - g_strstrip (lines[n]); - tokens = g_strsplit (lines[n], " ", -1); - num_tokens = g_strv_length (tokens); - if (num_tokens == 1 && g_strcmp0 (tokens[0], fstype) == 0) + addr = mmap (NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (addr == MAP_FAILED) { - ret = TRUE; + udisks_warning ("Error mmaping %s: %m", filesystems_file); + addr = NULL; + goto out; + } + contents = g_strndup (addr, sb.st_size); + } + else + { + contents = g_strdup (""); + } + + if (contents != NULL) + { + lines = g_strsplit (contents, "\n", -1); + for (n = 0; lines != NULL && lines[n] != NULL && !ret; n++) + { + gchar **tokens; + g_strdelimit (lines[n], " \t", ' '); + g_strstrip (lines[n]); + tokens = g_strsplit (lines[n], " ", -1); + if (g_strv_length (tokens) == 1 && g_strcmp0 (tokens[0], fstype) == 0) + { + ret = TRUE; + } + g_strfreev (tokens); } - g_strfreev (tokens); } - out: +out: g_strfreev (lines); - g_free (filesystems); + g_free (contents); + if (addr != NULL) + munmap (addr, sb.st_size); + if (fd != -1) + close (fd); return ret; } diff --git a/src/udisksstate.c b/src/udisksstate.c index a3b567764..2d5fff109 100644 --- a/src/udisksstate.c +++ b/src/udisksstate.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include "udisksdaemon.h" #include "udisksstate.h" @@ -2302,24 +2304,17 @@ udisks_state_get (UDisksState *state, const GVariantType *type) { gchar *path; - GVariant *ret; - gchar *contents = NULL; - GError *local_error = NULL; - gsize length = 0; + GVariant *ret = NULL; + int fd = -1; + struct stat sb; + void *addr = NULL; g_return_val_if_fail (UDISKS_IS_STATE (state), NULL); g_return_val_if_fail (key != NULL, NULL); g_return_val_if_fail (g_variant_type_is_definite (type), NULL); - /* TODO: - * - * - could use a cache here to avoid loading files all the time - * - could also mmap the file - */ - path = get_state_file_path (key); - /* see if it's already in the cache */ ret = g_hash_table_lookup (state->cache, path); if (ret != NULL) { @@ -2327,40 +2322,41 @@ udisks_state_get (UDisksState *state, goto out; } - if (!g_file_get_contents (path, - &contents, - &length, - &local_error)) + fd = open (path, O_RDONLY); + if (fd == -1) { - if (local_error->domain == G_FILE_ERROR && local_error->code == G_FILE_ERROR_NOENT) - { - /* this is not an error */ - g_clear_error (&local_error); - goto out; - } + if (errno != ENOENT) + udisks_warning ("Error opening state file %s: %m", path); + goto out; + } - udisks_warning ("Error getting state data %s: %s (%s, %d)", - key, - local_error->message, - g_quark_to_string (local_error->domain), - local_error->code); - g_clear_error (&local_error); + if (fstat (fd, &sb) == -1) + { + udisks_warning ("Error stating state file %s: %m", path); goto out; } - ret = g_variant_new_from_data (type, - (gconstpointer) contents, - length, - FALSE, - g_free, - contents); - g_warn_if_fail (ret != NULL); - g_variant_ref_sink (ret); + if (sb.st_size > 0) + { + addr = mmap (NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (addr == MAP_FAILED) + { + udisks_warning ("Error mmaping state file %s: %m", path); + addr = NULL; + goto out; + } + } - contents = NULL; /* ownership transferred to the returned GVariant */ + if (addr != NULL) + { + GBytes *bytes = g_bytes_new_with_free_func (addr, sb.st_size, (GDestroyNotify) munmap, addr); + ret = g_variant_new_from_bytes (type, bytes, FALSE); + g_bytes_unref (bytes); + } out: - g_free (contents); + if (fd != -1) + close (fd); g_free (path); return ret; }