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 / os2 / filesubr.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  21KB  |  881 lines

  1. /* filesubr.c --- subroutines for dealing with files under OS/2
  2.    Jim Blandy <jimb@cyclic.com> and Karl Fogel <kfogel@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 <io.h>
  25. #define INCL_DOSFILEMGR   /* File Manager values */
  26. #define INCL_DOSERRORS
  27. #include <os2.h>
  28.  
  29. #include "cvs.h"
  30.  
  31. static int deep_remove_dir PROTO((const char *path));
  32.  
  33. /*
  34.  * Copies "from" to "to".
  35.  */
  36. void
  37. copy_file (from, to)
  38.     const char *from;
  39.     const char *to;
  40. {
  41.     struct stat sb;
  42.     struct utimbuf t;
  43.     int fdin, fdout;
  44.  
  45.     if (trace)
  46. #ifdef SERVER_SUPPORT
  47.     (void) fprintf (stderr, "%c-> copy(%s,%s)\n",
  48.             (server_active) ? 'S' : ' ', from, to);
  49. #else
  50.     (void) fprintf (stderr, "-> copy(%s,%s)\n", from, to);
  51. #endif
  52.     if (noexec)
  53.     return;
  54.  
  55.     if ((fdin = open (from, O_RDONLY | O_BINARY)) < 0)
  56.     error (1, errno, "cannot open %s for copying", from);
  57.     if (fstat (fdin, &sb) < 0)
  58.     error (1, errno, "cannot fstat %s", from);
  59.     if ((fdout = open (to, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
  60.                        (int) sb.st_mode & 07777)) < 0)
  61.     error (1, errno, "cannot create %s for copying", to);
  62.     if (sb.st_size > 0)
  63.     {
  64.     char buf[BUFSIZ];
  65.     int n;
  66.  
  67.     for (;;) 
  68.     {
  69.         n = read (fdin, buf, sizeof(buf));
  70.         if (n == -1)
  71.         {
  72. #ifdef EINTR
  73.         if (errno == EINTR)
  74.             continue;
  75. #endif
  76.         error (1, errno, "cannot read file %s for copying", from);
  77.         }
  78.             else if (n == 0) 
  79.         break;
  80.   
  81.         if (write(fdout, buf, n) != n) {
  82.         error (1, errno, "cannot write file %s for copying", to);
  83.         }
  84.     }
  85.  
  86. #ifdef HAVE_FSYNC
  87.     if (fsync (fdout)) 
  88.         error (1, errno, "cannot fsync file %s after copying", to);
  89. #endif
  90.     }
  91.  
  92.     if (close (fdin) < 0) 
  93.     error (0, errno, "cannot close %s", from);
  94.     if (close (fdout) < 0)
  95.     error (1, errno, "cannot close %s", to);
  96.  
  97.     /* now, set the times for the copied file to match those of the original */
  98.     memset ((char *) &t, 0, sizeof (t));
  99.     t.actime = sb.st_atime;
  100.     t.modtime = sb.st_mtime;
  101.     (void) utime (to, &t);
  102. }
  103.  
  104. /*
  105.  * link a file, if possible.  Warning: the Windows NT version of this
  106.  * function just copies the file, so only use this function in ways
  107.  * that can deal with either a link or a copy.
  108.  */
  109. int
  110. link_file (from, to)
  111.     const char *from;
  112.     const char *to;
  113. {
  114.     copy_file (from, to);
  115.     return 0;
  116. }
  117.  
  118. /* FIXME-krp: these functions would benefit from caching the char * &
  119.    stat buf.  */
  120.  
  121. /*
  122.  * Returns non-zero if the argument file is a directory, or is a symbolic
  123.  * link which points to a directory.
  124.  */
  125. int
  126. isdir (file)
  127.     const char *file;
  128. {
  129.     struct stat sb;
  130.  
  131.     if (stat (file, &sb) < 0)
  132.     return (0);
  133.     return (S_ISDIR (sb.st_mode));
  134. }
  135.  
  136. /*
  137.  * Returns non-zero if the argument file is a symbolic link.
  138.  */
  139. int
  140. islink (file)
  141.     const char *file;
  142. {
  143. #ifdef S_ISLNK
  144.     struct stat sb;
  145.  
  146.     if (lstat (file, &sb) < 0)
  147.     return (0);
  148.     return (S_ISLNK (sb.st_mode));
  149. #else
  150.     return (0);
  151. #endif
  152. }
  153.  
  154. /*
  155.  * Returns non-zero if the argument file exists.
  156.  */
  157. int
  158. isfile (file)
  159.     const char *file;
  160. {
  161.     struct stat sb;
  162.  
  163.     if (stat (file, &sb) < 0)
  164.     return (0);
  165.     return (1);
  166. }
  167.  
  168. /*
  169.  * Returns non-zero if the argument file is readable.
  170.  * XXX - must be careful if "cvs" is ever made setuid!
  171.  */
  172. int
  173. isreadable (file)
  174.     const char *file;
  175. {
  176.     return (access (file, R_OK) != -1);
  177. }
  178.  
  179. /*
  180.  * Returns non-zero if the argument file is writable
  181.  * XXX - muct be careful if "cvs" is ever made setuid!
  182.  */
  183. int
  184. iswritable (file)
  185.     const char *file;
  186. {
  187.     return (access (file, W_OK) != -1);
  188. }
  189.  
  190. /*
  191.  * Returns non-zero if the argument file is accessable according to
  192.  * mode.  If compiled with SETXID_SUPPORT also works if cvs has setxid
  193.  * bits set.
  194.  */
  195. int
  196. isaccessible (file, mode)
  197.     const char *file;
  198.     const int mode;
  199. {
  200.     return access(file, mode) == 0;
  201. }
  202.  
  203.  
  204. /*
  205.  * Open a file and die if it fails
  206.  */
  207. FILE *
  208. open_file (name, mode)
  209.     const char *name;
  210.     const char *mode;
  211. {
  212.     FILE *fp;
  213.  
  214.     if ((fp = fopen (name, mode)) == NULL)
  215.     error (1, errno, "cannot open %s", name);
  216.     return (fp);
  217. }
  218.  
  219. /*
  220.  * Make a directory and die if it fails
  221.  */
  222. void
  223. make_directory (name)
  224.     const char *name;
  225. {
  226.     struct stat buf;
  227.  
  228.     if (stat (name, &buf) == 0 && (!S_ISDIR (buf.st_mode)))
  229.         error (0, 0, "%s already exists but is not a directory", name);
  230.     if (!noexec && mkdir (name) < 0)
  231.     error (1, errno, "cannot make directory %s", name);
  232. }
  233.  
  234. /*
  235.  * Make a path to the argument directory, printing a message if something
  236.  * goes wrong.
  237.  */
  238. void
  239. make_directories (name)
  240.     const char *name;
  241. {
  242.     char *cp;
  243.  
  244.     if (noexec)
  245.     return;
  246.  
  247.     if (mkdir (name) == 0 || errno == EACCESS)
  248.     return;
  249.     if (! existence_error (errno))
  250.     {
  251.     error (0, errno, "cannot make path to %s", name);
  252.     return;
  253.     }
  254.     if ((cp = strrchr (name, '/')) == NULL)
  255.     return;
  256.     *cp = '\0';
  257.     make_directories (name);
  258.     *cp++ = '/';
  259.     if (*cp == '\0')
  260.     return;
  261.     (void) mkdir (name);
  262. }
  263.  
  264. /* Create directory NAME if it does not already exist; fatal error for
  265.    other errors.  Returns 0 if directory was created; 1 if it already
  266.    existed.  */
  267. int
  268. mkdir_if_needed (name)
  269.     char *name;
  270. {
  271.     if (mkdir (name, 0777) < 0)
  272.     {
  273.     /* Now, let me get this straight.  In IBM C/C++
  274.        under OS/2, the error string for EEXIST is:
  275.  
  276.            "The file already exists",
  277.  
  278.        and the error string for EACCESS is:
  279.  
  280.            "The file or directory specified is read-only".
  281.  
  282.        Nonetheless, mkdir() will set EACCESS if the
  283.        directory *exists*, according both to the
  284.        documentation and its actual behavior.
  285.  
  286.        I'm sure that this made sense, to someone,
  287.        somewhere, sometime.  Just not me, here, now.  */
  288.     if (errno != EEXIST
  289. #ifdef EACCESS
  290.         && errno != EACCESS
  291. #endif
  292.         )
  293.         error (1, errno, "cannot make directory %s", name);
  294.     return 1;
  295.     }
  296.     return 0;
  297. }
  298.  
  299. /*
  300.  * Change the mode of a file, either adding write permissions, or removing
  301.  * all write permissions.  Adding write permissions honors the current umask
  302.  * setting.
  303.  */
  304. void
  305. xchmod (fname, writable)
  306.     char *fname;
  307.     int writable;
  308. {
  309.     char *attrib_cmd;
  310.     char *attrib_option;
  311.     char *whole_cmd;
  312.     char *p;
  313.     char *q;
  314.  
  315.     if (!isfile (fname))
  316.     return ENOENT;
  317.  
  318.     attrib_cmd = "attrib "; /* No, really? */
  319.  
  320.     if (writable)
  321.         attrib_option = "-r ";  /* make writeable */
  322.     else
  323.         attrib_option = "+r ";  /* make read-only */
  324.         
  325.     whole_cmd = xmalloc (strlen (attrib_cmd)
  326.                          + strlen (attrib_option)
  327.                          + strlen (fname)
  328.                          + 1);
  329.  
  330.     strcpy (whole_cmd, attrib_cmd);
  331.     strcat (whole_cmd, attrib_option);
  332.  
  333.     /* Copy fname to the end of whole_cmd, translating / to \.
  334.        Attrib doesn't take / but many parts of CVS rely
  335.        on being able to use it.  */
  336.     p = whole_cmd + strlen (whole_cmd);
  337.     q = fname;
  338.     while (*q)
  339.     {
  340.     if (*q == '/')
  341.         *p++ = '\\';
  342.     else
  343.         *p++ = *q;
  344.     ++q;
  345.     }
  346.     *p = '\0';
  347.  
  348.     system (whole_cmd);
  349.     free (whole_cmd);
  350. }
  351.  
  352.  
  353. /* Read the value of a symbolic link.
  354.    Under OS/2, this function always returns EINVAL.  */
  355. int
  356. readlink (char *path, char *buf, int buf_size)
  357. {
  358.     errno = EINVAL;
  359.     return -1;
  360. }
  361.  
  362. /*
  363.  * unlink a file, if possible.
  364.  */
  365. int
  366. unlink_file (f)
  367.     const char *f;
  368. {
  369.     if (trace)
  370. #ifdef SERVER_SUPPORT
  371.     (void) fprintf (stderr, "%c-> unlink(%s)\n",
  372.             (server_active) ? 'S' : ' ', f);
  373. #else
  374.     (void) fprintf (stderr, "-> unlink(%s)\n", f);
  375. #endif
  376.     if (noexec)
  377.     return (0);
  378.  
  379.    /* Win32 unlink is stupid - it fails if the file is read-only.
  380.     * OS/2 is similarly stupid.  It does have a remove() function,
  381.     * but the documentation does not make clear why remove() is or
  382.     * isn't preferable to unlink().  I'll use unlink() because the
  383.     * name is closer to our interface, what the heck.  Also, we know
  384.     * unlink()'s error code when trying to remove a directory.
  385.     */
  386.     xchmod (f, 1);
  387.     return (unlink (f));
  388. }
  389.  
  390. /*
  391.  * Unlink a file or dir, if possible.  If it is a directory do a deep
  392.  * removal of all of the files in the directory.  Return -1 on error
  393.  * (in which case errno is set).
  394.  */
  395. int
  396. unlink_file_dir (f)
  397.     const char *f;
  398. {
  399.     if (trace)
  400. #ifdef SERVER_SUPPORT
  401.     (void) fprintf (stderr, "%c-> unlink_file_dir(%s)\n",
  402.             (server_active) ? 'S' : ' ', f);
  403. #else
  404.     (void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f);
  405. #endif
  406.     if (noexec)
  407.     return (0);
  408.  
  409.     if (unlink_file (f) != 0)
  410.     {
  411.     /* under OS/2, unlink returns EACCESS if the path
  412.        is a directory.  */
  413.         if (errno == EACCESS)
  414.                 return deep_remove_dir (f);
  415.         else
  416.         /* The file wasn't a directory and some other
  417.          * error occured
  418.          */
  419.                 return -1;
  420.     }
  421.     /* We were able to remove the file from the disk */
  422.     return 0;
  423. }
  424.  
  425. /* Remove a directory and everything it contains.  Returns 0 for
  426.  * success, -1 for failure (in which case errno is set).
  427.  */
  428.  
  429. static int
  430. deep_remove_dir (path)
  431.     const char *path;
  432. {
  433.     DIR          *dirp;
  434.     struct dirent *dp;
  435.     char       buf[PATH_MAX];
  436.  
  437.     if ( rmdir (path) != 0 && errno == EACCESS )
  438.     {
  439.     if ((dirp = opendir (path)) == NULL)
  440.         /* If unable to open the directory return
  441.          * an error
  442.          */
  443.         return -1;
  444.  
  445.     while ((dp = readdir (dirp)) != NULL)
  446.     {
  447.         if (strcmp (dp->d_name, ".") == 0 ||
  448.             strcmp (dp->d_name, "..") == 0)
  449.         continue;
  450.  
  451.         sprintf (buf, "%s/%s", path, dp->d_name);
  452.  
  453.         if (unlink_file (buf) != 0 )
  454.         {
  455.         if (errno == EACCES)
  456.         {
  457.             if (deep_remove_dir (buf))
  458.             {
  459.             closedir (dirp);
  460.             return -1;
  461.             }
  462.         }
  463.         else
  464.         {
  465.             /* buf isn't a directory, or there are
  466.              * some sort of permision problems
  467.              */
  468.             closedir (dirp);
  469.             return -1;
  470.         }
  471.         }
  472.     }
  473.     closedir (dirp);
  474.     return rmdir (path);
  475.     }
  476.     /* Was able to remove the directory return 0 */
  477.     return 0;
  478. }
  479.  
  480.  
  481. /*
  482.  * Rename a file and die if it fails
  483.  */
  484. void
  485. rename_file (from, to)
  486.     const char *from;
  487.     const char *to;
  488. {
  489.     if (trace)
  490. #ifdef SERVER_SUPPORT
  491.     (void) fprintf (stderr, "%c-> rename(%s,%s)\n",
  492.             (server_active) ? 'S' : ' ', from, to);
  493. #else
  494.     (void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
  495. #endif
  496.     if (noexec)
  497.     return;
  498.  
  499.     unlink_file (to);
  500.     if (rename (from, to) != 0)
  501.     error (1, errno, "cannot rename file %s to %s", from, to);
  502. }
  503.  
  504.  
  505. /* Read NCHARS bytes from descriptor FD into BUF.
  506.    Return the number of characters successfully read.
  507.    The number returned is always NCHARS unless end-of-file or error.  */
  508. static size_t
  509. block_read (fd, buf, nchars)
  510.     int fd;
  511.     char *buf;
  512.     size_t nchars;
  513. {
  514.     char *bp = buf;
  515.     size_t nread;
  516.  
  517.     do 
  518.     {
  519.     nread = read (fd, bp, nchars);
  520.     if (nread == (size_t)-1)
  521.     {
  522. #ifdef EINTR
  523.         if (errno == EINTR)
  524.         continue;
  525. #endif
  526.         return (size_t)-1;
  527.     }
  528.  
  529.     if (nread == 0)
  530.         break; 
  531.  
  532.     bp += nread;
  533.     nchars -= nread;
  534.     } while (nchars != 0);
  535.  
  536.     return bp - buf;
  537.  
  538.     
  539. /*
  540.  * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
  541.  */
  542. int
  543. xcmp (file1, file2)
  544.     const char *file1;
  545.     const char *file2;
  546. {
  547.     char *buf1, *buf2;
  548.     struct stat sb1, sb2;
  549.     int fd1, fd2;
  550.     int ret;
  551.  
  552.     if ((fd1 = open (file1, O_RDONLY | O_BINARY)) < 0)
  553.     error (1, errno, "cannot open file %s for comparing", file1);
  554.     if ((fd2 = open (file2, O_RDONLY | O_BINARY)) < 0)
  555.     error (1, errno, "cannot open file %s for comparing", file2);
  556.     if (fstat (fd1, &sb1) < 0)
  557.     error (1, errno, "cannot fstat %s", file1);
  558.     if (fstat (fd2, &sb2) < 0)
  559.     error (1, errno, "cannot fstat %s", file2);
  560.  
  561.     /* A generic file compare routine might compare st_dev & st_ino here 
  562.        to see if the two files being compared are actually the same file.
  563.        But that won't happen in CVS, so we won't bother. */
  564.  
  565.     if (sb1.st_size != sb2.st_size)
  566.     ret = 1;
  567.     else if (sb1.st_size == 0)
  568.     ret = 0;
  569.     else
  570.     {
  571.     /* FIXME: compute the optimal buffer size by computing the least
  572.        common multiple of the files st_blocks field */
  573.     size_t buf_size = 8 * 1024;
  574.     size_t read1;
  575.     size_t read2;
  576.  
  577.     buf1 = xmalloc (buf_size);
  578.     buf2 = xmalloc (buf_size);
  579.  
  580.     do 
  581.     {
  582.         read1 = block_read (fd1, buf1, buf_size);
  583.         if (read1 == (size_t)-1)
  584.         error (1, errno, "cannot read file %s for comparing", file1);
  585.  
  586.         read2 = block_read (fd2, buf2, buf_size);
  587.         if (read2 == (size_t)-1)
  588.         error (1, errno, "cannot read file %s for comparing", file2);
  589.  
  590.         /* assert (read1 == read2); */
  591.  
  592.         ret = memcmp(buf1, buf2, read1);
  593.     } while (ret == 0 && read1 == buf_size);
  594.  
  595.     free (buf1);
  596.     free (buf2);
  597.     }
  598.     
  599.     (void) close (fd1);
  600.     (void) close (fd2);
  601.     return (ret);
  602. }
  603.  
  604.  
  605. /* The equivalence class mapping for filenames.
  606.    OS/2 filenames are case-insensitive, but case-preserving.  Both /
  607.    and \ are path element separators. 
  608.    Thus, this table maps both upper and lower case to lower case, and
  609.    both / and \ to /.  
  610.  
  611.    Much thanks to Jim Blandy, who already invented this wheel in the
  612.    Windows NT port. */
  613.  
  614. #if 0
  615. main ()
  616. {
  617.   int c;
  618.  
  619.   for (c = 0; c < 256; c++)
  620.     {
  621.       int t;
  622.  
  623.       if (c == '\\')
  624.         t = '/';
  625.       else
  626.         t = tolower (c);
  627.       
  628.       if ((c & 0x7) == 0x0)
  629.          printf ("    ");
  630.       printf ("0x%02x,", t);
  631.       if ((c & 0x7) == 0x7)
  632.          putchar ('\n');
  633.       else if ((c & 0x7) == 0x3)
  634.          putchar (' ');
  635.     }
  636. }
  637. #endif
  638.  
  639.  
  640. unsigned char
  641. OS2_filename_classes[] =
  642. {
  643.     0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07,
  644.     0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f,
  645.     0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17,
  646.     0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f,
  647.     0x20,0x21,0x22,0x23, 0x24,0x25,0x26,0x27,
  648.     0x28,0x29,0x2a,0x2b, 0x2c,0x2d,0x2e,0x2f,
  649.     0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
  650.     0x38,0x39,0x3a,0x3b, 0x3c,0x3d,0x3e,0x3f,
  651.     0x40,0x61,0x62,0x63, 0x64,0x65,0x66,0x67,
  652.     0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f,
  653.     0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77,
  654.     0x78,0x79,0x7a,0x5b, 0x2f,0x5d,0x5e,0x5f,
  655.     0x60,0x61,0x62,0x63, 0x64,0x65,0x66,0x67,
  656.     0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f,
  657.     0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77,
  658.     0x78,0x79,0x7a,0x7b, 0x7c,0x7d,0x7e,0x7f,
  659.     0x80,0x81,0x82,0x83, 0x84,0x85,0x86,0x87,
  660.     0x88,0x89,0x8a,0x8b, 0x8c,0x8d,0x8e,0x8f,
  661.     0x90,0x91,0x92,0x93, 0x94,0x95,0x96,0x97,
  662.     0x98,0x99,0x9a,0x9b, 0x9c,0x9d,0x9e,0x9f,
  663.     0xa0,0xa1,0xa2,0xa3, 0xa4,0xa5,0xa6,0xa7,
  664.     0xa8,0xa9,0xaa,0xab, 0xac,0xad,0xae,0xaf,
  665.     0xb0,0xb1,0xb2,0xb3, 0xb4,0xb5,0xb6,0xb7,
  666.     0xb8,0xb9,0xba,0xbb, 0xbc,0xbd,0xbe,0xbf,
  667.     0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7,
  668.     0xc8,0xc9,0xca,0xcb, 0xcc,0xcd,0xce,0xcf,
  669.     0xd0,0xd1,0xd2,0xd3, 0xd4,0xd5,0xd6,0xd7,
  670.     0xd8,0xd9,0xda,0xdb, 0xdc,0xdd,0xde,0xdf,
  671.     0xe0,0xe1,0xe2,0xe3, 0xe4,0xe5,0xe6,0xe7,
  672.     0xe8,0xe9,0xea,0xeb, 0xec,0xed,0xee,0xef,
  673.     0xf0,0xf1,0xf2,0xf3, 0xf4,0xf5,0xf6,0xf7,
  674.     0xf8,0xf9,0xfa,0xfb, 0xfc,0xfd,0xfe,0xff,
  675. };
  676.  
  677. /* Like strcmp, but with the appropriate tweaks for file names.
  678.    Under OS/2, filenames are case-insensitive but case-preserving, and
  679.    both \ and / are path element separators.  */ 
  680. int
  681. fncmp (const char *n1, const char *n2)
  682. {
  683.     while (*n1 && *n2
  684.            && (OS2_filename_classes[(unsigned char) *n1]
  685.            == OS2_filename_classes[(unsigned char) *n2]))
  686.         n1++, n2++;
  687.     return (OS2_filename_classes[(unsigned char) *n1]
  688.             - OS2_filename_classes[(unsigned char) *n2]);
  689. }
  690.  
  691. /* Fold characters in FILENAME to their canonical forms.  
  692.    If FOLD_FN_CHAR is not #defined, the system provides a default
  693.    definition for this.  */
  694. void
  695. fnfold (char *filename)
  696. {
  697.     while (*filename)
  698.     {
  699.         *filename = FOLD_FN_CHAR (*filename);
  700.     filename++;
  701.     }
  702. }
  703.  
  704.  
  705. /* Generate a unique temporary filename.  Returns a pointer to a newly
  706.    malloc'd string containing the name.  Returns successfully or not at
  707.    all.  */
  708. char *
  709. cvs_temp_name ()
  710. {
  711.     char value[L_tmpnam + 1];
  712.     char *retval;
  713.  
  714.     /* FIXME: Does OS/2 have some equivalent to TMPDIR?  */
  715.     retval = tmpnam (value);
  716.     if (retval == NULL)
  717.     error (1, errno, "cannot generate temporary filename");
  718.     return xstrdup (retval);
  719. }
  720.  
  721. /* Return non-zero iff FILENAME is absolute.
  722.    Trivial under Unix, but more complicated under other systems.  */
  723. int
  724. isabsolute (filename)
  725.     const char *filename;
  726. {
  727.     return (ISDIRSEP (filename[0])
  728.             || (filename[0] != '\0'
  729.                 && filename[1] == ':'
  730.                 && ISDIRSEP (filename[2])));
  731. }
  732.  
  733. /* Return a pointer into PATH's last component.  */
  734. char *
  735. last_component (char *path)
  736. {
  737.     char *scan;
  738.     char *last = 0;
  739.  
  740.     for (scan = path; *scan; scan++)
  741.         if (ISDIRSEP (*scan))
  742.         last = scan;
  743.  
  744.     if (last)
  745.         return last + 1;
  746.     else
  747.         return path;
  748. }
  749.  
  750.  
  751. /* Read data from INFILE, and copy it to OUTFILE. 
  752.    Open INFILE using INFLAGS, and OUTFILE using OUTFLAGS.
  753.    This is useful for converting between CRLF and LF line formats.  */
  754. void
  755. convert_file (char *infile,  int inflags,
  756.           char *outfile, int outflags)
  757. {
  758.     int infd, outfd;
  759.     char buf[8192];
  760.     int len;
  761.  
  762.     if ((infd = open (infile, inflags, S_IREAD | S_IWRITE)) < 0)
  763.         error (1, errno, "couldn't read %s", infile);
  764.     if ((outfd = open (outfile, outflags, S_IREAD | S_IWRITE)) < 0)
  765.         error (1, errno, "couldn't write %s", outfile);
  766.  
  767.     while ((len = read (infd, buf, sizeof (buf))) > 0)
  768.         if (write (outfd, buf, len) < 0)
  769.         error (1, errno, "error writing %s", outfile);
  770.     if (len < 0)
  771.         error (1, errno, "error reading %s", infile);
  772.  
  773.     if (close (outfd) < 0)
  774.         error (0, errno, "warning: couldn't close %s", outfile);
  775.     if (close (infd) < 0)
  776.         error (0, errno, "warning: couldn't close %s", infile);
  777. }
  778.  
  779. /* Return the home directory.  Returns a pointer to storage
  780.    managed by this function or its callees (currently getenv).  */
  781. char *
  782. get_homedir ()
  783. {
  784.     return getenv ("HOME");
  785. }
  786.  
  787. /* See cvs.h for description.  */
  788. void
  789. expand_wild (argc, argv, pargc, pargv)
  790.     int argc;
  791.     char **argv;
  792.     int *pargc;
  793.     char ***pargv;
  794. {
  795.     int i;
  796.     int new_argc;
  797.     char **new_argv;
  798.     /* Allocated size of new_argv.  We arrange it so there is always room for
  799.        one more element.  */
  800.     int max_new_argc;
  801.  
  802.     new_argc = 0;
  803.     /* Add one so this is never zero.  */
  804.     max_new_argc = argc + 1;
  805.     new_argv = (char **) xmalloc (max_new_argc * sizeof (char *));
  806.     for (i = 0; i < argc; ++i)
  807.     {
  808.     HDIR          FindHandle = 0x0001;
  809.     FILEFINDBUF3  FindBuffer;
  810.     ULONG         FindCount = 1;
  811.     APIRET        rc;          /* Return code */
  812. #define ALL_FILES (FILE_ARCHIVED|FILE_DIRECTORY|FILE_SYSTEM|FILE_HIDDEN|FILE_READONLY) 
  813.  
  814.     rc = DosFindFirst(argv[i],               /* File pattern */
  815.               &FindHandle,           /* Directory search handle */
  816.               ALL_FILES,             /* Search attribute */
  817.               (PVOID) &FindBuffer,   /* Result buffer */
  818.               sizeof(FindBuffer),    /* Result buffer length */
  819.               &FindCount,            /* Number of entries to find */
  820.               FIL_STANDARD);     /* Return level 1 file info */
  821.  
  822.     if (rc != 0)
  823.     {
  824.         if (rc == ERROR_FILE_NOT_FOUND)
  825.         {
  826.         /* No match.  The file specified didn't contain a wildcard (in which case
  827.            we clearly should return it unchanged), or it contained a wildcard which
  828.            didn't match (in which case it might be better for it to be an error,
  829.            but we don't try to do that).  */
  830.         new_argv [new_argc++] = xstrdup (argv[i]);
  831.         if (new_argc == max_new_argc)
  832.         {
  833.             max_new_argc *= 2;
  834.             new_argv = xrealloc (new_argv, max_new_argc * sizeof (char *));
  835.         }
  836.         }
  837.         else
  838.         {
  839.         error (1, rc, "cannot find %s", argv[i]);
  840.         }
  841.     }
  842.     else
  843.     {
  844.         while (1)
  845.         {
  846.         /*
  847.          * Don't match ".", "..", and files starting with '.'
  848.          * (unless pattern also starts with '.').  This is
  849.          * (more or less) what standard Unix globbing does.
  850.          */
  851.         if ((strcmp(FindBuffer.achName, ".") != 0) &&
  852.             (strcmp(FindBuffer.achName, "..") != 0) &&
  853.             ((argv[i][0] == '.') || (FindBuffer.achName[0] != '.')))
  854.         {
  855.             new_argv [new_argc++] = xstrdup (FindBuffer.achName);
  856.             if (new_argc == max_new_argc)
  857.             {
  858.             max_new_argc *= 2;
  859.             new_argv = xrealloc (new_argv, max_new_argc * sizeof (char *));
  860.             }
  861.         }
  862.         
  863.         rc = DosFindNext(FindHandle,
  864.                      (PVOID) &FindBuffer,
  865.                      sizeof(FindBuffer),
  866.                      &FindCount);
  867.         if (rc == ERROR_NO_MORE_FILES)
  868.             break;
  869.         else if (rc != NO_ERROR)
  870.             error (1, rc, "cannot find %s", argv[i]);
  871.         }
  872.         rc = DosFindClose(FindHandle);
  873.         if (rc != 0)
  874.         error (1, rc, "cannot close %s", argv[i]);
  875.     }
  876.     }
  877.     *pargc = new_argc;
  878.     *pargv = new_argv;
  879. }
  880.