home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / cvs-1.8.7-src.tgz / tar.out / fsf / cvs / src / filesubr.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  15KB  |  697 lines

  1. /* filesubr.c --- subroutines for dealing with files
  2.    Jim Blandy <jimb@cyclic.com>
  3.  
  4.    This file is part of GNU CVS.
  5.  
  6.    GNU CVS is free software; you can redistribute it and/or modify it
  7.    under the terms of the GNU General Public License as published by the
  8.    Free Software Foundation; either version 2, or (at your option) any
  9.    later version.
  10.  
  11.    This program is distributed in the hope that it will be useful,
  12.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with this program; if not, write to the Free Software
  18.    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /* These functions were moved out of subr.c because they need different
  21.    definitions under operating systems (like, say, Windows NT) with different
  22.    file system semantics.  */
  23.  
  24. #include "cvs.h"
  25.  
  26. /*
  27.  * I don't know of a convenient way to test this at configure time, or else
  28.  * I'd certainly do it there.
  29.  */
  30. #if defined(NeXT)
  31. #define LOSING_TMPNAM_FUNCTION
  32. #endif
  33.  
  34. static int deep_remove_dir PROTO((const char *path));
  35.  
  36. /*
  37.  * Copies "from" to "to".
  38.  */
  39. void
  40. copy_file (from, to)
  41.     const char *from;
  42.     const char *to;
  43. {
  44.     struct stat sb;
  45.     struct utimbuf t;
  46.     int fdin, fdout;
  47.  
  48.     if (trace)
  49. #ifdef SERVER_SUPPORT
  50.     (void) fprintf (stderr, "%c-> copy(%s,%s)\n",
  51.             (server_active) ? 'S' : ' ', from, to);
  52. #else
  53.     (void) fprintf (stderr, "-> copy(%s,%s)\n", from, to);
  54. #endif
  55.     if (noexec)
  56.     return;
  57.  
  58.     if ((fdin = open (from, O_RDONLY)) < 0)
  59.     error (1, errno, "cannot open %s for copying", from);
  60.     if (fstat (fdin, &sb) < 0)
  61.     error (1, errno, "cannot fstat %s", from);
  62.     if ((fdout = creat (to, (int) sb.st_mode & 07777)) < 0)
  63.     error (1, errno, "cannot create %s for copying", to);
  64.     if (sb.st_size > 0)
  65.     {
  66.     char buf[BUFSIZ];
  67.     int n;
  68.  
  69.     for (;;) 
  70.     {
  71.         n = read (fdin, buf, sizeof(buf));
  72.         if (n == -1)
  73.         {
  74. #ifdef EINTR
  75.         if (errno == EINTR)
  76.             continue;
  77. #endif
  78.         error (1, errno, "cannot read file %s for copying", from);
  79.         }
  80.             else if (n == 0) 
  81.         break;
  82.   
  83.         if (write(fdout, buf, n) != n) {
  84.         error (1, errno, "cannot write file %s for copying", to);
  85.         }
  86.     }
  87.  
  88. #ifdef HAVE_FSYNC
  89.     if (fsync (fdout)) 
  90.         error (1, errno, "cannot fsync file %s after copying", to);
  91. #endif
  92.     }
  93.  
  94.     if (close (fdin) < 0) 
  95.     error (0, errno, "cannot close %s", from);
  96.     if (close (fdout) < 0)
  97.     error (1, errno, "cannot close %s", to);
  98.  
  99.     /* now, set the times for the copied file to match those of the original */
  100.     memset ((char *) &t, 0, sizeof (t));
  101.     t.actime = sb.st_atime;
  102.     t.modtime = sb.st_mtime;
  103.     (void) utime (to, &t);
  104. }
  105.  
  106. /* FIXME-krp: these functions would benefit from caching the char * &
  107.    stat buf.  */
  108.  
  109. /*
  110.  * Returns non-zero if the argument file is a directory, or is a symbolic
  111.  * link which points to a directory.
  112.  */
  113. int
  114. isdir (file)
  115.     const char *file;
  116. {
  117.     struct stat sb;
  118.  
  119.     if (stat (file, &sb) < 0)
  120.     return (0);
  121.     return (S_ISDIR (sb.st_mode));
  122. }
  123.  
  124. /*
  125.  * Returns non-zero if the argument file is a symbolic link.
  126.  */
  127. int
  128. islink (file)
  129.     const char *file;
  130. {
  131. #ifdef S_ISLNK
  132.     struct stat sb;
  133.  
  134.     if (lstat (file, &sb) < 0)
  135.     return (0);
  136.     return (S_ISLNK (sb.st_mode));
  137. #else
  138.     return (0);
  139. #endif
  140. }
  141.  
  142. /*
  143.  * Returns non-zero if the argument file exists.
  144.  */
  145. int
  146. isfile (file)
  147.     const char *file;
  148. {
  149.     return isaccessible(file, F_OK);
  150. }
  151.  
  152. /*
  153.  * Returns non-zero if the argument file is readable.
  154.  */
  155. int
  156. isreadable (file)
  157.     const char *file;
  158. {
  159.     return isaccessible(file, R_OK);
  160. }
  161.  
  162. /*
  163.  * Returns non-zero if the argument file is writable.
  164.  */
  165. int
  166. iswritable (file)
  167.     const char *file;
  168. {
  169.     return isaccessible(file, W_OK);
  170. }
  171.  
  172. /*
  173.  * Returns non-zero if the argument file is accessable according to
  174.  * mode.  If compiled with SETXID_SUPPORT also works if cvs has setxid
  175.  * bits set.
  176.  */
  177. int
  178. isaccessible (file, mode)
  179.     const char *file;
  180.     const int mode;
  181. {
  182. #ifdef SETXID_SUPPORT
  183.     struct stat sb;
  184.     int umask = 0;
  185.     int gmask = 0;
  186.     int omask = 0;
  187.     int uid;
  188.     
  189.     if (stat(file, &sb) == -1)
  190.     return 0;
  191.     if (mode == F_OK)
  192.     return 1;
  193.  
  194.     uid = geteuid();
  195.     if (uid == 0)        /* superuser */
  196.     {
  197.     if (mode & X_OK)
  198.         return sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH);
  199.     else
  200.         return 1;
  201.     }
  202.     
  203.     if (mode & R_OK)
  204.     {
  205.     umask |= S_IRUSR;
  206.     gmask |= S_IRGRP;
  207.     omask |= S_IROTH;
  208.     }
  209.     if (mode & W_OK)
  210.     {
  211.     umask |= S_IWUSR;
  212.     gmask |= S_IWGRP;
  213.     omask |= S_IWOTH;
  214.     }
  215.     if (mode & X_OK)
  216.     {
  217.     umask |= S_IXUSR;
  218.     gmask |= S_IXGRP;
  219.     omask |= S_IXOTH;
  220.     }
  221.  
  222.     if (sb.st_uid == uid)
  223.     return (sb.st_mode & umask) == umask;
  224.     else if (sb.st_gid == getegid())
  225.     return (sb.st_mode & gmask) == gmask;
  226.     else
  227.     return (sb.st_mode & omask) == omask;
  228. #else
  229.     return access(file, mode) == 0;
  230. #endif
  231. }
  232.  
  233. /*
  234.  * Open a file and die if it fails
  235.  */
  236. FILE *
  237. open_file (name, mode)
  238.     const char *name;
  239.     const char *mode;
  240. {
  241.     FILE *fp;
  242.  
  243.     if ((fp = fopen (name, mode)) == NULL)
  244.     error (1, errno, "cannot open %s", name);
  245.     return (fp);
  246. }
  247.  
  248. /*
  249.  * Make a directory and die if it fails
  250.  */
  251. void
  252. make_directory (name)
  253.     const char *name;
  254. {
  255.     struct stat sb;
  256.  
  257.     if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode)))
  258.         error (0, 0, "%s already exists but is not a directory", name);
  259.     if (!noexec && mkdir (name, 0777) < 0)
  260.     error (1, errno, "cannot make directory %s", name);
  261. }
  262.  
  263. /*
  264.  * Make a path to the argument directory, printing a message if something
  265.  * goes wrong.
  266.  */
  267. void
  268. make_directories (name)
  269.     const char *name;
  270. {
  271.     char *cp;
  272.  
  273.     if (noexec)
  274.     return;
  275.  
  276.     if (mkdir (name, 0777) == 0 || errno == EEXIST)
  277.     return;
  278.     if (! existence_error (errno))
  279.     {
  280.     error (0, errno, "cannot make path to %s", name);
  281.     return;
  282.     }
  283.     if ((cp = strrchr (name, '/')) == NULL)
  284.     return;
  285.     *cp = '\0';
  286.     make_directories (name);
  287.     *cp++ = '/';
  288.     if (*cp == '\0')
  289.     return;
  290.     (void) mkdir (name, 0777);
  291. }
  292.  
  293. /* Create directory NAME if it does not already exist; fatal error for
  294.    other errors.  Returns 0 if directory was created; 1 if it already
  295.    existed.  */
  296. int
  297. mkdir_if_needed (name)
  298.     char *name;
  299. {
  300.     if (mkdir (name, 0777) < 0)
  301.     {
  302.     if (errno != EEXIST)
  303.         error (1, errno, "cannot make directory %s", name);
  304.     return 1;
  305.     }
  306.     return 0;
  307. }
  308.  
  309. /*
  310.  * Change the mode of a file, either adding write permissions, or removing
  311.  * all write permissions.  Either change honors the current umask setting.
  312.  */
  313. void
  314. xchmod (fname, writable)
  315.     char *fname;
  316.     int writable;
  317. {
  318.     struct stat sb;
  319.     mode_t mode, oumask;
  320.  
  321.     if (stat (fname, &sb) < 0)
  322.     {
  323.     if (!noexec)
  324.         error (0, errno, "cannot stat %s", fname);
  325.     return;
  326.     }
  327.     oumask = umask (0);
  328.     (void) umask (oumask);
  329.     if (writable)
  330.     {
  331.     mode = sb.st_mode | (~oumask
  332.                  & (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0)
  333.                 | ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0)
  334.                 | ((sb.st_mode & S_IROTH) ? S_IWOTH : 0)));
  335.     }
  336.     else
  337.     {
  338.     mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH) & ~oumask;
  339.     }
  340.  
  341.     if (trace)
  342. #ifdef SERVER_SUPPORT
  343.     (void) fprintf (stderr, "%c-> chmod(%s,%o)\n",
  344.             (server_active) ? 'S' : ' ', fname,
  345.             (unsigned int) mode);
  346. #else
  347.     (void) fprintf (stderr, "-> chmod(%s,%o)\n", fname,
  348.             (unsigned int) mode);
  349. #endif
  350.     if (noexec)
  351.     return;
  352.  
  353.     if (chmod (fname, mode) < 0)
  354.     error (0, errno, "cannot change mode of file %s", fname);
  355. }
  356.  
  357. /*
  358.  * Rename a file and die if it fails
  359.  */
  360. void
  361. rename_file (from, to)
  362.     const char *from;
  363.     const char *to;
  364. {
  365.     if (trace)
  366. #ifdef SERVER_SUPPORT
  367.     (void) fprintf (stderr, "%c-> rename(%s,%s)\n",
  368.             (server_active) ? 'S' : ' ', from, to);
  369. #else
  370.     (void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
  371. #endif
  372.     if (noexec)
  373.     return;
  374.  
  375.     if (rename (from, to) < 0)
  376.     error (1, errno, "cannot rename file %s to %s", from, to);
  377. }
  378.  
  379. /*
  380.  * link a file, if possible.  Warning: the Windows NT version of this
  381.  * function just copies the file, so only use this function in ways
  382.  * that can deal with either a link or a copy.
  383.  */
  384. int
  385. link_file (from, to)
  386.     const char *from;
  387.     const char *to;
  388. {
  389.     if (trace)
  390. #ifdef SERVER_SUPPORT
  391.     (void) fprintf (stderr, "%c-> link(%s,%s)\n",
  392.             (server_active) ? 'S' : ' ', from, to);
  393. #else
  394.     (void) fprintf (stderr, "-> link(%s,%s)\n", from, to);
  395. #endif
  396.     if (noexec)
  397.     return (0);
  398.  
  399.     return (link (from, to));
  400. }
  401.  
  402. /*
  403.  * unlink a file, if possible.
  404.  */
  405. int
  406. unlink_file (f)
  407.     const char *f;
  408. {
  409.     if (trace)
  410. #ifdef SERVER_SUPPORT
  411.     (void) fprintf (stderr, "%c-> unlink(%s)\n",
  412.             (server_active) ? 'S' : ' ', f);
  413. #else
  414.     (void) fprintf (stderr, "-> unlink(%s)\n", f);
  415. #endif
  416.     if (noexec)
  417.     return (0);
  418.  
  419.     return (unlink (f));
  420. }
  421.  
  422. /*
  423.  * Unlink a file or dir, if possible.  If it is a directory do a deep
  424.  * removal of all of the files in the directory.  Return -1 on error
  425.  * (in which case errno is set).
  426.  */
  427. int
  428. unlink_file_dir (f)
  429.     const char *f;
  430. {
  431.     if (trace)
  432. #ifdef SERVER_SUPPORT
  433.     (void) fprintf (stderr, "%c-> unlink_file_dir(%s)\n",
  434.             (server_active) ? 'S' : ' ', f);
  435. #else
  436.     (void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f);
  437. #endif
  438.     if (noexec)
  439.     return (0);
  440.  
  441.     /* For at least some unices, if root tries to unlink() a directory,
  442.        instead of doing something rational like returning EISDIR,
  443.        the system will gleefully go ahead and corrupt the filesystem.
  444.        So we first call isdir() to see if it is OK to call unlink().  This
  445.        doesn't quite work--if someone creates a directory between the
  446.        call to isdir() and the call to unlink(), we'll still corrupt
  447.        the filesystem.  Where is the Unix Haters Handbook when you need
  448.        it?  */
  449.     if (isdir(f)) 
  450.     return deep_remove_dir(f);
  451.     else
  452.     {
  453.     if (unlink (f) != 0)
  454.         return -1;
  455.     }
  456.     /* We were able to remove the file from the disk */
  457.     return 0;
  458. }
  459.  
  460. /* Remove a directory and everything it contains.  Returns 0 for
  461.  * success, -1 for failure (in which case errno is set).
  462.  */
  463.  
  464. static int
  465. deep_remove_dir (path)
  466.     const char *path;
  467. {
  468.     DIR          *dirp;
  469.     struct dirent *dp;
  470.     char       buf[PATH_MAX];
  471.  
  472.     if (rmdir (path) != 0 && (errno == ENOTEMPTY || errno == EEXIST)) 
  473.     {
  474.     if ((dirp = opendir (path)) == NULL)
  475.         /* If unable to open the directory return
  476.          * an error
  477.          */
  478.         return -1;
  479.  
  480.     while ((dp = readdir (dirp)) != NULL)
  481.     {
  482.         if (strcmp (dp->d_name, ".") == 0 ||
  483.             strcmp (dp->d_name, "..") == 0)
  484.         continue;
  485.  
  486.         sprintf (buf, "%s/%s", path, dp->d_name);
  487.  
  488.         /* See comment in unlink_file_dir explanation of why we use
  489.            isdir instead of just calling unlink and checking the
  490.            status.  */
  491.         if (isdir(buf)) 
  492.         {
  493.         if (deep_remove_dir(buf))
  494.         {
  495.             closedir(dirp);
  496.             return -1;
  497.         }
  498.         }
  499.         else
  500.         {
  501.         if (unlink (buf) != 0)
  502.         {
  503.             closedir(dirp);
  504.             return -1;
  505.         }
  506.         }
  507.     }
  508.     closedir (dirp);
  509.     return rmdir (path);
  510.     }
  511.  
  512.     /* Was able to remove the directory return 0 */
  513.     return 0;
  514. }
  515.  
  516. /* Read NCHARS bytes from descriptor FD into BUF.
  517.    Return the number of characters successfully read.
  518.    The number returned is always NCHARS unless end-of-file or error.  */
  519. static size_t
  520. block_read (fd, buf, nchars)
  521.     int fd;
  522.     char *buf;
  523.     size_t nchars;
  524. {
  525.     char *bp = buf;
  526.     size_t nread;
  527.  
  528.     do 
  529.     {
  530.     nread = read (fd, bp, nchars);
  531.     if (nread == (size_t)-1)
  532.     {
  533. #ifdef EINTR
  534.         if (errno == EINTR)
  535.         continue;
  536. #endif
  537.         return (size_t)-1;
  538.     }
  539.  
  540.     if (nread == 0)
  541.         break; 
  542.  
  543.     bp += nread;
  544.     nchars -= nread;
  545.     } while (nchars != 0);
  546.  
  547.     return bp - buf;
  548.  
  549.     
  550. /*
  551.  * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
  552.  */
  553. int
  554. xcmp (file1, file2)
  555.     const char *file1;
  556.     const char *file2;
  557. {
  558.     char *buf1, *buf2;
  559.     struct stat sb1, sb2;
  560.     int fd1, fd2;
  561.     int ret;
  562.  
  563.     if ((fd1 = open (file1, O_RDONLY)) < 0)
  564.     error (1, errno, "cannot open file %s for comparing", file1);
  565.     if ((fd2 = open (file2, O_RDONLY)) < 0)
  566.     error (1, errno, "cannot open file %s for comparing", file2);
  567.     if (fstat (fd1, &sb1) < 0)
  568.     error (1, errno, "cannot fstat %s", file1);
  569.     if (fstat (fd2, &sb2) < 0)
  570.     error (1, errno, "cannot fstat %s", file2);
  571.  
  572.     /* A generic file compare routine might compare st_dev & st_ino here 
  573.        to see if the two files being compared are actually the same file.
  574.        But that won't happen in CVS, so we won't bother. */
  575.  
  576.     if (sb1.st_size != sb2.st_size)
  577.     ret = 1;
  578.     else if (sb1.st_size == 0)
  579.     ret = 0;
  580.     else
  581.     {
  582.     /* FIXME: compute the optimal buffer size by computing the least
  583.        common multiple of the files st_blocks field */
  584.     size_t buf_size = 8 * 1024;
  585.     size_t read1;
  586.     size_t read2;
  587.  
  588.     buf1 = xmalloc (buf_size);
  589.     buf2 = xmalloc (buf_size);
  590.  
  591.     do 
  592.     {
  593.         read1 = block_read (fd1, buf1, buf_size);
  594.         if (read1 == (size_t)-1)
  595.         error (1, errno, "cannot read file %s for comparing", file1);
  596.  
  597.         read2 = block_read (fd2, buf2, buf_size);
  598.         if (read2 == (size_t)-1)
  599.         error (1, errno, "cannot read file %s for comparing", file2);
  600.  
  601.         /* assert (read1 == read2); */
  602.  
  603.         ret = memcmp(buf1, buf2, read1);
  604.     } while (ret == 0 && read1 == buf_size);
  605.  
  606.     free (buf1);
  607.     free (buf2);
  608.     }
  609.     
  610.     (void) close (fd1);
  611.     (void) close (fd2);
  612.     return (ret);
  613. }
  614.  
  615. /* Just in case this implementation does not define this.  */
  616. #ifndef L_tmpnam
  617. #define    L_tmpnam 50
  618. #endif
  619.  
  620. #ifdef LOSING_TMPNAM_FUNCTION
  621. char *
  622. cvs_temp_name ()
  623. {
  624.     char value[L_tmpnam + 1];
  625.  
  626.     /* FIXME: Should be using TMPDIR.  */
  627.     strcpy (value, "/tmp/cvsXXXXXX");
  628.     mktemp (value);
  629.     return xstrdup (value);
  630. }
  631. #else
  632. /* Generate a unique temporary filename.  Returns a pointer to a newly
  633.    malloc'd string containing the name.  Returns successfully or not at
  634.    all.  */
  635. char *
  636. cvs_temp_name ()
  637. {
  638.     char value[L_tmpnam + 1];
  639.     char *retval;
  640.  
  641.     /* FIXME: should be using TMPDIR, perhaps by using tempnam on systems
  642.        which have it.  */
  643.     retval = tmpnam (value);
  644.     if (retval == NULL)
  645.     error (1, errno, "cannot generate temporary filename");
  646.     return xstrdup (retval);
  647. }
  648. #endif
  649.  
  650. /* Return non-zero iff FILENAME is absolute.
  651.    Trivial under Unix, but more complicated under other systems.  */
  652. int
  653. isabsolute (filename)
  654.     const char *filename;
  655. {
  656.     return filename[0] == '/';
  657. }
  658.  
  659.  
  660. /* Return a pointer into PATH's last component.  */
  661. char *
  662. last_component (path)
  663.     char *path;
  664. {
  665.     char *last = strrchr (path, '/');
  666.  
  667.     if (last)
  668.         return last + 1;
  669.     else
  670.         return path;
  671. }
  672.  
  673. /* Return the home directory.  Returns a pointer to storage
  674.    managed by this function or its callees (currently getenv).  */
  675. char *
  676. get_homedir ()
  677. {
  678.     return getenv ("HOME");
  679. }
  680.  
  681. /* See cvs.h for description.  On unix this does nothing, because the
  682.    shell expands the wildcards.  */
  683. void
  684. expand_wild (argc, argv, pargc, pargv)
  685.     int argc;
  686.     char **argv;
  687.     int *pargc;
  688.     char ***pargv;
  689. {
  690.     int i;
  691.     *pargc = argc;
  692.     *pargv = (char **) xmalloc (argc * sizeof (char *));
  693.     for (i = 0; i < argc; ++i)
  694.     (*pargv)[i] = xstrdup (argv[i]);
  695. }
  696.