Commit 74ea1999 authored by Alexander Larsson's avatar Alexander Larsson

Cache mountinfo lookups

parent 7e9a0310
......@@ -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;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment