Add program to calculate the shortest relative path for symlinks

This commit is contained in:
Lucas De Marchi 2012-01-18 16:01:58 -02:00
parent 434f32ca8d
commit 411d83c41e
3 changed files with 104 additions and 1 deletions

View File

@ -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 $<) $@)

1
tools/.gitignore vendored
View File

@ -7,3 +7,4 @@ modinfo
depmod
kmod
kmod-nolib
shortest-relpath

100
tools/shortest-relpath.c Normal file
View File

@ -0,0 +1,100 @@
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
static void usage(const char *progname)
{
printf("%s <path> <relative-to-path>\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;
}