Logo Search packages:      
Sourcecode: ncftp version File versions

u_pathcat.c

/* u_pathcat.c
 *
 * Copyright (c) 2002 Mike Gleason, NcFTP Software.
 * All rights reserved.
 *
 */

#include "syshdrs.h"
#ifdef PRAGMA_HDRSTOP
#     pragma hdrstop
#endif


/* This simplifies a pathname, by converting it to the
 * equivalent of "cd $dir ; dir=`pwd`".  In other words,
 * if $PWD==/usr/spool/uucp, and you had a path like
 * "$PWD/../tmp////./../xx/", it would be converted to
 * "/usr/spool/xx".
 */

int
IsValidUNCPath(const char *const src)
{
      const char *a, *b;
      int c;
      int n;

      /* We may have a DOS path.  */
      if ((src[0] == '\\') && (src[1] == '\\') && (isalpha((int) src[2]))) {
            for (a = src + 3; ; ) {
                  c = *a++;
                  if (c == '\\')
                        break;
                  if ((! isalnum(c)) && (c != '_'))
                        return (0);
            }
            b = a;
            c = *b++;
            if (! (isalpha(c)))
                  return (0); /* share does not start with letter */
            for ( ; ; ) {
                  c = *b++;
                  if ((c == '\\') || (c == '\0'))
                        break;
                  if ((! isalnum(c)) && (c != '_'))
                        return (0);
            }
            n = (int) (b - src);
            return (n);
      }
      return (0);
}     /* IsValidUNCPath */



void
CompressPath(char *const dst, const char *const src, const size_t dsize, int dosCompat)
{
      int c;
      const char *s, *start, *dotp;
      char *d, *lim, *dstart;
      char *a, *b;
      char slash = (char) '/';
      size_t n;

#define isslash(c) ((c == '/') || (c == '\\'))
      s = start = src;
      d = dstart = dst;
      lim = d + dsize - 1;    /* leave room for nul byte. */

      if (dsize == 0)
            return;
      *dst = '\0';

      if ((s[0] == '\0') || (dsize < 4)) {
            return;
      } else if (dosCompat != 0) {
            if (src[0] == '\\') {
                  /* We have a DOS path.  */
                  slash = (char) '\\';
                  n = (size_t) IsValidUNCPath(src);
                  if (n != 0) {
                        if (dsize < n)
                              return;
                        --n;
                        memcpy(d, src, n);
                        d += n;
                        *d = '\0';
                        dstart = d;
                        s += n;
                        start = s;
                        /* unc = 1; */
                  }
            } else if ((isalpha((int) src[0])) && (src[1] == ':')) {
                  /* We may have a DOS driveletter+path.  */
                  *d++ = src[0];
                  *d++ = ':';
                  start += 2;
                  dstart += 2;
                  s += 2;
                  if (! isslash(src[2])) {
                        slash = (char) '\\';
                        *d++ = '\\';
                  } else {
                        slash = src[2];
                        /* add it below *d++ = src[2]; */
                  }
            }
      }

      for (;;) {
            c = *s;
            if (c == '.') {
                  if (((s == start) || isslash(s[-1])) && (isslash(s[1]) || (s[1] == '\0'))) {
                        /* Don't copy "./" */
                        if (isslash(s[1]))
                              ++s;
                        ++s;
                  } else if ((dosCompat != 0) && (s[1] == '.')) {
                        if (d < lim)
                              *d++ = *s++;
                        if (d < lim)
                              *d++ = *s++;
                        if (*s == '.') {
                              dotp = s;
                              while (*dotp == '.')
                                    dotp++;
                              if ((*dotp == '\0') || (isslash(*dotp))) {
                                    /* On DOS, "..." == "..",
                                     * "...." == "..", etc,
                                     * so skip the extra dots.
                                     */
                                    s = dotp;
                              }
                        }
                  } else if (d < lim) {
                        *d++ = *s++;
                  } else {
                        ++s;
                  }
            } else if (isslash(c)) {
                  /* Don't copy multiple slashes. */
                  if (d < lim)
                        *d++ = slash;
                  ++s;
                  for (;;) {
                        c = *s;
                        if (isslash(c)) {
                              /* Don't copy multiple slashes. */
                              ++s;
                        } else if (c == '.') {
                              c = s[1];
                              if (isslash(c)) {
                                    /* Skip "./" */
                                    s += 2;
                              } else if (c == '\0') {
                                    /* Skip "./" */
                                    s += 1;
                              } else {
                                    break;
                              }
                        } else {
                              break;
                        }
                  }
            } else if (c == '\0') {
                  /* Remove trailing slash. */
                  if (isslash(d[-1]) && (d > (dstart + 1)))
                        d[-1] = '\0';
                  *d = '\0';
                  break;
            } else if (d < lim) {
                  *d++ = *s++;
            } else {
                  ++s;
            }
      }
      a = dstart;

      /* fprintf(stderr, "<%s>\n", dst); */
      /* Go through and remove .. in the path when we know what the
       * parent directory is.  After we get done with this, the only
       * .. nodes in the path will be at the front.
       */
      while (*a != '\0') {
            b = a;
            for (;;) {
                  /* Get the next node in the path. */
                  if (*a == '\0')
                        return;
                  if (isslash(*a)) {
                        ++a;
                        break;
                  }
                  ++a;
            }
            if ((b[0] == '.') && (b[1] == '.')) {
                  if (isslash(b[2])) {
                        /* We don't know what the parent of this
                         * node would be.
                         */
                        continue;
                  }
            }
            if ((a[0] == '.') && (a[1] == '.')) {
                  if (isslash(a[2])) {
                        /* Remove the .. node and the one before it. */
                        if ((b == dstart) && (isslash(*dstart)))
                              (void) memmove(b + 1, a + 3, strlen(a + 3) + 1);
                        else
                              (void) memmove(b, a + 3, strlen(a + 3) + 1);
                        a = dstart; /* Start over. */
                  } else if (a[2] == '\0') {
                        /* Remove a trailing .. like:  /aaa/bbb/.. */
                        if (b == dstart) {
                              dstart[0] = (char) ((isslash(start[0])) ? slash : '.');
                              dstart[1] = '\0';
                        } else if ((b <= dstart + 1) && isslash(*dstart)) {
                              dstart[1] = '\0';
                        } else {
                              b[-1] = '\0';
                        }
                        a = dstart; /* Start over. */
                  } else {
                        /* continue processing this node.
                         * It is probably some bogus path,
                         * like ".../", "..foo/", etc.
                         */
                  }
            }
      }
#undef isslash
}     /* CompressPath */



