home *** CD-ROM | disk | FTP | other *** search
/ ftp.ncftp.com / ftp.ncftp.com.zip / ftp.ncftp.com / ncftp / older_versions / ncftp-3.2.2-src.tar.bz2 / ncftp-3.2.2-src.tar / ncftp-3.2.2 / libncftp / u_pathcat.c < prev    next >
C/C++ Source or Header  |  2006-07-27  |  8KB  |  378 lines

  1. /* u_pathcat.c
  2.  *
  3.  * Copyright (c) 1996-2005 Mike Gleason, NcFTP Software.
  4.  * All rights reserved.
  5.  *
  6.  */
  7.  
  8. #include "syshdrs.h"
  9. #ifdef PRAGMA_HDRSTOP
  10. #    pragma hdrstop
  11. #endif
  12.  
  13.  
  14. /* This simplifies a pathname, by converting it to the
  15.  * equivalent of "cd $dir ; dir=`pwd`".  In other words,
  16.  * if $PWD==/usr/spool/uucp, and you had a path like
  17.  * "$PWD/../tmp////./../xx/", it would be converted to
  18.  * "/usr/spool/xx".
  19.  */
  20.  
  21. int
  22. IsValidUNCPath(const char *const src)
  23. {
  24.     const char *a, *b;
  25.     int c;
  26.     int n;
  27.  
  28.     /* We may have a DOS path.  */
  29.     if ((src[0] == '\\') && (src[1] == '\\') && (isalpha((int) src[2]))) {
  30.         for (a = src + 3; ; ) {
  31.             c = *a++;
  32.             if (c == '\\')
  33.                 break;
  34.             if ((! isalnum(c)) && (c != '_'))
  35.                 return (0);
  36.         }
  37.         b = a;
  38.         c = *b++;
  39.         if (! (isalpha(c)))
  40.             return (0);    /* share does not start with letter */
  41.         for ( ; ; ) {
  42.             c = *b++;
  43.             if ((c == '\\') || (c == '\0'))
  44.                 break;
  45.             if ((! isalnum(c)) && (c != '_'))
  46.                 return (0);
  47.         }
  48.         n = (int) (b - src);
  49.         return (n);
  50.     }
  51.     return (0);
  52. }    /* IsValidUNCPath */
  53.  
  54.  
  55.  
  56. void
  57. CompressPath(char *const dst, const char *const src, const size_t dsize, int dosCompat)
  58. {
  59.     int c;
  60.     const char *s, *start, *dotp;
  61.     char *d, *lim, *dstart;
  62.     char *a, *b;
  63.     char slash = (char) '/';
  64.     size_t n;
  65.  
  66. #define isslash(c) ((c == '/') || (c == '\\'))
  67.     s = start = src;
  68.     d = dstart = dst;
  69.     lim = d + dsize - 1;    /* leave room for nul byte. */
  70.  
  71.     if (dsize == 0)
  72.         return;
  73.     *dst = '\0';
  74.  
  75.     if ((s[0] == '\0') || (dsize < 4)) {
  76.         return;
  77.     } else if (dosCompat != 0) {
  78.         if (src[0] == '\\') {
  79.             /* We have a DOS path.  */
  80.             slash = (char) '\\';
  81.             n = (size_t) IsValidUNCPath(src);
  82.             if (n != 0) {
  83.                 if (dsize < n)
  84.                     return;
  85.                 --n;
  86.                 memcpy(d, src, n);
  87.                 d += n;
  88.                 *d = '\0';
  89.                 dstart = d;
  90.                 s += n;
  91.                 start = s;
  92.                 /* unc = 1; */
  93.             }
  94.         } else if ((isalpha((int) src[0])) && (src[1] == ':')) {
  95.             /* We may have a DOS driveletter+path.  */
  96.             *d++ = src[0];
  97.             *d++ = ':';
  98.             start += 2;
  99.             dstart += 2;
  100.             s += 2;
  101.             if (! isslash(src[2])) {
  102.                 slash = (char) '\\';
  103.                 *d++ = '\\';
  104.             } else {
  105.                 slash = src[2];
  106.                 /* add it below *d++ = src[2]; */
  107.             }
  108.         }
  109.     }
  110.  
  111.     for (;;) {
  112.         c = *s;
  113.         if (c == '.') {
  114.             if (((s == start) || isslash(s[-1])) && (isslash(s[1]) || (s[1] == '\0'))) {
  115.                 /* Don't copy "./" */
  116.                 if (isslash(s[1]))
  117.                     ++s;
  118.                 ++s;
  119.             } else if ((dosCompat != 0) && (s[1] == '.')) {
  120.                 if (d < lim)
  121.                     *d++ = *s++;
  122.                 if (d < lim)
  123.                     *d++ = *s++;
  124.                 if (*s == '.') {
  125.                     dotp = s;
  126.                     while (*dotp == '.')
  127.                         dotp++;
  128.                     if ((*dotp == '\0') || (isslash(*dotp))) {
  129.                         /* On DOS, "..." == "..",
  130.                          * "...." == "..", etc,
  131.                          * so skip the extra dots.
  132.                          */
  133.                         s = dotp;
  134.                     }
  135.                 }
  136.             } else if (d < lim) {
  137.                 *d++ = *s++;
  138.             } else {
  139.                 ++s;
  140.             }
  141.         } else if (isslash(c)) {
  142.             /* Don't copy multiple slashes. */
  143.             if (d < lim)
  144.                 *d++ = slash;
  145.             ++s;
  146.             for (;;) {
  147.                 c = *s;
  148.                 if (isslash(c)) {
  149.                     /* Don't copy multiple slashes. */
  150.                     ++s;
  151.                 } else if (c == '.') {
  152.                     c = s[1];
  153.                     if (isslash(c)) {
  154.                         /* Skip "./" */
  155.                         s += 2;
  156.                     } else if (c == '\0') {
  157.                         /* Skip "./" */
  158.                         s += 1;
  159.                     } else {
  160.                         break;
  161.                     }
  162.                 } else {
  163.                     break;
  164.                 }
  165.             }
  166.         } else if (c == '\0') {
  167.             /* Remove trailing slash. */
  168.             if (isslash(d[-1]) && (d > (dstart + 1)))
  169.                 d[-1] = '\0';
  170.             *d = '\0';
  171.             break;
  172.         } else if (d < lim) {
  173.             *d++ = *s++;
  174.         } else {
  175.             ++s;
  176.         }
  177.     }
  178.     a = dstart;
  179.  
  180.     /* fprintf(stderr, "<%s>\n", dst); */
  181.     /* Go through and remove .. in the path when we know what the
  182.      * parent directory is.  After we get done with this, the only
  183.      * .. nodes in the path will be at the front.
  184.      */
  185.     while (*a != '\0') {
  186.         b = a;
  187.         for (;;) {
  188.             /* Get the next node in the path. */
  189.             if (*a == '\0')
  190.                 return;
  191.             if (isslash(*a)) {
  192.                 ++a;
  193.                 break;
  194.             }
  195.             ++a;
  196.         }
  197.         if ((b[0] == '.') && (b[1] == '.')) {
  198.             if (isslash(b[2])) {
  199.                 /* We don't know what the parent of this
  200.                  * node would be.
  201.                  */
  202.                 continue;
  203.             }
  204.         }
  205.         if ((a[0] == '.') && (a[1] == '.')) {
  206.             if (isslash(a[2])) {
  207.                 /* Remove the .. node and the one before it. */
  208.                 if ((b == dstart) && (isslash(*dstart)))
  209.                     (void) memmove(b + 1, a + 3, strlen(a + 3) + 1);
  210.                 else
  211.                     (void) memmove(b, a + 3, strlen(a + 3) + 1);
  212.                 a = dstart;    /* Start over. */
  213.             } else if (a[2] == '\0') {
  214.                 /* Remove a trailing .. like:  /aaa/bbb/.. */
  215.                 if (b == dstart) {
  216.                     dstart[0] = (char) ((isslash(start[0])) ? slash : '.');
  217.                     dstart[1] = '\0';
  218.                 } else if ((b <= dstart + 1) && isslash(*dstart)) {
  219.                     dstart[1] = '\0';
  220.                 } else {
  221.                     b[-1] = '\0';
  222.                 }
  223.                 a = dstart;    /* Start over. */
  224.             } else {
  225.                 /* continue processing this node.
  226.                  * It is probably some bogus path,
  227.                  * like ".../", "..foo/", etc.
  228.                  */
  229.             }
  230.         }
  231.     }
  232. #undef isslash
  233. }    /* CompressPath */
  234.  
  235.  
  236.  
  237. void
  238. PathCat(char *const dst, const size_t dsize, const char *const cwd, const char *const src, int dosCompat)
  239. {
  240.     char *cp;
  241.     char tmp[512];
  242.  
  243.     if (dosCompat != 0) {
  244.         if ((isalpha((int) cwd[0])) && (cwd[1] == ':')) {
  245.             if ((isalpha((int) src[0])) && (src[1] == ':')) {
  246.                 /* A new fully-qualified DOS drive+path was requested. */
  247.                 CompressPath(dst, src, dsize, dosCompat);
  248.                 return;
  249.             } else if (IsValidUNCPath(src)) {
  250.                 CompressPath(dst, src, dsize, dosCompat);
  251.                 return;
  252.             } else if (src[0] == '\\') {
  253.                 /* A new fully-qualified DOS path on the same
  254.                  * drive letter was requested.
  255.                  */
  256.                 dst[0] = cwd[0];
  257.                 dst[1] = ':';
  258.                 CompressPath(dst + 2, src, dsize - 2, dosCompat);
  259.                 return;
  260.             }
  261.         } else if (IsValidUNCPath(src)) {
  262.             /* A new fully-qualified DOS UNC path was requested.
  263.              * (but no drive letter was present on CWD?)
  264.              */
  265.             CompressPath(dst, src, dsize, dosCompat);
  266.             return;
  267.         } else if ((src[0] == '\\') || ((isalpha((int) src[0])) && (src[1] == ':'))) {
  268.             /* A new fully-qualified DOS path was requested.
  269.              * (but no drive letter was present on CWD?)
  270.              */
  271.             CompressPath(dst, src, dsize, dosCompat);
  272.             return;
  273.         }
  274.     }
  275.     if ((src[0] == '/') || (src[0] == '~')) {
  276.         /* A new fully-qualified UNIX path was requested. */
  277.         CompressPath(dst, src, dsize, dosCompat);
  278.         return;
  279.     }
  280.  
  281.     cp = Strnpcpy(tmp, cwd, sizeof(tmp) - 1);
  282.     if (dosCompat) {
  283.         if (dst[0] == '\\')
  284.             *cp++ = '\\';
  285.         else if ((dst[1] != ':') || (dst[2] == '/'))
  286.             *cp++ = '/';
  287.         else
  288.             *cp++ = '\\';
  289.     } else {
  290.         *cp++ = '/';
  291.     }
  292.     *cp = '\0';
  293.     (void) Strnpcat(cp, src, sizeof(tmp) - (cp - tmp));
  294.     CompressPath(dst, tmp, dsize, dosCompat);
  295. }    /* PathCat */
  296.  
  297.  
  298.  
  299. int
  300. DPathCat(char **const dst0, const char *const cwd, const char *const src, int dosCompat)
  301. {
  302.     char *cp, *dst, *tmp;
  303.     size_t dsize;
  304.  
  305.     dsize = strlen(cwd) +
  306.         /* pathdelim */ 1 +
  307.         strlen(src) +
  308.         /* NUL byte */ 1 +
  309.         /* spare */ 10;
  310.  
  311.     dst = calloc(dsize, 1);
  312.     *dst0 = dst;
  313.     if (dst == NULL)
  314.         return (-1);
  315.  
  316.     if (dosCompat != 0) {
  317.         if ((isalpha((int) cwd[0])) && (cwd[1] == ':')) {
  318.             if ((isalpha((int) src[0])) && (src[1] == ':')) {
  319.                 /* A new fully-qualified DOS drive+path was requested. */
  320.                 CompressPath(dst, src, dsize, dosCompat);
  321.                 return (0);
  322.             } else if (IsValidUNCPath(src)) {
  323.                 CompressPath(dst, src, dsize, dosCompat);
  324.                 return (0);
  325.             } else if (src[0] == '\\') {
  326.                 /* A new fully-qualified DOS path on the same
  327.                  * drive letter was requested.
  328.                  */
  329.                 dst[0] = cwd[0];
  330.                 dst[1] = ':';
  331.                 CompressPath(dst + 2, src, dsize - 2, dosCompat);
  332.                 return (0);
  333.             }
  334.         } else if (IsValidUNCPath(src)) {
  335.             /* A new fully-qualified DOS UNC path was requested.
  336.              * (but no drive letter was present on CWD?)
  337.              */
  338.             CompressPath(dst, src, dsize, dosCompat);
  339.             return (0);
  340.         } else if ((src[0] == '\\') || ((isalpha((int) src[0])) && (src[1] == ':'))) {
  341.             /* A new fully-qualified DOS path was requested.
  342.              * (but no drive letter was present on CWD?)
  343.              */
  344.             CompressPath(dst, src, dsize, dosCompat);
  345.             return (0);
  346.         }
  347.     }
  348.     if (src[0] == '/') {
  349.         /* A new fully-qualified UNIX path was requested. */
  350.         CompressPath(dst, src, dsize, dosCompat);
  351.         return (0);
  352.     }
  353.  
  354.     tmp = calloc(dsize, 1);
  355.     if (tmp == NULL) {
  356.         free(dst);
  357.         *dst0 = NULL;
  358.         return (-1);
  359.     }
  360.  
  361.     cp = Strnpcpy(tmp, cwd, dsize - 1);
  362.     if (dosCompat) {
  363.         if (dst[0] == '\\')
  364.             *cp++ = '\\';
  365.         else if ((dst[1] != ':') || (dst[2] == '/'))
  366.             *cp++ = '/';
  367.         else
  368.             *cp++ = '\\';
  369.     } else {
  370.         *cp++ = '/';
  371.     }
  372.     *cp = '\0';
  373.     (void) Strnpcat(cp, src, dsize - (cp - tmp));
  374.     CompressPath(dst, tmp, dsize, dosCompat);
  375.     free(tmp);
  376.     return (0);
  377. }    /* DPathCat */
  378.