diff options
author | Alexander Larsson <alexl@redhat.com> | 2009-06-18 10:55:15 +0200 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2009-06-23 15:10:27 +0200 |
commit | 74ea19992c60e0bd2e9f1a9e925b349909f1bdd8 (patch) | |
tree | 1c0e3c73e6de333f1ba24d251c94c4cf029b6b27 /metadata/metatree.c | |
parent | 7e9a03103145fbfdbab2d29767321f5362d7ac31 (diff) | |
download | gvfs-74ea19992c60e0bd2e9f1a9e925b349909f1bdd8.tar.gz |
Cache mountinfo lookups
Diffstat (limited to 'metadata/metatree.c')
-rw-r--r-- | metadata/metatree.c | 270 |
1 files changed, 167 insertions, 103 deletions
diff --git a/metadata/metatree.c b/metadata/metatree.c index dad41d85..744f54e0 100644 --- a/metadata/metatree.c +++ b/metadata/metatree.c @@ -11,6 +11,7 @@ #include <glib.h> #include <glib/gstdio.h> #include <errno.h> +#include <poll.h> #include "crc32.h" #define MAGIC "\xda\x1ameta" @@ -1873,81 +1874,25 @@ struct _MetaLookupCache { }; #ifdef __linux__ -static gboolean -mountinfo_strequal_escaped (const char *s, - const char *escaped) -{ - char c; - while (*s != 0 && *escaped != ' ' && *escaped != 0) - { - if (*escaped == '\\') - { - escaped++; - c = *escaped++ - '0'; - c <<= 3; - c |= *escaped++ - '0'; - c <<= 3; - c |= *escaped++ - '0'; - } - else - c = *escaped++; - - if (c != *s++) - return FALSE; - } - if (*s == 0 && (*escaped == 0 || *escaped == ' ')) - return TRUE; - return FALSE; -} -static char * -mountinfo_unescape (const char *escaped) -{ - char *res, *s; - char c; - gsize len; - - s = strchr (escaped, ' '); - if (s) - len = s - escaped; - else - len = strlen (escaped); - res = malloc (len + 1); - s = res; +typedef struct { + char *mountpoint; + char *root; +} MountinfoEntry; - while (*escaped != 0 && *escaped != ' ') - { - if (*escaped == '\\') - { - escaped++; - c = *escaped++ - '0'; - c <<= 3; - c |= *escaped++ - '0'; - c <<= 3; - c |= *escaped++ - '0'; - } - else - c = *escaped++; - *s++ = c; - } - *s = 0; - return res; -} +static gboolean mountinfo_initialized = FALSE; +static int mountinfo_fd = -1; +static MountinfoEntry *mountinfo_roots = NULL; +G_LOCK_DEFINE_STATIC (mountinfo); /* We want to avoid mmap and stat as these are not ideal operations for a proc file */ static char * -read_contents (char *filename) +read_contents (int fd) { char *data; gsize len; gsize bytes_read; - int fd; - - fd = open (filename, O_RDONLY); - - if (fd == -1) - return NULL; len = 4096; data = g_malloc (len); @@ -1970,7 +1915,6 @@ read_contents (char *filename) if (errno != EINTR) { g_free (data); - close (fd); return NULL; } } @@ -1979,7 +1923,6 @@ read_contents (char *filename) else bytes_read += rc; } - close (fd); /* zero terminate */ if (len - bytes_read < 1) @@ -1988,62 +1931,183 @@ read_contents (char *filename) return (char *)data; } -#endif - static char * -get_extra_prefix_for_mount (const char *mountpoint) +mountinfo_unescape (const char *escaped) { -#ifdef __linux__ - gchar *contents; - char *res; - char *line; - char *line_root; - char *line_mountpoint; + char *res, *s; + char c; + gsize len; - if (mountpoint && - (contents = read_contents ("/proc/self/mountinfo")) != NULL) + s = strchr (escaped, ' '); + if (s) + len = s - escaped; + else + len = strlen (escaped); + res = malloc (len + 1); + s = res; + + while (*escaped != 0 && *escaped != ' ') { - line = contents; - while (line != NULL && *line != 0) + if (*escaped == '\\') { - /* parent id */ - line = strchr (line, ' '); - line_mountpoint = NULL; + escaped++; + c = *escaped++ - '0'; + c <<= 3; + c |= *escaped++ - '0'; + c <<= 3; + c |= *escaped++ - '0'; + } + else + c = *escaped++; + *s++ = c; + } + *s = 0; + return res; +} + +static MountinfoEntry * +parse_mountinfo (const char *contents) +{ + GArray *a; + const char *line; + const char *line_root; + const char *line_mountpoint; + + a = g_array_new (TRUE, TRUE, sizeof (MountinfoEntry)); + + line = contents; + while (line != NULL && *line != 0) + { + /* parent id */ + line = strchr (line, ' '); + line_mountpoint = NULL; + if (line) + { + /* major:minor */ + line = strchr (line+1, ' '); if (line) { - /* major:minor */ + /* root */ line = strchr (line+1, ' '); + line_root = line + 1; if (line) { - /* root */ + /* mountpoint */ line = strchr (line+1, ' '); - line_root = line + 1; - if (line) - { - /* mountpoint */ - line = strchr (line+1, ' '); - line_mountpoint = line + 1; - } + line_mountpoint = line + 1; } } + } - if (line_mountpoint && - mountinfo_strequal_escaped (mountpoint, line_mountpoint)) - { - res = mountinfo_unescape (line_root); - g_free (contents); - return res; - } + if (line_mountpoint && !(line_root[0] == '/' && line_root[1] == ' ')) + { + MountinfoEntry new_entry; - line = strchr (line, '\n'); - if (line) - line++; + new_entry.mountpoint = mountinfo_unescape (line_mountpoint); + new_entry.root = mountinfo_unescape (line_root); + + g_array_append_val (a, new_entry); } - g_free (contents); + line = strchr (line, '\n'); + if (line) + line++; } + return (MountinfoEntry *)g_array_free (a, FALSE); +} + +static void +free_mountinfo (void) +{ + int i; + + if (mountinfo_roots) + { + for (i = 0; mountinfo_roots[i].mountpoint != NULL; i++) + { + g_free (mountinfo_roots[i].mountpoint); + g_free (mountinfo_roots[i].root); + } + g_free (mountinfo_roots); + mountinfo_roots = NULL; + } +} + +static void +update_mountinfo (void) +{ + char *contents; + int res; + gboolean first; + struct pollfd pfd; + + first = FALSE; + if (!mountinfo_initialized) + { + mountinfo_initialized = TRUE; + mountinfo_fd = open ("/proc/self/mountinfo", O_RDONLY); + first = TRUE; + } + + if (mountinfo_fd == -1) + return; + + if (!first) + { + pfd.fd = mountinfo_fd; + pfd.events = POLLIN | POLLOUT | POLLPRI; + pfd.revents = 0; + res = poll (&pfd, 1, 0); + if (res == 0) + return; + } + + free_mountinfo (); + contents = read_contents (mountinfo_fd); + lseek (mountinfo_fd, SEEK_SET, 0); + if (contents) + mountinfo_roots = parse_mountinfo (contents); +} + +static const char * +find_mountinfo_root_for_mountpoint (const char *mountpoint) +{ + char *res; + int i; + + res = NULL; + + G_LOCK (mountinfo); + + update_mountinfo (); + + if (mountinfo_roots) + { + for (i = 0; mountinfo_roots[i].mountpoint != NULL; i++) + { + if (strcmp (mountinfo_roots[i].mountpoint, mountpoint) == 0) + { + res = g_strdup (mountinfo_roots[i].root); + break; + } + } + } + + G_UNLOCK (mountinfo); + + return res; +} + +#endif + + +static char * +get_extra_prefix_for_mount (const char *mountpoint) +{ +#ifdef __linux__ + return find_mountinfo_root_for_mountpoint (mountpoint); #endif return NULL; } |