home *** CD-ROM | disk | FTP | other *** search
- From: dupuy@westend.columbia.edu (Alexander Dupuy)
- Newsgroups: comp.sources.misc
- Subject: v02i073: A filename canonicalizer for BSD
- Message-ID: <7490@ncoast.UUCP>
- Date: 9 Mar 88 23:23:45 GMT
- Approved: allbery@ncoast.UUCP
-
- Comp.sources.misc: Volume 2, Issue 73
- Submitted-By: "Alexander Dupuy" <dupuy@westend.columbia.edu>
- Archive-Name: name
-
- Have your filesystems become such a mess of symbolic links that you don't know
- where a given path really leads? If so, this program will help. It takes a
- pathname and gives you back the true name of the file. It has an option [-a]
- to give you an absolute name (leading '/'), an option [-n] to give you a
- normalized name (all "//", "/./", and "/../" removed, if possible), and even an
- option [-i] which ignores symbolic links (this is pretty useless if you don't
- also specify the normalize option).
-
- The most useful option is the verbose [-v] option, which prints out all
- symbolic links encountered while looking up the name. This helps in figuring
- out how it got from here to there.
-
- Sorry, no man page. If you hadn't guessed, this is BSD-only. However, I was
- able to compile it under HP-UX with "-lBSD" for the getwd() call. How many
- System V's have symlinks anyhow?
-
- @alex
- --
- inet: dupuy@columbia.edu
- uucp: ...!rutgers!columbia!dupuy
-
- : This is a shar archive. Extract with sh, not csh.
- : The rest of this file will extract:
- :
- : name.c
- :
- echo x - name.c
- sed 's/^X//' > name.c << '//go.sysin dd *'
- X/*
- X * name - find a file's real name
- X */
- X
- X#include <stdio.h>
- X#include <errno.h>
- X#include <strings.h>
- X#include <sys/param.h>
- X#include <sys/stat.h>
- X#include <sys/dir.h>
- X
- Xchar usage[] = "Usage: name [-ainv] pathname...\n";
- X
- Xint absolute; /* print absolute pathnames */
- Xint normalize; /* normalize pathnames */
- Xint ignore; /* ignore symbolic links */
- Xint verbose; /* describe each symbolic link */
- X
- Xmain (argc, argv)
- Xchar **argv;
- X{
- X int option;
- X extern int optind;
- X int errors = 0;
- X char realname[MAXPATHLEN + MAXNAMLEN];
- X extern char *name();
- X
- X while ((option = getopt (argc, argv, "ainv")) != EOF)
- X switch (option)
- X {
- X case 'a':
- X absolute += 1;
- X break;
- X
- X case 'i':
- X ignore += 1;
- X break;
- X
- X case 'n':
- X normalize += 1;
- X break;
- X
- X case 'v':
- X verbose += 1;
- X break;
- X
- X default:
- X fputs (usage, stderr);
- X exit (1);
- X }
- X
- X argc -= optind;
- X argv += optind;
- X
- X if (argc == 0) /* have to have a path... */
- X {
- X fputs (usage, stderr);
- X exit (1);
- X }
- X
- X while (argc-- > 0)
- X {
- X if (name (*argv++, realname) == 0)
- X { /* print error returned by name() */
- X fputs (realname, stderr);
- X (void) putc ('\n', stderr);
- X errors++;
- X }
- X else /* print the real name itself */
- X puts (realname);
- X }
- X
- X exit (errors);
- X}
- X
- Xstatic int links; /* how many symbolic links in path */
- X
- Xchar *name (path, truename)
- Xchar *path;
- Xchar *truename;
- X{
- X static char prefix[MAXPATHLEN + MAXNAMLEN + 1];
- X extern char *getwd();
- X
- X if (*path != '/' && absolute) /* get absolute pathname of relative */
- X {
- X if (getwd (prefix) == NULL) /* system five doesn't have this... */
- X {
- X strcpy (truename, prefix); /* contains error message from getwd */
- X return (NULL);
- X }
- X strcat (prefix, "/"); /* add trailing '/' */
- X }
- X else
- X prefix[0] = '\0';
- X
- X links = 0;
- X
- X if (name1 (prefix, path) == 0) /* an error occurred */
- X {
- X strcpy (truename, prefix); /* copy back the error message */
- X return (NULL);
- X }
- X else
- X {
- X strcpy (truename, prefix); /* copy back the real name */
- X return (truename);
- X }
- X}
- X
- X
- X#define rootdir(name) ((name)[0]=='/' && (name)[1]=='\0')
- X
- X#define dotdir(name) \
- X((name)[0]=='.' && ((name)[1]=='\0' || ((name)[1]=='.' && (name)[2]=='\0')))
- X
- X#define dotdotdir(name) \
- X((name)[0]=='.' && (name)[1]=='.' && (name)[2]=='\0')
- X
- X
- X/*
- X * Recursively add suffix to prefix, canonicalizing as we go...
- X */
- X
- Xstatic name1 (prefix, suffix)
- Xchar *prefix;
- Xregister char *suffix;
- X{
- X extern char *sys_errlist[];
- X char link[MAXPATHLEN];
- X struct stat status;
- X register char *splice;
- X register char *cut;
- X register int cc;
- X int result;
- X
- X splice = prefix + strlen (prefix);
- X
- X do
- X {
- X if (!normalize)
- X {
- X if (*suffix == '/') /* skip one leading "/" */
- X {
- X *splice++ = '/';
- X *splice = '\0';
- X suffix++;
- X }
- X }
- X else
- X {
- X if (*suffix == '/')
- X {
- X while (*suffix == '/')
- X suffix++; /* treat "//" as "/" */
- X
- X if (splice == prefix ||
- X (*suffix != '\0' && splice[-1] != '/'))
- X {
- X *splice++ = '/';
- X *splice = '\0';
- X }
- X }
- X
- X if (*suffix == '.')
- X {
- X if (suffix[1] == '\0')
- X { /* treat "." as "." (not "") */
- X if (splice == prefix)
- X {
- X *splice++ = '.';
- X *splice = '\0';
- X } /* treat "x/." as "x" */
- X else if (!rootdir (prefix))
- X *--splice = '\0';
- X return (1); /* treat "/." as "/" */
- X }
- X
- X if (suffix[1] == '/')
- X {
- X suffix += 2; /* treat "/./" as "/" */
- X continue;
- X }
- X
- X if (suffix[1] == '.')
- X {
- X if (suffix[2] == '\0')
- X { /* treat ".." as ".." */
- X if (prefix == splice)
- X strcpy (prefix, "..");
- X
- X else if (!rootdir (prefix))
- X {
- X *--splice = '\0';
- X
- X if ((splice = rindex (prefix, '/')) == 0)
- X {
- X if (dotdotdir (prefix))
- X {
- X strcat (prefix, "/..");
- X return (1);
- X }
- X else
- X splice = prefix;
- X }
- X else if (dotdotdir (splice + 1))
- X {
- X strcat (splice, "/..");
- X return (1);
- X }
- X
- X *splice= '\0';
- X }
- X
- X return (1);
- X }
- X
- X if (suffix[2] == '/')
- X {
- X if (splice == prefix)
- X {
- X strcpy (prefix, "..");
- X splice += 2;
- X suffix += 2;
- X }
- X
- X else if (!rootdir (prefix))
- X { /* don't back up "/" prefix */
- X *--splice = '\0';
- X
- X if ((splice = rindex (prefix, '/')) == 0)
- X {
- X if (dotdotdir (prefix))
- X {
- X strcat (prefix, "/..");
- X splice = prefix + strlen (prefix);
- X suffix += 2;
- X }
- X else
- X {
- X splice = prefix;
- X *splice = '\0';
- X suffix += 3;
- X }
- X }
- X else
- X {
- X if (dotdotdir (splice))
- X {
- X strcat (splice, "..");
- X splice += strlen (splice);
- X suffix += 2;
- X }
- X else
- X {
- X *splice = '\0';
- X suffix += 2;
- X }
- X }
- X }
- X else
- X suffix += 3;
- X
- X continue;
- X }
- X }
- X }
- X }
- X
- X if (!*suffix)
- X break; /* empty suffix string */
- X
- X if ((cut = index (suffix, '/')) == 0)
- X {
- X cc = strlen (suffix);
- X cut = suffix + cc;
- X }
- X else
- X cc = cut - suffix;
- X
- X if (cc >= MAXNAMLEN)
- X {
- X (void) sprintf (prefix, "%s: %s",
- X suffix, sys_errlist[ENAMETOOLONG]);
- X return (0);
- X }
- X
- X if (cc == 0) /* suffix has leading '/' */
- X {
- X cut++;
- X cc = 1; /* so force it to be copied */
- X }
- X
- X strncpy (splice, suffix, cc);
- X splice[cc] = '\0';
- X
- X if (!ignore)
- X {
- X if ((result = lstat (prefix, &status)) == -1)
- X {
- X (void) sprintf (splice + cc, ": %s", sys_errlist[errno]);
- X return (0);
- X }
- X
- X if ((status.st_mode & S_IFMT) == S_IFLNK)
- X {
- X if ((result = readlink (prefix, link, MAXPATHLEN)) == -1)
- X {
- X (void) sprintf (splice + cc, ": %s", sys_errlist[errno]);
- X return (0);
- X }
- X link[result] = '\0';
- X
- X if (links++ == MAXSYMLINKS &&
- X (result = stat (prefix, &status)) == -1)
- X {
- X (void) sprintf (splice + cc, ": %s", sys_errlist[errno]);
- X return (0);
- X }
- X
- X if (verbose)
- X {
- X (void) printf ("%s -> %s\n", prefix, link);
- X }
- X
- X if (*link == '/')
- X *prefix = '\0'; /* chop prefix if link is absolute */
- X else
- X *splice = '\0'; /* chop just the link name */
- X
- X if (name1 (prefix, link) == 0)
- X return (0); /* recurse */
- X
- X splice = prefix + strlen (prefix);
- X }
- X }
- X else if ((result = stat (prefix, &status)) == -1)
- X {
- X (void) sprintf (splice + cc, ": %s", sys_errlist[errno]);
- X return (0);
- X }
- X
- X suffix = cut; /* advance suffix past cut */
- X
- X splice += strlen (splice); /* advance splice to end of prefix */
- X }
- X while (*suffix);
- X
- X return (1);
- X}
- //go.sysin dd *
- exit
-
- inet: dupuy@columbia.edu
- uucp: ...!rutgers!columbia!dupuy
-