]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: try absolute target before canonicalize
authorKarel Zak <kzak@redhat.com>
Thu, 24 Mar 2016 10:51:12 +0000 (11:51 +0100)
committerKarel Zak <kzak@redhat.com>
Wed, 13 Apr 2016 10:29:16 +0000 (12:29 +0200)
The path canonicalization is expensive and in many cases unwanted due
to problems with readlink() on unreachable NFS and automounters.

This patch add a possibility to search also by $(CWD)/<path> if the
<path> is relative to reduce number of situation when we convert the
path to the canonical absolute path.

The common use-case:

# cd /some/long/path
# umount ./mountpoint

old version:

15543: libmount:      TAB: [0x560a99a54230]: lookup TARGET: './test'
15543: libmount:    CACHE: [0x560a99a54290]: canonicalize path ./test
15543: libmount:    CACHE: [0x560a99a54290]: add entry [ 1] (path): /mnt/test: ./test
15543: libmount:      TAB: [0x560a99a54230]: lookup canonical TARGET: '/mnt/test'
15543: libmount:      CXT: [0x560a99a54050]: umount fs: /mnt/test

new version:

15597: libmount:      TAB: [0xabf230]: lookup TARGET: './test'
15597: libmount:      TAB: [0xabf230]: lookup absolute TARGET: '/mnt/test'
15597: libmount:      CXT: [0xabf050]: umount fs: /mnt/test

Signed-off-by: Karel Zak <kzak@redhat.com>
include/canonicalize.h
lib/canonicalize.c
libmount/src/tab.c

index 7a18aca090f7c2764d38d3ef9103bc33e3de2dce..0a292fc32cf372f8415e2dd7396fbf93e9f79d5a 100644 (file)
 #define CANONICALIZE_H
 
 #include "c.h" /* for PATH_MAX */
+#include "strutils.h"
 
 extern char *canonicalize_path(const char *path);
 extern char *canonicalize_path_restricted(const char *path);
 extern char *canonicalize_dm_name(const char *ptname);
 
+extern char *absolute_path(const char *path);
+
+static inline int is_relative_path(const char *path)
+{
+       if (!path || *path == '/')
+               return 0;
+       return 1;
+}
+
 #endif /* CANONICALIZE_H */
index 49ac8024661ab9a264644d5321b74a35fda7190f..93782e894075375fbd8e2e111d4be929c6360fa7 100644 (file)
@@ -66,6 +66,47 @@ static int is_dm_devname(char *canonical, char **name)
        return 1;
 }
 
+/*
+ * This function does not cannonicalize the path! It just prepends CWD before a
+ * relative path. If the path is no relative than returns NULL. The path does
+ * not have to exist.
+ */
+char *absolute_path(const char *path)
+{
+       char cwd[PATH_MAX], *res, *p;
+       size_t psz, csz;
+
+       if (!is_relative_path(path)) {
+               errno = EINVAL;
+               return NULL;
+       }
+       if (!getcwd(cwd, sizeof(cwd)))
+               return NULL;
+
+       /* simple clean up */
+       if (startswith(path, "./"))
+               path += 2;
+       else if (strcmp(path, ".") == 0)
+               path = NULL;
+
+       if (!path || !*path)
+               return strdup(cwd);
+
+       csz = strlen(cwd);
+       psz = strlen(path);
+
+       p = res = malloc(csz + 1 + psz + 1);
+       if (!res)
+               return NULL;
+
+       memcpy(p, cwd, csz);
+       p += csz;
+       *p++ = '/';
+       memcpy(p, path, psz + 1);
+
+       return res;
+}
+
 char *canonicalize_path(const char *path)
 {
        char *canonical, *dmname;
@@ -139,7 +180,6 @@ int main(int argc, char **argv)
 
        fprintf(stdout, "orig: %s\n", argv[1]);
        fprintf(stdout, "real: %s\n", canonicalize_path(argv[1]));
-
        exit(EXIT_SUCCESS);
 }
 #endif
index d7a633cba89d42fb16661292536e36d08da6fb0f..a8d835e042401118fb4c0baee0db5122b9b9def7 100644 (file)
@@ -867,6 +867,20 @@ struct libmnt_fs *mnt_table_find_target(struct libmnt_table *tb, const char *pat
                if (mnt_fs_streq_target(fs, path))
                        return fs;
        }
+
+       /* try absolute path */
+       if (is_relative_path(path) && (cn = absolute_path(path))) {
+               DBG(TAB, ul_debugobj(tb, "lookup absolute TARGET: '%s'", cn));
+               mnt_reset_iter(&itr, direction);
+               while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
+                       if (mnt_fs_streq_target(fs, cn)) {
+                               free(cn);
+                               return fs;
+                       }
+               }
+               free(cn);
+       }
+
        if (!tb->cache || !(cn = mnt_resolve_path(path, tb->cache)))
                return NULL;