void
PathCat(char *const dst, const size_t dsize, const char *const cwd, const char *const src, int dosCompat)
{
      char *cp;
      char tmp[512];

      if (dosCompat != 0) {
            if ((isalpha((int) cwd[0])) && (cwd[1] == ':')) {
                  if ((isalpha((int) src[0])) && (src[1] == ':')) {
                        /* A new fully-qualified DOS drive+path was requested. */
                        CompressPath(dst, src, dsize, dosCompat);
                        return;
                  } else if (IsValidUNCPath(src)) {
                        CompressPath(dst, src, dsize, dosCompat);
                        return;
                  } else if (src[0] == '\\') {
                        /* A new fully-qualified DOS path on the same
                         * drive letter was requested.
                         */
                        dst[0] = cwd[0];
                        dst[1] = ':';
                        CompressPath(dst + 2, src, dsize - 2, dosCompat);
                        return;
                  }
            } else if (IsValidUNCPath(src)) {
                  /* A new fully-qualified DOS UNC path was requested.
                   * (but no drive letter was present on CWD?)
                   */
                  CompressPath(dst, src, dsize, dosCompat);
                  return;
            } else if ((src[0] == '\\') || ((isalpha((int) src[0])) && (src[1] == ':'))) {
                  /* A new fully-qualified DOS path was requested.
                   * (but no drive letter was present on CWD?)
                   */
                  CompressPath(dst, src, dsize, dosCompat);
                  return;
            }
      }
      if (src[0] == '/') {
            /* A new fully-qualified UNIX path was requested. */
            CompressPath(dst, src, dsize, dosCompat);
            return;
      }

      cp = Strnpcpy(tmp, cwd, sizeof(tmp) - 1);
      if (dosCompat) {
            if (dst[0] == '\\')
                  *cp++ = '\\';
            else if ((dst[1] != ':') || (dst[2] == '/'))
                  *cp++ = '/';
            else
                  *cp++ = '\\';
      } else {
            *cp++ = '/';
      }
      *cp = '\0';
      (void) Strnpcat(cp, src, sizeof(tmp) - (cp - tmp));
      CompressPath(dst, tmp, dsize, dosCompat);
}     /* PathCat */



int
DPathCat(char **const dst0, const char *const cwd, const char *const src, int dosCompat)
{
      char *cp, *dst, *tmp;
      size_t dsize;

      dsize = strlen(cwd) +
            /* pathdelim */ 1 +
            strlen(src) +
            /* NUL byte */ 1 +
            /* spare */ 10;

      dst = calloc(dsize, 1);
      *dst0 = dst;
      if (dst == NULL)
            return (-1);

      if (dosCompat != 0) {
            if ((isalpha((int) cwd[0])) && (cwd[1] == ':')) {
                  if ((isalpha((int) src[0])) && (src[1] == ':')) {
                        /* A new fully-qualified DOS drive+path was requested. */
                        CompressPath(dst, src, dsize, dosCompat);
                        return (0);
                  } else if (IsValidUNCPath(src)) {
                        CompressPath(dst, src, dsize, dosCompat);
                        return (0);
                  } else if (src[0] == '\\') {
                        /* A new fully-qualified DOS path on the same
                         * drive letter was requested.
                         */
                        dst[0] = cwd[0];
                        dst[1] = ':';
                        CompressPath(dst + 2, src, dsize - 2, dosCompat);
                        return (0);
                  }
            } else if (IsValidUNCPath(src)) {
                  /* A new fully-qualified DOS UNC path was requested.
                   * (but no drive letter was present on CWD?)
                   */
                  CompressPath(dst, src, dsize, dosCompat);
                  return (0);
            } else if ((src[0] == '\\') || ((isalpha((int) src[0])) && (src[1] == ':'))) {
                  /* A new fully-qualified DOS path was requested.
                   * (but no drive letter was present on CWD?)
                   */
                  CompressPath(dst, src, dsize, dosCompat);
                  return (0);
            }
      }
      if (src[0] == '/') {
            /* A new fully-qualified UNIX path was requested. */
            CompressPath(dst, src, dsize, dosCompat);
            return (0);
      }

      tmp = calloc(dsize, 1);
      if (tmp == NULL) {
            free(dst);
            *dst0 = NULL;
            return (-1);
      }

      cp = Strnpcpy(tmp, cwd, dsize - 1);
      if (dosCompat) {
            if (dst[0] == '\\')
                  *cp++ = '\\';
            else if ((dst[1] != ':') || (dst[2] == '/'))
                  *cp++ = '/';
            else
                  *cp++ = '\\';
      } else {
            *cp++ = '/';
      }
      *cp = '\0';
      (void) Strnpcat(cp, src, dsize - (cp - tmp));
      CompressPath(dst, tmp, dsize, dosCompat);
      free(tmp);
      return (0);
}     /* DPathCat */

Generated by  Doxygen 1.6.0   Back to index