home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1995 August / NEBULA.mdf / SourceCode / libcs / makepath.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-11  |  10.2 KB  |  374 lines

  1. /*
  2.  * Copyright (c) 1990 Carnegie Mellon University
  3.  * All Rights Reserved.
  4.  * 
  5.  * Permission to use, copy, modify and distribute this software and its
  6.  * documentation is hereby granted, provided that both the copyright
  7.  * notice and this permission notice appear in all copies of the
  8.  * software, derivative works or modified versions, and any portions
  9.  * thereof, and that both notices appear in supporting documentation.
  10.  *
  11.  * THE SOFTWARE IS PROVIDED "AS IS" AND CARNEGIE MELLON UNIVERSITY
  12.  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  13.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT
  14.  * SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR ANY SPECIAL, DIRECT,
  15.  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  16.  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
  17.  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  18.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  19.  *
  20.  * Users of this software agree to return to Carnegie Mellon any
  21.  * improvements or extensions that they make and grant Carnegie the
  22.  * rights to redistribute these changes.
  23.  *
  24.  * Export of this software is permitted only after complying with the
  25.  * regulations of the U.S. Deptartment of Commerce relating to the
  26.  * Export of Technical Data.
  27.  */
  28. /*
  29.  *  makepath - create intermediate directories along a path
  30.  *
  31.  *  makepath(path, refpath, trace, showerrs)
  32.  *  char *path, *refpath;
  33.  *  int trace, showerrs;
  34.  *
  35.  *  Create any directories missing in path.  If refpath is non-null,
  36.  *  then it must have a non-null trailing subpath that is common to
  37.  *  path.  The entire path will be created if refpath is given and
  38.  *  refpath is the path of a directory, otherwise only the components
  39.  *  preceding the final component will be created for path.  If trace
  40.  *  is non-zero, diagnostics will be printed to stderr.  If showerrs
  41.  *  is non-zero error messages will be printed to stderr.
  42.  *
  43.  **********************************************************************
  44.  * HISTORY
  45.  * $Log:    makepath.c,v $
  46.  * Revision 2.3  90/12/11  17:56:54  mja
  47.  *     Add copyright/disclaimer for distribution.
  48.  * 
  49.  * Revision 2.2  88/12/13  13:51:54  gm0w
  50.  *     Created from makepath program.
  51.  *     [88/12/13            gm0w]
  52.  * 
  53.  **********************************************************************
  54.  */
  55. #include <sys/param.h>
  56. #include <sys/stat.h>
  57. #include <sys/time.h>
  58. #include <stdio.h>
  59. #include <libc.h>
  60. #include <c.h>
  61.  
  62. static
  63. char *fixpath(path, buf)
  64. register char *path;
  65. char *buf;
  66. {
  67.     register char *ls = NULL;
  68.     register char *p = buf;
  69.  
  70.     *p = *path;
  71.     while (*path != '\0') {
  72.     path++;
  73.     while (*p == '/' && *path == '/')
  74.         path++;
  75.     *++p = *path;
  76.     if (*p == '/')
  77.         ls = p;
  78.     }
  79.     return(ls);
  80. }
  81.  
  82. makepath(path, refpath, trace, showerrs)
  83. char *path, *refpath;
  84. int trace, showerrs;
  85. {
  86.     char pathbuf[MAXPATHLEN], refpathbuf[MAXPATHLEN];
  87.     char linkbuf[MAXPATHLEN], linkbuf2[MAXPATHLEN];
  88.     char *base, *refbase;
  89.     char *slash, *refslash;
  90.     struct stat statb, refstatb;
  91.     int ch, cc, cc2;
  92.     extern uid_t getuid();
  93.     uid_t uid = getuid();
  94.  
  95.     if (path == NULL) {
  96.     if (showerrs)
  97.         fprintf(stderr, "makepath: NULL path argument\n");
  98.     return(1);
  99.     }
  100.  
  101.     base = fixpath(path, pathbuf);
  102.  
  103.     if (refpath == NULL) {
  104.     if (base == NULL || base == pathbuf) {
  105.         if (showerrs)
  106.         fprintf(stderr,
  107.             "makepath: %s must have an imbedded '/' character\n",
  108.             pathbuf);
  109.         return(1);
  110.     }
  111.     *base = '\0';
  112.     base = pathbuf;
  113.     if (*base == '/')
  114.         base++;
  115.     if (*base == '\0') {
  116.         if (showerrs)
  117.         fprintf(stderr, "makepath: illegal pathname %s\n", pathbuf);
  118.         return(1);
  119.     }
  120.     for (;;) {
  121.         /* find end of this component */
  122.         while (*base != '\0' && *base != '/')
  123.         base++;
  124.  
  125.         /* create path so far, if necessary */
  126.         ch = *base; *base = '\0';
  127.         if (stat(pathbuf, &statb) < 0) {
  128.         if (mkdir(pathbuf, 0755) < 0) {
  129.             if (showerrs)
  130.             fprintf(stderr,
  131.                 "makepath: unable to create directory %s: %s\n",
  132.                 pathbuf, errmsg(-1));
  133.             return(1);
  134.         }
  135.         if (stat(pathbuf, &statb) < 0) {
  136.             if (showerrs)
  137.             fprintf(stderr,
  138.                 "%s: unable to stat directory %s: %s\n",
  139.                 pathbuf, errmsg(-1));
  140.             return(1);
  141.         }
  142.         if (trace)
  143.             fprintf(stderr, "%s: created directory\n", pathbuf);
  144.         } else if ((statb.st_mode&S_IFMT) != S_IFDIR) {
  145.         if (showerrs)
  146.             fprintf(stderr,
  147.                 "makepath: %s is not a directory (mode %#o)\n",
  148.                 pathbuf, (statb.st_mode&S_IFMT));
  149.         return(1);
  150.         }
  151.         if (ch == '\0')
  152.         break;
  153.         *base++ = ch;
  154.     }
  155.     return(0);
  156.     }
  157.  
  158.     refbase = fixpath(refpath, refpathbuf);
  159.  
  160.     /* if not a directory path, strip final component */
  161.     if (stat(refpathbuf, &refstatb) < 0 ||
  162.     (refstatb.st_mode&S_IFMT) != S_IFDIR) {
  163.     if (base == NULL || base == pathbuf) {
  164.         if (showerrs)
  165.         fprintf(stderr,
  166.             "makepath: %s must have an imbedded '/' character\n",
  167.             pathbuf);
  168.         return(1);
  169.     }
  170.     if (refbase == NULL || refbase == refpathbuf) {
  171.         if (showerrs)
  172.         fprintf(stderr,
  173.             "makepath: %s must have an imbedded '/' character\n",
  174.             refpathbuf);
  175.         return(1);
  176.     }
  177.     if (strcmp(base, refbase) != 0) {
  178.         if (showerrs)
  179.         fprintf(stderr,
  180.             "makepath: %s and %s do not have common trailing components\n",
  181.             base, refbase);
  182.         return(1);
  183.     }
  184.     *base = *refbase = '\0';
  185.     if (stat(refpathbuf, &refstatb) < 0) {
  186.         if (showerrs)
  187.         fprintf(stderr,
  188.             "%s: unable to stat reference directory %s: %s\n",
  189.             refpathbuf, errmsg(-1));
  190.         return(1);
  191.     }
  192.     if ((refstatb.st_mode&S_IFMT) != S_IFDIR) {
  193.         if (showerrs)
  194.         fprintf(stderr, "makepath: %s is not a directory (mode %#o)\n",
  195.             refpathbuf, (refstatb.st_mode&S_IFMT));
  196.         return(1);
  197.     }
  198.     }
  199.  
  200.     /* find beginning of common part of path names */
  201.     base = pathbuf + strlen(pathbuf);
  202.     refbase = refpathbuf + strlen(refpathbuf);
  203.     while (*base == *refbase) {
  204.     if (base == pathbuf || refbase == refpathbuf)
  205.         break;
  206.     base--; refbase--;
  207.     }
  208.     if (*base == *refbase && *base != '/') {
  209.     if (base == pathbuf && *(refbase-1) == '/') {
  210.         base = pathbuf + strlen(pathbuf) + 2;
  211.         do {
  212.         *base = *(base - 2);
  213.         } while (base-- > pathbuf + 2);
  214.         *(base-1) = '.';
  215.         *base = '/';
  216.         refbase--;
  217.     }
  218.     if (refbase == refpathbuf && *(base-1) == '/') {
  219.         refbase = refpathbuf + strlen(refpathbuf) + 2;
  220.         do {
  221.         *refbase = *(refbase - 2);
  222.         } while (refbase-- > refpathbuf + 2);
  223.         *(refbase-1) = '.';
  224.         *refbase = '/';
  225.         base--;
  226.     }
  227.     }
  228.     while (*base != '\0' && *base != '/') {
  229.     base++; refbase++;
  230.     }
  231.     slash = base++;
  232.     refslash = refbase++;
  233.     ch = *slash; *slash = '\0';
  234.     if (stat(pathbuf, &statb) < 0) {
  235.     if (showerrs)
  236.         fprintf(stderr,
  237.             "makepath: unable to stat target directory %s: %s\n",
  238.             pathbuf, errmsg(-1));
  239.     return(1);
  240.     }
  241.     if ((statb.st_mode&S_IFMT) != S_IFDIR) {
  242.     if (showerrs)
  243.         fprintf(stderr, "makepath: %s: invalid mode %#o\n",
  244.             pathbuf, (statb.st_mode&S_IFMT));
  245.     return(1);
  246.     }
  247.     *slash = ch;
  248.  
  249.     /* check each component along common path and make them the same */
  250.     while (ch != '\0') {
  251.     /* find end of this component */
  252.     while (*base != '\0' && *base != '/') {
  253.         base++; refbase++;
  254.     }
  255.  
  256.     /* get stat information for source path */
  257.     ch = *refbase; *refbase = '\0'; *base = '\0';
  258.     if (stat(refpathbuf, &refstatb) < 0) {
  259.         if (showerrs)
  260.         fprintf(stderr, "makepath: stat %s: %s\n",
  261.             refpathbuf, errmsg(-1));
  262.         return(1);
  263.     }
  264.     if ((refstatb.st_mode&S_IFMT) != S_IFDIR) {
  265.         if (showerrs)
  266.         fprintf(stderr, "makepath: %s: invalid mode %#o\n",
  267.             refpathbuf, (refstatb.st_mode&S_IFMT));
  268.         return(1);
  269.     }
  270.     if (lstat(refpathbuf, &refstatb) < 0) {
  271.         if (showerrs)
  272.         fprintf(stderr, "makepath: lstat %s: %s\n",
  273.             refpathbuf, errmsg(-1));
  274.         return(1);
  275.     }
  276.     if ((refstatb.st_mode&S_IFMT) == S_IFLNK) {
  277.         if ((cc = readlink(refpathbuf, linkbuf, sizeof(linkbuf)-1)) < 0) {
  278.         if (showerrs)
  279.             fprintf(stderr, "makepath: readlink %s: %s\n",
  280.                 refpathbuf, errmsg(-1));
  281.         return(1);
  282.         }
  283.         if (cc > 0 && *linkbuf != '/') {
  284.         *refbase = ch;
  285.         linkbuf[cc] = '\0';
  286.         if (lstat(pathbuf, &statb) < 0) {
  287.             if (symlink(linkbuf, pathbuf) < 0) {
  288.             if (showerrs)
  289.                 fprintf(stderr, "makepath: symlink %s: %s\n",
  290.                     pathbuf, errmsg(-1));
  291.             return(1);
  292.             }
  293.             if (trace)
  294.             fprintf(stderr, "%s: created symlink to %s\n",
  295.                 pathbuf, linkbuf);
  296.         } else {
  297.             if ((statb.st_mode&S_IFMT) != S_IFLNK) {
  298.             if (showerrs)
  299.                 fprintf(stderr, "makepath: %s: invalid mode %#o\n",
  300.                     pathbuf, (statb.st_mode&S_IFMT));
  301.             return(1);
  302.             }
  303.             cc2 = readlink(pathbuf, linkbuf2, sizeof(linkbuf2)-1);
  304.             if (cc2 < 0) {
  305.             if (showerrs)
  306.                 fprintf(stderr, "makepath: readlink %s: %s\n",
  307.                     pathbuf, errmsg(-1));
  308.             return(1);
  309.             }
  310.             if (cc != cc2 || bcmp(linkbuf, linkbuf2, cc) != 0) {
  311.             if (showerrs)
  312.                 fprintf(stderr,
  313.                     "makepath: symlinks %s and %s differ\n",
  314.                     refpathbuf, pathbuf, errmsg(-1));
  315.             return(1);
  316.             }
  317.         }
  318.         (void) strcpy(linkbuf+cc, refbase);
  319.         (void) strcpy(refslash+1, linkbuf);
  320.         (void) strcpy(slash+1, linkbuf);
  321.         (void) fixpath(refslash, refslash);
  322.         (void) fixpath(slash, slash);
  323.         refbase = refslash+1;
  324.         base = slash+1;
  325.         ch = *refslash;
  326.         continue;
  327.         }
  328.     }
  329.  
  330.     /* create path so far, if necessary */
  331.     if (lstat(pathbuf, &statb) < 0) {
  332.         if (mkdir(pathbuf, (int)(refstatb.st_mode&07777)) < 0) {
  333.         if (showerrs)
  334.             fprintf(stderr, "makepath: mkdir %s: %s\n",
  335.                 pathbuf, errmsg(-1));
  336.         return(1);
  337.         }
  338.         if (stat(pathbuf, &statb) < 0) {
  339.         if (showerrs)
  340.             fprintf(stderr, "makepath: stat %s: %s\n",
  341.                 pathbuf, errmsg(-1));
  342.         return(1);
  343.         }
  344.         if (trace)
  345.         fprintf(stderr, "%s: created directory\n", pathbuf);
  346.     } else if ((statb.st_mode&S_IFMT) != S_IFDIR) {
  347.         if (showerrs)
  348.         fprintf(stderr, "makepath: %s: invalid mode %#o\n",
  349.             pathbuf, (statb.st_mode&S_IFMT));
  350.         return(1);
  351.     }
  352.  
  353.     if (uid == 0 && (statb.st_uid != refstatb.st_uid ||
  354.              statb.st_gid != refstatb.st_gid)) {
  355.         (void) chown(pathbuf, (int)refstatb.st_uid, (int)refstatb.st_gid);
  356.         if (trace)
  357.         fprintf(stderr, "%s: owner %d, group %d\n", pathbuf,
  358.             refstatb.st_uid, refstatb.st_gid);
  359.     }
  360.     if ((statb.st_mode&07777) != (refstatb.st_mode&07777)) {
  361.         (void) chmod(pathbuf, (int)(refstatb.st_mode&07777));
  362.         if (trace)
  363.         fprintf(stderr, "%s: mode %#o\n", pathbuf,
  364.             refstatb.st_mode&07777);
  365.     }
  366.  
  367.     refslash = refbase;
  368.     *refbase++ = ch;
  369.     slash = base;
  370.     *base++ = ch;
  371.     }
  372.     return(0);
  373. }
  374.