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