Logo Search packages:      
Sourcecode: ksh version File versions  Download package

pathcanon.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*          Copyright (c) 1985-2007 AT&T Intellectual Property          *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                    by AT&T Intellectual Property                     *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                  David Korn <dgk@research.att.com>                   *
*                   Phong Vo <kpv@research.att.com>                    *
*                                                                      *
***********************************************************************/
#pragma prototyped
/*
 * Glenn Fowler
 * AT&T Research
 *
 * in-place path name canonicalization -- preserves the logical view
 * pointer to trailing 0 in path returned
 *
 *    remove redundant .'s and /'s
 *    move ..'s to the front
 *    /.. preserved (for pdu and newcastle hacks)
 *    FS_3D handles ...
 *    if (flags&PATH_PHYSICAL) then symlinks resolved at each component
 *    if (flags&PATH_DOTDOT) then each .. checked for access
 *    if (flags&PATH_EXISTS) then path must exist at each component
 *    if (flags&PATH_VERIFIED(n)) then first n chars of path exist
 * 
 * longer pathname possible if (flags&PATH_PHYSICAL) or FS_3D ... involved
 * 0 returned on error and if (flags&(PATH_DOTDOT|PATH_EXISTS)) then path
 * will contain the components following the failure point
 */

#include <ast.h>
#include <ls.h>
#include <fs3d.h>
#include <error.h>

char*
pathcanon(char* path, int flags)
{
      register char*    p;
      register char*    r;
      register char*    s;
      register char*    t;
      register int      dots;
      char*       phys;
      char*       v;
      int         loop;
      int         oerrno;
#if defined(FS_3D)
      long        visits = 0;
#endif

      oerrno = errno;
      dots = loop = 0;
      phys = path;
      v = path + ((flags >> 5) & 01777);
      if (*path == '/' && *(path + 1) == '/' && *astconf("PATH_LEADING_SLASHES", NiL, NiL) == '1')
            do path++; while (*path == '/' && *(path + 1) == '/');
      p = r = s = t = path;
      for (;;) switch (*t++ = *s++)
      {
      case '.':
            dots++;
            break;
      case 0:
            s--;
            /*FALLTHROUGH*/
      case '/':
            while (*s == '/') s++;
            switch (dots)
            {
            case 1:
                  t -= 2;
                  break;
            case 2:
                  if ((flags & (PATH_DOTDOT|PATH_EXISTS)) == PATH_DOTDOT && (t - 2) >= v)
                  {
                        struct stat st;

                        *(t - 2) = 0;
                        if (stat(phys, &st))
                        {
                              strcpy(path, s);
                              return 0;
                        }
                        *(t - 2) = '.';
                  }
#if PRESERVE_TRAILING_SLASH
                  if (t - 5 < r) r = t;
#else
                  if (t - 5 < r)
                  {
                        if (t - 4 == r) t = r + 1;
                        else r = t;
                  }
#endif
                  else for (t -= 5; t > r && *(t - 1) != '/'; t--);
                  break;
            case 3:
#if defined(FS_3D)
                  {
                        char*       x;
                        char*       o;
                        int         c;

                        o = t;
                        if ((t -= 5) <= path) t = path + 1;
                        c = *t;
                        *t = 0;
                        if (x = pathnext(phys, s - (*s != 0), &visits))
                        {
                              r = path;
                              if (t == r + 1) x = r;
                              v = s = t = x;
                        }
                        else
                        {
                              *t = c;
                              t = o;
                        }
                  }
#else
                  r = t;
#endif
                  break;
            default:
                  if ((flags & PATH_PHYSICAL) && loop < 32 && (t - 1) > path)
                  {
                        int   c;
                        char  buf[PATH_MAX];

                        c = *(t - 1);
                        *(t - 1) = 0;
                        dots = pathgetlink(phys, buf, sizeof(buf));
                        *(t - 1) = c;
                        if (dots > 0)
                        {
                              loop++;
                              strcpy(buf + dots, s - (*s != 0));
                              if (*buf == '/') p = r = path;
                              v = s = t = p;
                              strcpy(p, buf);
                        }
                        else if (dots < 0 && errno == ENOENT)
                        {
                              if (flags & PATH_EXISTS)
                              {
                                    strcpy(path, s);
                                    return 0;
                              }
                              flags &= ~(PATH_PHYSICAL|PATH_DOTDOT);
                        }
                        dots = 4;
                  }
                  break;
            }
            if (dots >= 4 && (flags & PATH_EXISTS) && (t - 1) >= v && (t > path + 1 || t > path && *(t - 1) && *(t - 1) != '/'))
            {
                  struct stat st;

                  *(t - 1) = 0;
                  if (stat(phys, &st))
                  {
                        strcpy(path, s);
                        return 0;
                  }
                  v = t;
                  if (*s) *(t - 1) = '/';
            }
            if (!*s)
            {
                  if (t > path && !*(t - 1)) t--;
                  if (t == path) *t++ = '.';
#if DONT_PRESERVE_TRAILING_SLASH
                  else if (t > path + 1 && *(t - 1) == '/') t--;
#else
                  else if ((s <= path || *(s - 1) != '/') && t > path + 1 && *(t - 1) == '/') t--;
#endif
                  *t = 0;
                  errno = oerrno;
                  return t;
            }
            dots = 0;
            p = t;
            break;
      default:
            dots = 4;
            break;
      }
}

Generated by  Doxygen 1.6.0   Back to index