1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1985-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* Glenn Fowler <gsf@research.att.com> *
1N/A* David Korn <dgk@research.att.com> *
1N/A* Phong Vo <kpv@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#pragma prototyped
1N/A/*
1N/A * Glenn Fowler
1N/A * AT&T Research
1N/A *
1N/A * in-place path name canonicalization -- preserves the logical view
1N/A * pointer to trailing 0 in path returned
1N/A *
1N/A * remove redundant .'s and /'s
1N/A * move ..'s to the front
1N/A * /.. preserved (for pdu and newcastle hacks)
1N/A * FS_3D handles ...
1N/A * if (flags&PATH_PHYSICAL) then symlinks resolved at each component
1N/A * if (flags&PATH_DOTDOT) then each .. checked for access
1N/A * if (flags&PATH_EXISTS) then path must exist at each component
1N/A * if (flags&PATH_VERIFIED(n)) then first n chars of path exist
1N/A *
1N/A * longer pathname possible if (flags&PATH_PHYSICAL) or FS_3D ... involved
1N/A * 0 returned on error and if (flags&(PATH_DOTDOT|PATH_EXISTS)) then path
1N/A * will contain the components following the failure point
1N/A */
1N/A
1N/A#define _AST_API_H 1
1N/A
1N/A#include <ast.h>
1N/A#include <ls.h>
1N/A#include <fs3d.h>
1N/A#include <error.h>
1N/A
1N/Achar*
1N/Apathcanon(char* path, int flags)
1N/A{
1N/A return pathcanon_20100601(path, PATH_MAX, flags);
1N/A}
1N/A
1N/A#undef _AST_API_H
1N/A
1N/A#include <ast_api.h>
1N/A
1N/Achar*
1N/Apathcanon_20100601(char* path, size_t size, int flags)
1N/A{
1N/A register char* p;
1N/A register char* r;
1N/A register char* s;
1N/A register char* t;
1N/A register int dots;
1N/A char* phys;
1N/A char* v;
1N/A int loop;
1N/A int oerrno;
1N/A#if defined(FS_3D)
1N/A long visits = 0;
1N/A#endif
1N/A
1N/A oerrno = errno;
1N/A dots = loop = 0;
1N/A phys = path;
1N/A v = path + ((flags >> 5) & 01777);
1N/A if (!size)
1N/A size = strlen(path) + 1;
1N/A if (*path == '/')
1N/A {
1N/A if (*(path + 1) == '/' && *astconf("PATH_LEADING_SLASHES", NiL, NiL) == '1')
1N/A do path++; while (*path == '/' && *(path + 1) == '/');
1N/A if (!*(path + 1))
1N/A return path + 1;
1N/A }
1N/A p = r = s = t = path;
1N/A for (;;)
1N/A switch (*t++ = *s++)
1N/A {
1N/A case '.':
1N/A dots++;
1N/A break;
1N/A case 0:
1N/A s--;
1N/A /*FALLTHROUGH*/
1N/A case '/':
1N/A while (*s == '/') s++;
1N/A switch (dots)
1N/A {
1N/A case 1:
1N/A t -= 2;
1N/A break;
1N/A case 2:
1N/A if ((flags & (PATH_DOTDOT|PATH_EXISTS)) == PATH_DOTDOT && (t - 2) >= v)
1N/A {
1N/A struct stat st;
1N/A
1N/A *(t - 2) = 0;
1N/A if (stat(phys, &st))
1N/A {
1N/A strcpy(path, s);
1N/A return 0;
1N/A }
1N/A *(t - 2) = '.';
1N/A }
1N/A#if PRESERVE_TRAILING_SLASH
1N/A if (t - 5 < r) r = t;
1N/A#else
1N/A if (t - 5 < r)
1N/A {
1N/A if (t - 4 == r) t = r + 1;
1N/A else r = t;
1N/A }
1N/A#endif
1N/A else for (t -= 5; t > r && *(t - 1) != '/'; t--);
1N/A break;
1N/A case 3:
1N/A#if defined(FS_3D)
1N/A {
1N/A char* x;
1N/A char* o;
1N/A int c;
1N/A
1N/A o = t;
1N/A if ((t -= 5) <= path) t = path + 1;
1N/A c = *t;
1N/A *t = 0;
1N/A if (x = pathnext(phys, s - (*s != 0), &visits))
1N/A {
1N/A r = path;
1N/A if (t == r + 1) x = r;
1N/A v = s = t = x;
1N/A }
1N/A else
1N/A {
1N/A *t = c;
1N/A t = o;
1N/A }
1N/A }
1N/A#else
1N/A r = t;
1N/A#endif
1N/A break;
1N/A default:
1N/A if ((flags & PATH_PHYSICAL) && loop < 32 && (t - 1) > path)
1N/A {
1N/A int c;
1N/A char buf[PATH_MAX];
1N/A
1N/A c = *(t - 1);
1N/A *(t - 1) = 0;
1N/A dots = pathgetlink(phys, buf, sizeof(buf));
1N/A *(t - 1) = c;
1N/A if (dots > 0)
1N/A {
1N/A loop++;
1N/A strcpy(buf + dots, s - (*s != 0));
1N/A if (*buf == '/') p = r = path;
1N/A v = s = t = p;
1N/A strcpy(p, buf);
1N/A }
1N/A else if (dots < 0 && errno == ENOENT)
1N/A {
1N/A if (flags & PATH_EXISTS)
1N/A {
1N/A strcpy(path, s);
1N/A return 0;
1N/A }
1N/A flags &= ~(PATH_PHYSICAL|PATH_DOTDOT);
1N/A }
1N/A dots = 4;
1N/A }
1N/A break;
1N/A }
1N/A if (dots >= 4 && (flags & PATH_EXISTS) && (t - 1) >= v && (t > path + 1 || t > path && *(t - 1) && *(t - 1) != '/'))
1N/A {
1N/A struct stat st;
1N/A
1N/A *(t - 1) = 0;
1N/A if (stat(phys, &st))
1N/A {
1N/A strcpy(path, s);
1N/A return 0;
1N/A }
1N/A v = t;
1N/A if (*s) *(t - 1) = '/';
1N/A }
1N/A if (!*s)
1N/A {
1N/A if (t > path && !*(t - 1)) t--;
1N/A if (t == path) *t++ = '.';
1N/A#if DONT_PRESERVE_TRAILING_SLASH
1N/A else if (t > path + 1 && *(t - 1) == '/') t--;
1N/A#else
1N/A else if ((s <= path || *(s - 1) != '/') && t > path + 1 && *(t - 1) == '/') t--;
1N/A#endif
1N/A *t = 0;
1N/A errno = oerrno;
1N/A return t;
1N/A }
1N/A dots = 0;
1N/A p = t;
1N/A break;
1N/A default:
1N/A dots = 4;
1N/A break;
1N/A }
1N/A}