From 411d83c41eef6c001eda6a33ad57342ad9e19a58 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Wed, 18 Jan 2012 16:01:58 -0200 Subject: [PATCH] Add program to calculate the shortest relative path for symlinks --- Makefile.am | 4 +- tools/.gitignore | 1 + tools/shortest-relpath.c | 100 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 tools/shortest-relpath.c diff --git a/Makefile.am b/Makefile.am index 22ef9ec..6eec0d8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -124,13 +124,15 @@ tools_kmod_CFLAGS = $(AM_CFLAGS) tools_kmod_LDADD = libkmod/libkmod-util.la \ libkmod/libkmod.la -noinst_PROGRAMS = tools/kmod-nolib +noinst_PROGRAMS = tools/kmod-nolib scripts/shortest_relpath tools_kmod_nolib_SOURCES = $(tools_kmod_SOURCES) tools_kmod_nolib_CPPFLAGS = $(tools_kmod_CPPFLAGS) tools_kmod_nolib_CFLAGS = $(tools_kmod_CFLAGS) tools_kmod_nolib_LDADD = libkmod/libkmod-util.la \ libkmod/libkmod-private.la +scripts_shortest_relpath_SOURCES = scripts/shortest_relpath.c + ${noinst_SCRIPTS}: tools/kmod-nolib $(AM_V_GEN) ($(RM) $@; \ $(LN_S) $(notdir $<) $@) diff --git a/tools/.gitignore b/tools/.gitignore index 041d7b2..a3a5795 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -7,3 +7,4 @@ modinfo depmod kmod kmod-nolib +shortest-relpath diff --git a/tools/shortest-relpath.c b/tools/shortest-relpath.c new file mode 100644 index 0000000..5c960bb --- /dev/null +++ b/tools/shortest-relpath.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include + +static void usage(const char *progname) +{ + printf("%s \n", progname); +} + +/* + * path must be absolute path, as the result of calling realpath() + */ +static void split_path(const char *path, char d[PATH_MAX], size_t *dlen, + char n[NAME_MAX], size_t *nlen) +{ + size_t dirnamelen, namelen; + char *p; + + p = strrchr(path, '/'); /* p is never NULL since path is abs */ + dirnamelen = p - path; + if (dirnamelen > 0) + memcpy(d, path, dirnamelen); + d[dirnamelen] = '\0'; + + namelen = strlen(p + 1); + if (namelen > 0) + memcpy(n, p + 1, namelen + 1); + + if (dlen) + *dlen = dirnamelen; + if (nlen) + *nlen = namelen; +} + +int main(int argc, char *argv[]) +{ + size_t sympathlen, namelen, pathlen, i, j; + char name[NAME_MAX], path[PATH_MAX]; + char sympath[PATH_MAX]; + char buf[PATH_MAX]; + char *p; + + if (argc < 3) { + usage(basename(argv[0])); + return EXIT_FAILURE; + } + + p = realpath(argv[1], buf); + if (p == NULL) { + fprintf(stderr, "could not get realpath of %s: %m\n", argv[1]); + return EXIT_FAILURE; + } + split_path(buf, path, &pathlen, name, &namelen); + + p = realpath(argv[2], sympath); + if (p == NULL) { + fprintf(stderr, "could not get realpath of %s: %m\n", argv[2]); + return EXIT_FAILURE; + } + sympathlen = strlen(sympath); + + for (i = 1; i < sympathlen && i < pathlen; i++) { + if (sympath[i] == path[i]) + continue; + break; + } + + if (i < sympathlen) { + while (sympath[i - 1] != '/') + i--; + } + + p = &path[i]; + + j = 0; + if (i < sympathlen) { + memcpy(buf + j, "../", 3); + j += 3; + } + + for (; i < sympathlen; i++) { + if (sympath[i] != '/') + continue; + + memcpy(buf + j, "../", 3); + j += 3; + } + + if (p != path + pathlen) { + memcpy(buf + j, p, path + pathlen - p); + j += path + pathlen - p;; + buf[j++] = '/'; + } + memcpy(buf + j, name, namelen + 1); + + printf("%s\n", buf); + return 0; +} -- 2.39.2