13142e03fSSimon Schubert /* filesubr.c --- subroutines for dealing with files
23142e03fSSimon Schubert Jim Blandy <jimb@cyclic.com>
33142e03fSSimon Schubert
43142e03fSSimon Schubert This file is part of GNU CVS.
53142e03fSSimon Schubert
63142e03fSSimon Schubert GNU CVS is free software; you can redistribute it and/or modify it
73142e03fSSimon Schubert under the terms of the GNU General Public License as published by the
83142e03fSSimon Schubert Free Software Foundation; either version 2, or (at your option) any
93142e03fSSimon Schubert later version.
103142e03fSSimon Schubert
113142e03fSSimon Schubert This program is distributed in the hope that it will be useful,
123142e03fSSimon Schubert but WITHOUT ANY WARRANTY; without even the implied warranty of
133142e03fSSimon Schubert MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
143142e03fSSimon Schubert GNU General Public License for more details. */
153142e03fSSimon Schubert
163142e03fSSimon Schubert /* These functions were moved out of subr.c because they need different
173142e03fSSimon Schubert definitions under operating systems (like, say, Windows NT) with different
183142e03fSSimon Schubert file system semantics. */
193142e03fSSimon Schubert
203142e03fSSimon Schubert #include "cvs.h"
213142e03fSSimon Schubert #include "lstat.h"
223142e03fSSimon Schubert #include "save-cwd.h"
233142e03fSSimon Schubert #include "xsize.h"
243142e03fSSimon Schubert
253142e03fSSimon Schubert static int deep_remove_dir (const char *path);
263142e03fSSimon Schubert
273142e03fSSimon Schubert /*
283142e03fSSimon Schubert * Copies "from" to "to".
293142e03fSSimon Schubert */
303142e03fSSimon Schubert void
copy_file(const char * from,const char * to)313142e03fSSimon Schubert copy_file (const char *from, const char *to)
323142e03fSSimon Schubert {
333142e03fSSimon Schubert struct stat sb;
343142e03fSSimon Schubert struct utimbuf t;
353142e03fSSimon Schubert int fdin, fdout;
363142e03fSSimon Schubert ssize_t rsize;
373142e03fSSimon Schubert
383142e03fSSimon Schubert TRACE (TRACE_FUNCTION, "copy(%s,%s)", from, to);
393142e03fSSimon Schubert
403142e03fSSimon Schubert if (noexec)
413142e03fSSimon Schubert return;
423142e03fSSimon Schubert
433142e03fSSimon Schubert /* If the file to be copied is a link or a device, then just create
443142e03fSSimon Schubert the new link or device appropriately. */
453142e03fSSimon Schubert if ((rsize = islink (from)) > 0)
463142e03fSSimon Schubert {
473142e03fSSimon Schubert char *source = Xreadlink (from, rsize);
483142e03fSSimon Schubert symlink (source, to);
493142e03fSSimon Schubert free (source);
503142e03fSSimon Schubert return;
513142e03fSSimon Schubert }
523142e03fSSimon Schubert
533142e03fSSimon Schubert if (isdevice (from))
543142e03fSSimon Schubert {
553142e03fSSimon Schubert #if defined(HAVE_MKNOD) && defined(HAVE_STRUCT_STAT_ST_RDEV)
563142e03fSSimon Schubert if (stat (from, &sb) < 0)
573142e03fSSimon Schubert error (1, errno, "cannot stat %s", from);
583142e03fSSimon Schubert mknod (to, sb.st_mode, sb.st_rdev);
593142e03fSSimon Schubert #else
603142e03fSSimon Schubert error (1, 0, "cannot copy device files on this system (%s)", from);
613142e03fSSimon Schubert #endif
623142e03fSSimon Schubert }
633142e03fSSimon Schubert else
643142e03fSSimon Schubert {
653142e03fSSimon Schubert /* Not a link or a device... probably a regular file. */
663142e03fSSimon Schubert if ((fdin = open (from, O_RDONLY)) < 0)
673142e03fSSimon Schubert error (1, errno, "cannot open %s for copying", from);
683142e03fSSimon Schubert if (fstat (fdin, &sb) < 0)
693142e03fSSimon Schubert error (1, errno, "cannot fstat %s", from);
703142e03fSSimon Schubert if ((fdout = creat (to, (int) sb.st_mode & 07777)) < 0)
713142e03fSSimon Schubert error (1, errno, "cannot create %s for copying", to);
723142e03fSSimon Schubert if (sb.st_size > 0)
733142e03fSSimon Schubert {
743142e03fSSimon Schubert char buf[BUFSIZ];
753142e03fSSimon Schubert int n;
763142e03fSSimon Schubert
773142e03fSSimon Schubert for (;;)
783142e03fSSimon Schubert {
793142e03fSSimon Schubert n = read (fdin, buf, sizeof(buf));
803142e03fSSimon Schubert if (n == -1)
813142e03fSSimon Schubert {
823142e03fSSimon Schubert #ifdef EINTR
833142e03fSSimon Schubert if (errno == EINTR)
843142e03fSSimon Schubert continue;
853142e03fSSimon Schubert #endif
863142e03fSSimon Schubert error (1, errno, "cannot read file %s for copying", from);
873142e03fSSimon Schubert }
883142e03fSSimon Schubert else if (n == 0)
893142e03fSSimon Schubert break;
903142e03fSSimon Schubert
913142e03fSSimon Schubert if (write(fdout, buf, n) != n) {
923142e03fSSimon Schubert error (1, errno, "cannot write file %s for copying", to);
933142e03fSSimon Schubert }
943142e03fSSimon Schubert }
953142e03fSSimon Schubert }
963142e03fSSimon Schubert
973142e03fSSimon Schubert if (close (fdin) < 0)
983142e03fSSimon Schubert error (0, errno, "cannot close %s", from);
993142e03fSSimon Schubert if (close (fdout) < 0)
1003142e03fSSimon Schubert error (1, errno, "cannot close %s", to);
1013142e03fSSimon Schubert }
1023142e03fSSimon Schubert
1033142e03fSSimon Schubert /* preserve last access & modification times */
1043142e03fSSimon Schubert memset ((char *) &t, 0, sizeof (t));
1053142e03fSSimon Schubert t.actime = sb.st_atime;
1063142e03fSSimon Schubert t.modtime = sb.st_mtime;
1073142e03fSSimon Schubert (void) utime (to, &t);
1083142e03fSSimon Schubert }
1093142e03fSSimon Schubert
1103142e03fSSimon Schubert
1113142e03fSSimon Schubert
1123142e03fSSimon Schubert /* FIXME-krp: these functions would benefit from caching the char * &
1133142e03fSSimon Schubert stat buf. */
1143142e03fSSimon Schubert
1153142e03fSSimon Schubert /*
1163142e03fSSimon Schubert * Returns true if the argument file is a directory, or is a symbolic
1173142e03fSSimon Schubert * link which points to a directory.
1183142e03fSSimon Schubert */
1193142e03fSSimon Schubert bool
isdir(const char * file)1203142e03fSSimon Schubert isdir (const char *file)
1213142e03fSSimon Schubert {
1223142e03fSSimon Schubert struct stat sb;
1233142e03fSSimon Schubert
1243142e03fSSimon Schubert if (stat (file, &sb) < 0)
1253142e03fSSimon Schubert return false;
1263142e03fSSimon Schubert return S_ISDIR (sb.st_mode);
1273142e03fSSimon Schubert }
1283142e03fSSimon Schubert
1293142e03fSSimon Schubert
1303142e03fSSimon Schubert
1313142e03fSSimon Schubert /*
1323142e03fSSimon Schubert * Returns 0 if the argument file is not a symbolic link.
1333142e03fSSimon Schubert * Returns size of the link if it is a symbolic link.
1343142e03fSSimon Schubert */
1353142e03fSSimon Schubert ssize_t
islink(const char * file)1363142e03fSSimon Schubert islink (const char *file)
1373142e03fSSimon Schubert {
1383142e03fSSimon Schubert ssize_t retsize = 0;
1393142e03fSSimon Schubert #ifdef S_ISLNK
1403142e03fSSimon Schubert struct stat sb;
1413142e03fSSimon Schubert
1423142e03fSSimon Schubert if ((lstat (file, &sb) >= 0) && S_ISLNK (sb.st_mode))
1433142e03fSSimon Schubert retsize = sb.st_size;
1443142e03fSSimon Schubert #endif
1453142e03fSSimon Schubert return retsize;
1463142e03fSSimon Schubert }
1473142e03fSSimon Schubert
1483142e03fSSimon Schubert
1493142e03fSSimon Schubert
1503142e03fSSimon Schubert /*
1513142e03fSSimon Schubert * Returns true if the argument file is a block or
1523142e03fSSimon Schubert * character special device.
1533142e03fSSimon Schubert */
1543142e03fSSimon Schubert bool
isdevice(const char * file)1553142e03fSSimon Schubert isdevice (const char *file)
1563142e03fSSimon Schubert {
1573142e03fSSimon Schubert struct stat sb;
1583142e03fSSimon Schubert
1593142e03fSSimon Schubert if (lstat (file, &sb) < 0)
1603142e03fSSimon Schubert return false;
1613142e03fSSimon Schubert #ifdef S_ISBLK
1623142e03fSSimon Schubert if (S_ISBLK (sb.st_mode))
1633142e03fSSimon Schubert return true;
1643142e03fSSimon Schubert #endif
1653142e03fSSimon Schubert #ifdef S_ISCHR
1663142e03fSSimon Schubert if (S_ISCHR (sb.st_mode))
1673142e03fSSimon Schubert return true;
1683142e03fSSimon Schubert #endif
1693142e03fSSimon Schubert return false;
1703142e03fSSimon Schubert }
1713142e03fSSimon Schubert
1723142e03fSSimon Schubert
1733142e03fSSimon Schubert
1743142e03fSSimon Schubert /*
1753142e03fSSimon Schubert * Returns true if the argument file exists.
1763142e03fSSimon Schubert */
1773142e03fSSimon Schubert bool
isfile(const char * file)1783142e03fSSimon Schubert isfile (const char *file)
1793142e03fSSimon Schubert {
1803142e03fSSimon Schubert return isaccessible (file, F_OK);
1813142e03fSSimon Schubert }
1823142e03fSSimon Schubert
1833142e03fSSimon Schubert
1843142e03fSSimon Schubert
1853142e03fSSimon Schubert /*
1863142e03fSSimon Schubert * Returns non-zero if the argument file is readable.
1873142e03fSSimon Schubert */
1883142e03fSSimon Schubert bool
isreadable(const char * file)1893142e03fSSimon Schubert isreadable (const char *file)
1903142e03fSSimon Schubert {
1913142e03fSSimon Schubert return isaccessible (file, R_OK);
1923142e03fSSimon Schubert }
1933142e03fSSimon Schubert
1943142e03fSSimon Schubert
1953142e03fSSimon Schubert
1963142e03fSSimon Schubert /*
1973142e03fSSimon Schubert * Returns non-zero if the argument file is writable.
1983142e03fSSimon Schubert */
1993142e03fSSimon Schubert bool
iswritable(const char * file)2003142e03fSSimon Schubert iswritable (const char *file)
2013142e03fSSimon Schubert {
2023142e03fSSimon Schubert return isaccessible (file, W_OK);
2033142e03fSSimon Schubert }
2043142e03fSSimon Schubert
2053142e03fSSimon Schubert
2063142e03fSSimon Schubert
2073142e03fSSimon Schubert /*
2083142e03fSSimon Schubert * Returns true if the argument file is accessable according to
2093142e03fSSimon Schubert * mode. If compiled with SETXID_SUPPORT also works if cvs has setxid
2103142e03fSSimon Schubert * bits set.
2113142e03fSSimon Schubert */
2123142e03fSSimon Schubert bool
isaccessible(const char * file,const int mode)2133142e03fSSimon Schubert isaccessible (const char *file, const int mode)
2143142e03fSSimon Schubert {
2153142e03fSSimon Schubert #ifdef SETXID_SUPPORT
2163142e03fSSimon Schubert struct stat sb;
2173142e03fSSimon Schubert int umask = 0;
2183142e03fSSimon Schubert int gmask = 0;
2193142e03fSSimon Schubert int omask = 0;
2203142e03fSSimon Schubert int uid, mask;
2213142e03fSSimon Schubert
2223142e03fSSimon Schubert if (stat (file, &sb)== -1)
2233142e03fSSimon Schubert return false;
2243142e03fSSimon Schubert if (mode == F_OK)
2253142e03fSSimon Schubert return true;
2263142e03fSSimon Schubert
2273142e03fSSimon Schubert uid = geteuid();
2283142e03fSSimon Schubert if (uid == 0) /* superuser */
2293142e03fSSimon Schubert {
2303142e03fSSimon Schubert if (!(mode & X_OK) || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
2313142e03fSSimon Schubert return true;
2323142e03fSSimon Schubert
2333142e03fSSimon Schubert errno = EACCES;
2343142e03fSSimon Schubert return false;
2353142e03fSSimon Schubert }
2363142e03fSSimon Schubert
2373142e03fSSimon Schubert if (mode & R_OK)
2383142e03fSSimon Schubert {
2393142e03fSSimon Schubert umask |= S_IRUSR;
2403142e03fSSimon Schubert gmask |= S_IRGRP;
2413142e03fSSimon Schubert omask |= S_IROTH;
2423142e03fSSimon Schubert }
2433142e03fSSimon Schubert if (mode & W_OK)
2443142e03fSSimon Schubert {
2453142e03fSSimon Schubert umask |= S_IWUSR;
2463142e03fSSimon Schubert gmask |= S_IWGRP;
2473142e03fSSimon Schubert omask |= S_IWOTH;
2483142e03fSSimon Schubert }
2493142e03fSSimon Schubert if (mode & X_OK)
2503142e03fSSimon Schubert {
2513142e03fSSimon Schubert umask |= S_IXUSR;
2523142e03fSSimon Schubert gmask |= S_IXGRP;
2533142e03fSSimon Schubert omask |= S_IXOTH;
2543142e03fSSimon Schubert }
2553142e03fSSimon Schubert
2563142e03fSSimon Schubert mask = sb.st_uid == uid ? umask : sb.st_gid == getegid() ? gmask : omask;
2573142e03fSSimon Schubert if ((sb.st_mode & mask) == mask)
2583142e03fSSimon Schubert return true;
2593142e03fSSimon Schubert errno = EACCES;
2603142e03fSSimon Schubert return false;
2613142e03fSSimon Schubert #else /* !SETXID_SUPPORT */
2623142e03fSSimon Schubert return access (file, mode) == 0;
2633142e03fSSimon Schubert #endif /* SETXID_SUPPORT */
2643142e03fSSimon Schubert }
2653142e03fSSimon Schubert
2663142e03fSSimon Schubert
2673142e03fSSimon Schubert
2683142e03fSSimon Schubert /*
2693142e03fSSimon Schubert * Make a directory and die if it fails
2703142e03fSSimon Schubert */
2713142e03fSSimon Schubert void
make_directory(const char * name)2723142e03fSSimon Schubert make_directory (const char *name)
2733142e03fSSimon Schubert {
2743142e03fSSimon Schubert struct stat sb;
2753142e03fSSimon Schubert
2763142e03fSSimon Schubert if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode)))
2773142e03fSSimon Schubert error (0, 0, "%s already exists but is not a directory", name);
2783142e03fSSimon Schubert if (!noexec && mkdir (name, 0777) < 0)
2793142e03fSSimon Schubert error (1, errno, "cannot make directory %s", name);
2803142e03fSSimon Schubert }
2813142e03fSSimon Schubert
2823142e03fSSimon Schubert /*
2833142e03fSSimon Schubert * Make a path to the argument directory, printing a message if something
2843142e03fSSimon Schubert * goes wrong.
2853142e03fSSimon Schubert */
2863142e03fSSimon Schubert void
make_directories(const char * name)2873142e03fSSimon Schubert make_directories (const char *name)
2883142e03fSSimon Schubert {
2893142e03fSSimon Schubert char *cp;
2903142e03fSSimon Schubert
2913142e03fSSimon Schubert if (noexec)
2923142e03fSSimon Schubert return;
2933142e03fSSimon Schubert
2943142e03fSSimon Schubert if (mkdir (name, 0777) == 0 || errno == EEXIST)
2953142e03fSSimon Schubert return;
2963142e03fSSimon Schubert if (! existence_error (errno))
2973142e03fSSimon Schubert {
2983142e03fSSimon Schubert error (0, errno, "cannot make path to %s", name);
2993142e03fSSimon Schubert return;
3003142e03fSSimon Schubert }
3013142e03fSSimon Schubert if ((cp = strrchr (name, '/')) == NULL)
3023142e03fSSimon Schubert return;
3033142e03fSSimon Schubert *cp = '\0';
3043142e03fSSimon Schubert make_directories (name);
3053142e03fSSimon Schubert *cp++ = '/';
3063142e03fSSimon Schubert if (*cp == '\0')
3073142e03fSSimon Schubert return;
3083142e03fSSimon Schubert (void) mkdir (name, 0777);
3093142e03fSSimon Schubert }
3103142e03fSSimon Schubert
3113142e03fSSimon Schubert /* Create directory NAME if it does not already exist; fatal error for
3123142e03fSSimon Schubert other errors. Returns 0 if directory was created; 1 if it already
3133142e03fSSimon Schubert existed. */
3143142e03fSSimon Schubert int
mkdir_if_needed(const char * name)3153142e03fSSimon Schubert mkdir_if_needed (const char *name)
3163142e03fSSimon Schubert {
3173142e03fSSimon Schubert if (mkdir (name, 0777) < 0)
3183142e03fSSimon Schubert {
3193142e03fSSimon Schubert int save_errno = errno;
3203142e03fSSimon Schubert if (save_errno != EEXIST && !isdir (name))
3213142e03fSSimon Schubert error (1, save_errno, "cannot make directory %s", name);
3223142e03fSSimon Schubert return 1;
3233142e03fSSimon Schubert }
3243142e03fSSimon Schubert return 0;
3253142e03fSSimon Schubert }
3263142e03fSSimon Schubert
3273142e03fSSimon Schubert /*
3283142e03fSSimon Schubert * Change the mode of a file, either adding write permissions, or removing
3293142e03fSSimon Schubert * all write permissions. Either change honors the current umask setting.
3303142e03fSSimon Schubert *
3313142e03fSSimon Schubert * Don't do anything if PreservePermissions is set to `yes'. This may
3323142e03fSSimon Schubert * have unexpected consequences for some uses of xchmod.
3333142e03fSSimon Schubert */
3343142e03fSSimon Schubert void
xchmod(const char * fname,int writable)3353142e03fSSimon Schubert xchmod (const char *fname, int writable)
3363142e03fSSimon Schubert {
3373142e03fSSimon Schubert struct stat sb;
3383142e03fSSimon Schubert mode_t mode, oumask;
3393142e03fSSimon Schubert
3403142e03fSSimon Schubert #ifdef PRESERVE_PERMISSIONS_SUPPORT
3413142e03fSSimon Schubert if (config->preserve_perms)
3423142e03fSSimon Schubert return;
3433142e03fSSimon Schubert #endif /* PRESERVE_PERMISSIONS_SUPPORT */
3443142e03fSSimon Schubert
3453142e03fSSimon Schubert if (stat (fname, &sb) < 0)
3463142e03fSSimon Schubert {
3473142e03fSSimon Schubert if (!noexec)
3483142e03fSSimon Schubert error (0, errno, "cannot stat %s", fname);
3493142e03fSSimon Schubert return;
3503142e03fSSimon Schubert }
3513142e03fSSimon Schubert oumask = umask (0);
3523142e03fSSimon Schubert (void) umask (oumask);
3533142e03fSSimon Schubert if (writable)
3543142e03fSSimon Schubert {
3553142e03fSSimon Schubert mode = sb.st_mode | (~oumask
3563142e03fSSimon Schubert & (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0)
3573142e03fSSimon Schubert | ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0)
3583142e03fSSimon Schubert | ((sb.st_mode & S_IROTH) ? S_IWOTH : 0)));
3593142e03fSSimon Schubert }
3603142e03fSSimon Schubert else
3613142e03fSSimon Schubert {
3623142e03fSSimon Schubert mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH) & ~oumask;
3633142e03fSSimon Schubert }
3643142e03fSSimon Schubert
3653142e03fSSimon Schubert TRACE (TRACE_FUNCTION, "chmod(%s,%o)", fname, (unsigned int) mode);
3663142e03fSSimon Schubert
3673142e03fSSimon Schubert if (noexec)
3683142e03fSSimon Schubert return;
3693142e03fSSimon Schubert
3703142e03fSSimon Schubert if (chmod (fname, mode) < 0)
3713142e03fSSimon Schubert error (0, errno, "cannot change mode of file %s", fname);
3723142e03fSSimon Schubert }
3733142e03fSSimon Schubert
3743142e03fSSimon Schubert /*
3753142e03fSSimon Schubert * Rename a file and die if it fails
3763142e03fSSimon Schubert */
3773142e03fSSimon Schubert void
rename_file(const char * from,const char * to)3783142e03fSSimon Schubert rename_file (const char *from, const char *to)
3793142e03fSSimon Schubert {
3803142e03fSSimon Schubert TRACE (TRACE_FUNCTION, "rename(%s,%s)", from, to);
3813142e03fSSimon Schubert
3823142e03fSSimon Schubert if (noexec)
3833142e03fSSimon Schubert return;
3843142e03fSSimon Schubert
3853142e03fSSimon Schubert if (rename (from, to) < 0)
3863142e03fSSimon Schubert error (1, errno, "cannot rename file %s to %s", from, to);
3873142e03fSSimon Schubert }
3883142e03fSSimon Schubert
3893142e03fSSimon Schubert /*
3903142e03fSSimon Schubert * unlink a file, if possible.
3913142e03fSSimon Schubert */
3923142e03fSSimon Schubert int
unlink_file(const char * f)3933142e03fSSimon Schubert unlink_file (const char *f)
3943142e03fSSimon Schubert {
3953142e03fSSimon Schubert TRACE (TRACE_FUNCTION, "unlink_file(%s)", f);
3963142e03fSSimon Schubert
3973142e03fSSimon Schubert if (noexec)
3983142e03fSSimon Schubert return (0);
3993142e03fSSimon Schubert
4003142e03fSSimon Schubert return (CVS_UNLINK (f));
4013142e03fSSimon Schubert }
4023142e03fSSimon Schubert
4033142e03fSSimon Schubert
4043142e03fSSimon Schubert
4053142e03fSSimon Schubert /*
4063142e03fSSimon Schubert * Unlink a file or dir, if possible. If it is a directory do a deep
4073142e03fSSimon Schubert * removal of all of the files in the directory. Return -1 on error
4083142e03fSSimon Schubert * (in which case errno is set).
4093142e03fSSimon Schubert */
4103142e03fSSimon Schubert int
unlink_file_dir(const char * f)4113142e03fSSimon Schubert unlink_file_dir (const char *f)
4123142e03fSSimon Schubert {
4133142e03fSSimon Schubert struct stat sb;
4143142e03fSSimon Schubert
4153142e03fSSimon Schubert /* This is called by the server parent process in contexts where
4163142e03fSSimon Schubert it is not OK to send output (e.g. after we sent "ok" to the
4173142e03fSSimon Schubert client). */
4183142e03fSSimon Schubert if (!server_active)
4193142e03fSSimon Schubert TRACE (TRACE_FUNCTION, "unlink_file_dir(%s)", f);
4203142e03fSSimon Schubert
4213142e03fSSimon Schubert if (noexec)
4223142e03fSSimon Schubert return 0;
4233142e03fSSimon Schubert
4243142e03fSSimon Schubert /* For at least some unices, if root tries to unlink() a directory,
4253142e03fSSimon Schubert instead of doing something rational like returning EISDIR,
4263142e03fSSimon Schubert the system will gleefully go ahead and corrupt the filesystem.
4273142e03fSSimon Schubert So we first call stat() to see if it is OK to call unlink(). This
4283142e03fSSimon Schubert doesn't quite work--if someone creates a directory between the
4293142e03fSSimon Schubert call to stat() and the call to unlink(), we'll still corrupt
4303142e03fSSimon Schubert the filesystem. Where is the Unix Haters Handbook when you need
4313142e03fSSimon Schubert it? */
4323142e03fSSimon Schubert if (stat (f, &sb) < 0)
4333142e03fSSimon Schubert {
4343142e03fSSimon Schubert if (existence_error (errno))
4353142e03fSSimon Schubert {
4363142e03fSSimon Schubert /* The file or directory doesn't exist anyhow. */
4373142e03fSSimon Schubert return -1;
4383142e03fSSimon Schubert }
4393142e03fSSimon Schubert }
4403142e03fSSimon Schubert else if (S_ISDIR (sb.st_mode))
4413142e03fSSimon Schubert return deep_remove_dir (f);
4423142e03fSSimon Schubert
4433142e03fSSimon Schubert return CVS_UNLINK (f);
4443142e03fSSimon Schubert }
4453142e03fSSimon Schubert
4463142e03fSSimon Schubert
4473142e03fSSimon Schubert
4483142e03fSSimon Schubert /* Remove a directory and everything it contains. Returns 0 for
4493142e03fSSimon Schubert * success, -1 for failure (in which case errno is set).
4503142e03fSSimon Schubert */
4513142e03fSSimon Schubert
4523142e03fSSimon Schubert static int
deep_remove_dir(const char * path)4533142e03fSSimon Schubert deep_remove_dir (const char *path)
4543142e03fSSimon Schubert {
4553142e03fSSimon Schubert DIR *dirp;
4563142e03fSSimon Schubert struct dirent *dp;
4573142e03fSSimon Schubert
4583142e03fSSimon Schubert if (rmdir (path) != 0)
4593142e03fSSimon Schubert {
4603142e03fSSimon Schubert if (errno == ENOTEMPTY
4613142e03fSSimon Schubert || errno == EEXIST
4623142e03fSSimon Schubert /* Ugly workaround for ugly AIX 4.1 (and 3.2) header bug
4633142e03fSSimon Schubert (it defines ENOTEMPTY and EEXIST to 17 but actually
4643142e03fSSimon Schubert returns 87). */
4653142e03fSSimon Schubert || (ENOTEMPTY == 17 && EEXIST == 17 && errno == 87))
4663142e03fSSimon Schubert {
4673142e03fSSimon Schubert if ((dirp = CVS_OPENDIR (path)) == NULL)
4683142e03fSSimon Schubert /* If unable to open the directory return
4693142e03fSSimon Schubert * an error
4703142e03fSSimon Schubert */
4713142e03fSSimon Schubert return -1;
4723142e03fSSimon Schubert
4733142e03fSSimon Schubert errno = 0;
4743142e03fSSimon Schubert while ((dp = CVS_READDIR (dirp)) != NULL)
4753142e03fSSimon Schubert {
4763142e03fSSimon Schubert char *buf;
4773142e03fSSimon Schubert
4783142e03fSSimon Schubert if (strcmp (dp->d_name, ".") == 0 ||
4793142e03fSSimon Schubert strcmp (dp->d_name, "..") == 0)
4803142e03fSSimon Schubert continue;
4813142e03fSSimon Schubert
4823142e03fSSimon Schubert buf = Xasprintf ("%s/%s", path, dp->d_name);
4833142e03fSSimon Schubert
4843142e03fSSimon Schubert /* See comment in unlink_file_dir explanation of why we use
4853142e03fSSimon Schubert isdir instead of just calling unlink and checking the
4863142e03fSSimon Schubert status. */
4873142e03fSSimon Schubert if (isdir (buf))
4883142e03fSSimon Schubert {
4893142e03fSSimon Schubert if (deep_remove_dir (buf))
4903142e03fSSimon Schubert {
4913142e03fSSimon Schubert CVS_CLOSEDIR (dirp);
4923142e03fSSimon Schubert free (buf);
4933142e03fSSimon Schubert return -1;
4943142e03fSSimon Schubert }
4953142e03fSSimon Schubert }
4963142e03fSSimon Schubert else
4973142e03fSSimon Schubert {
4983142e03fSSimon Schubert if (CVS_UNLINK (buf) != 0)
4993142e03fSSimon Schubert {
5003142e03fSSimon Schubert CVS_CLOSEDIR (dirp);
5013142e03fSSimon Schubert free (buf);
5023142e03fSSimon Schubert return -1;
5033142e03fSSimon Schubert }
5043142e03fSSimon Schubert }
5053142e03fSSimon Schubert free (buf);
5063142e03fSSimon Schubert
5073142e03fSSimon Schubert errno = 0;
5083142e03fSSimon Schubert }
5093142e03fSSimon Schubert if (errno != 0)
5103142e03fSSimon Schubert {
5113142e03fSSimon Schubert int save_errno = errno;
5123142e03fSSimon Schubert CVS_CLOSEDIR (dirp);
5133142e03fSSimon Schubert errno = save_errno;
5143142e03fSSimon Schubert return -1;
5153142e03fSSimon Schubert }
5163142e03fSSimon Schubert CVS_CLOSEDIR (dirp);
5173142e03fSSimon Schubert return rmdir (path);
5183142e03fSSimon Schubert }
5193142e03fSSimon Schubert else
5203142e03fSSimon Schubert return -1;
5213142e03fSSimon Schubert }
5223142e03fSSimon Schubert
5233142e03fSSimon Schubert /* Was able to remove the directory return 0 */
5243142e03fSSimon Schubert return 0;
5253142e03fSSimon Schubert }
5263142e03fSSimon Schubert
5273142e03fSSimon Schubert
5283142e03fSSimon Schubert
5293142e03fSSimon Schubert /* Read NCHARS bytes from descriptor FD into BUF.
5303142e03fSSimon Schubert Return the number of characters successfully read.
5313142e03fSSimon Schubert The number returned is always NCHARS unless end-of-file or error. */
5323142e03fSSimon Schubert static size_t
block_read(int fd,char * buf,size_t nchars)5333142e03fSSimon Schubert block_read (int fd, char *buf, size_t nchars)
5343142e03fSSimon Schubert {
5353142e03fSSimon Schubert char *bp = buf;
5363142e03fSSimon Schubert size_t nread;
5373142e03fSSimon Schubert
5383142e03fSSimon Schubert do
5393142e03fSSimon Schubert {
5403142e03fSSimon Schubert nread = read (fd, bp, nchars);
5413142e03fSSimon Schubert if (nread == (size_t)-1)
5423142e03fSSimon Schubert {
5433142e03fSSimon Schubert #ifdef EINTR
5443142e03fSSimon Schubert if (errno == EINTR)
5453142e03fSSimon Schubert continue;
5463142e03fSSimon Schubert #endif
5473142e03fSSimon Schubert return (size_t)-1;
5483142e03fSSimon Schubert }
5493142e03fSSimon Schubert
5503142e03fSSimon Schubert if (nread == 0)
5513142e03fSSimon Schubert break;
5523142e03fSSimon Schubert
5533142e03fSSimon Schubert bp += nread;
5543142e03fSSimon Schubert nchars -= nread;
5553142e03fSSimon Schubert } while (nchars != 0);
5563142e03fSSimon Schubert
5573142e03fSSimon Schubert return bp - buf;
5583142e03fSSimon Schubert }
5593142e03fSSimon Schubert
5603142e03fSSimon Schubert
5613142e03fSSimon Schubert /*
5623142e03fSSimon Schubert * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
5633142e03fSSimon Schubert * If FILE1 and FILE2 are special files, compare their salient characteristics
5643142e03fSSimon Schubert * (i.e. major/minor device numbers, links, etc.
5653142e03fSSimon Schubert */
5663142e03fSSimon Schubert int
xcmp(const char * file1,const char * file2)5673142e03fSSimon Schubert xcmp (const char *file1, const char *file2)
5683142e03fSSimon Schubert {
5693142e03fSSimon Schubert char *buf1, *buf2;
5703142e03fSSimon Schubert struct stat sb1, sb2;
5713142e03fSSimon Schubert int fd1, fd2;
5723142e03fSSimon Schubert int ret;
5733142e03fSSimon Schubert
5743142e03fSSimon Schubert if (lstat (file1, &sb1) < 0)
5753142e03fSSimon Schubert error (1, errno, "cannot lstat %s", file1);
5763142e03fSSimon Schubert if (lstat (file2, &sb2) < 0)
5773142e03fSSimon Schubert error (1, errno, "cannot lstat %s", file2);
5783142e03fSSimon Schubert
5793142e03fSSimon Schubert /* If FILE1 and FILE2 are not the same file type, they are unequal. */
5803142e03fSSimon Schubert if ((sb1.st_mode & S_IFMT) != (sb2.st_mode & S_IFMT))
5813142e03fSSimon Schubert return 1;
5823142e03fSSimon Schubert
5833142e03fSSimon Schubert /* If FILE1 and FILE2 are symlinks, they are equal if they point to
5843142e03fSSimon Schubert the same thing. */
5853142e03fSSimon Schubert #ifdef S_ISLNK
5863142e03fSSimon Schubert if (S_ISLNK (sb1.st_mode) && S_ISLNK (sb2.st_mode))
5873142e03fSSimon Schubert {
5883142e03fSSimon Schubert int result;
5893142e03fSSimon Schubert buf1 = Xreadlink (file1, sb1.st_size);
5903142e03fSSimon Schubert buf2 = Xreadlink (file2, sb2.st_size);
5913142e03fSSimon Schubert result = (strcmp (buf1, buf2) == 0);
5923142e03fSSimon Schubert free (buf1);
5933142e03fSSimon Schubert free (buf2);
5943142e03fSSimon Schubert return result;
5953142e03fSSimon Schubert }
5963142e03fSSimon Schubert #endif
5973142e03fSSimon Schubert
5983142e03fSSimon Schubert /* If FILE1 and FILE2 are devices, they are equal if their device
5993142e03fSSimon Schubert numbers match. */
6003142e03fSSimon Schubert if (S_ISBLK (sb1.st_mode) || S_ISCHR (sb1.st_mode))
6013142e03fSSimon Schubert {
6023142e03fSSimon Schubert #ifdef HAVE_STRUCT_STAT_ST_RDEV
6033142e03fSSimon Schubert if (sb1.st_rdev == sb2.st_rdev)
6043142e03fSSimon Schubert return 0;
6053142e03fSSimon Schubert else
6063142e03fSSimon Schubert return 1;
6073142e03fSSimon Schubert #else
6083142e03fSSimon Schubert error (1, 0, "cannot compare device files on this system (%s and %s)",
6093142e03fSSimon Schubert file1, file2);
6103142e03fSSimon Schubert #endif
6113142e03fSSimon Schubert }
6123142e03fSSimon Schubert
6133142e03fSSimon Schubert if ((fd1 = open (file1, O_RDONLY)) < 0)
6143142e03fSSimon Schubert error (1, errno, "cannot open file %s for comparing", file1);
6153142e03fSSimon Schubert if ((fd2 = open (file2, O_RDONLY)) < 0)
6163142e03fSSimon Schubert error (1, errno, "cannot open file %s for comparing", file2);
6173142e03fSSimon Schubert
6183142e03fSSimon Schubert /* A generic file compare routine might compare st_dev & st_ino here
6193142e03fSSimon Schubert to see if the two files being compared are actually the same file.
6203142e03fSSimon Schubert But that won't happen in CVS, so we won't bother. */
6213142e03fSSimon Schubert
6223142e03fSSimon Schubert if (sb1.st_size != sb2.st_size)
6233142e03fSSimon Schubert ret = 1;
6243142e03fSSimon Schubert else if (sb1.st_size == 0)
6253142e03fSSimon Schubert ret = 0;
6263142e03fSSimon Schubert else
6273142e03fSSimon Schubert {
6283142e03fSSimon Schubert /* FIXME: compute the optimal buffer size by computing the least
6293142e03fSSimon Schubert common multiple of the files st_blocks field */
6303142e03fSSimon Schubert size_t buf_size = 8 * 1024;
6313142e03fSSimon Schubert size_t read1;
6323142e03fSSimon Schubert size_t read2;
6333142e03fSSimon Schubert
6343142e03fSSimon Schubert buf1 = xmalloc (buf_size);
6353142e03fSSimon Schubert buf2 = xmalloc (buf_size);
6363142e03fSSimon Schubert
6373142e03fSSimon Schubert do
6383142e03fSSimon Schubert {
6393142e03fSSimon Schubert read1 = block_read (fd1, buf1, buf_size);
640*96be2d36Szrj if (read1 == (size_t)-1) {
6413142e03fSSimon Schubert error (1, errno, "cannot read file %s for comparing", file1);
642*96be2d36Szrj exit(1); /* to suppress -Wstringop-overflow */
643*96be2d36Szrj }
6443142e03fSSimon Schubert
6453142e03fSSimon Schubert read2 = block_read (fd2, buf2, buf_size);
6463142e03fSSimon Schubert if (read2 == (size_t)-1)
6473142e03fSSimon Schubert error (1, errno, "cannot read file %s for comparing", file2);
6483142e03fSSimon Schubert
6493142e03fSSimon Schubert /* assert (read1 == read2); */
6503142e03fSSimon Schubert
6513142e03fSSimon Schubert ret = memcmp(buf1, buf2, read1);
6523142e03fSSimon Schubert } while (ret == 0 && read1 == buf_size);
6533142e03fSSimon Schubert
6543142e03fSSimon Schubert free (buf1);
6553142e03fSSimon Schubert free (buf2);
6563142e03fSSimon Schubert }
6573142e03fSSimon Schubert
6583142e03fSSimon Schubert (void) close (fd1);
6593142e03fSSimon Schubert (void) close (fd2);
6603142e03fSSimon Schubert return (ret);
6613142e03fSSimon Schubert }
6623142e03fSSimon Schubert
6633142e03fSSimon Schubert /* Generate a unique temporary filename. Returns a pointer to a newly
6643142e03fSSimon Schubert * malloc'd string containing the name. Returns successfully or not at
6653142e03fSSimon Schubert * all.
6663142e03fSSimon Schubert *
6673142e03fSSimon Schubert * THIS FUNCTION IS DEPRECATED!!! USE cvs_temp_file INSTEAD!!!
6683142e03fSSimon Schubert *
6693142e03fSSimon Schubert * and yes, I know about the way the rcs commands use temp files. I think
6703142e03fSSimon Schubert * they should be converted too but I don't have time to look into it right
6713142e03fSSimon Schubert * now.
6723142e03fSSimon Schubert */
6733142e03fSSimon Schubert char *
cvs_temp_name(void)6743142e03fSSimon Schubert cvs_temp_name (void)
6753142e03fSSimon Schubert {
6763142e03fSSimon Schubert char *fn;
6773142e03fSSimon Schubert FILE *fp;
6783142e03fSSimon Schubert
6793142e03fSSimon Schubert fp = cvs_temp_file (&fn);
6803142e03fSSimon Schubert if (fp == NULL)
6813142e03fSSimon Schubert error (1, errno, "Failed to create temporary file");
6823142e03fSSimon Schubert if (fclose (fp) == EOF)
6833142e03fSSimon Schubert error (0, errno, "Failed to close temporary file %s", fn);
6843142e03fSSimon Schubert return fn;
6853142e03fSSimon Schubert }
6863142e03fSSimon Schubert
6873142e03fSSimon Schubert /* Generate a unique temporary filename and return an open file stream
6883142e03fSSimon Schubert * to the truncated file by that name
6893142e03fSSimon Schubert *
6903142e03fSSimon Schubert * INPUTS
6913142e03fSSimon Schubert * filename where to place the pointer to the newly allocated file
6923142e03fSSimon Schubert * name string
6933142e03fSSimon Schubert *
6943142e03fSSimon Schubert * OUTPUTS
6953142e03fSSimon Schubert * filename dereferenced, will point to the newly allocated file
6963142e03fSSimon Schubert * name string. This value is undefined if the function
6973142e03fSSimon Schubert * returns an error.
6983142e03fSSimon Schubert *
6993142e03fSSimon Schubert * RETURNS
7003142e03fSSimon Schubert * An open file pointer to a read/write mode empty temporary file with the
7013142e03fSSimon Schubert * unique file name or NULL on failure.
7023142e03fSSimon Schubert *
7033142e03fSSimon Schubert * ERRORS
7043142e03fSSimon Schubert * On error, errno will be set to some value either by CVS_FOPEN or
7053142e03fSSimon Schubert * whatever system function is called to generate the temporary file name.
7063142e03fSSimon Schubert * The value of filename is undefined on error.
7073142e03fSSimon Schubert */
7083142e03fSSimon Schubert FILE *
cvs_temp_file(char ** filename)7093142e03fSSimon Schubert cvs_temp_file (char **filename)
7103142e03fSSimon Schubert {
7113142e03fSSimon Schubert char *fn;
7123142e03fSSimon Schubert FILE *fp;
7133142e03fSSimon Schubert int fd;
7143142e03fSSimon Schubert
7153142e03fSSimon Schubert /* FIXME - I'd like to be returning NULL here in noexec mode, but I think
7163142e03fSSimon Schubert * some of the rcs & diff functions which rely on a temp file run in
7173142e03fSSimon Schubert * noexec mode too.
7183142e03fSSimon Schubert */
7193142e03fSSimon Schubert
7203142e03fSSimon Schubert assert (filename != NULL);
7213142e03fSSimon Schubert
7223142e03fSSimon Schubert fn = Xasprintf ("%s/%s", get_cvs_tmp_dir (), "cvsXXXXXX");
7233142e03fSSimon Schubert fd = mkstemp (fn);
7243142e03fSSimon Schubert
7253142e03fSSimon Schubert /* a NULL return will be interpreted by callers as an error and
7263142e03fSSimon Schubert * errno should still be set
7273142e03fSSimon Schubert */
7283142e03fSSimon Schubert if (fd == -1)
7293142e03fSSimon Schubert fp = NULL;
7303142e03fSSimon Schubert else if ((fp = CVS_FDOPEN (fd, "w+")) == NULL)
7313142e03fSSimon Schubert {
7323142e03fSSimon Schubert /* Attempt to close and unlink the file since mkstemp returned
7333142e03fSSimon Schubert * sucessfully and we believe it's been created and opened.
7343142e03fSSimon Schubert */
7353142e03fSSimon Schubert int save_errno = errno;
7363142e03fSSimon Schubert if (close (fd))
7373142e03fSSimon Schubert error (0, errno, "Failed to close temporary file %s", fn);
7383142e03fSSimon Schubert if (CVS_UNLINK (fn))
7393142e03fSSimon Schubert error (0, errno, "Failed to unlink temporary file %s", fn);
7403142e03fSSimon Schubert errno = save_errno;
7413142e03fSSimon Schubert }
7423142e03fSSimon Schubert
7433142e03fSSimon Schubert if (fp == NULL)
7443142e03fSSimon Schubert free (fn);
7453142e03fSSimon Schubert
7463142e03fSSimon Schubert /* mkstemp is defined to open mode 0600 using glibc 2.0.7+. There used
7473142e03fSSimon Schubert * to be a complicated #ifdef checking the library versions here and then
7483142e03fSSimon Schubert * a chmod 0600 on the temp file for versions of glibc less than 2.1. This
7493142e03fSSimon Schubert * is rather a special case, leaves a race condition open regardless, and
7503142e03fSSimon Schubert * one could hope that sysadmins have read the relevant security
7513142e03fSSimon Schubert * announcements and upgraded by now to a version with a fix committed in
7523142e03fSSimon Schubert * January of 1999.
7533142e03fSSimon Schubert *
7543142e03fSSimon Schubert * If it is decided at some point that old, buggy versions of glibc should
7553142e03fSSimon Schubert * still be catered to, a umask of 0600 should be set before file creation
7563142e03fSSimon Schubert * instead then reset after file creation since this would avoid the race
7573142e03fSSimon Schubert * condition that the chmod left open to exploitation.
7583142e03fSSimon Schubert */
7593142e03fSSimon Schubert
7603142e03fSSimon Schubert *filename = fn;
7613142e03fSSimon Schubert return fp;
7623142e03fSSimon Schubert }
7633142e03fSSimon Schubert
7643142e03fSSimon Schubert
7653142e03fSSimon Schubert
7663142e03fSSimon Schubert /* Return a pointer into PATH's last component. */
7673142e03fSSimon Schubert const char *
last_component(const char * path)7683142e03fSSimon Schubert last_component (const char *path)
7693142e03fSSimon Schubert {
7703142e03fSSimon Schubert const char *last = strrchr (path, '/');
7713142e03fSSimon Schubert
7723142e03fSSimon Schubert if (last && (last != path))
7733142e03fSSimon Schubert return last + 1;
7743142e03fSSimon Schubert else
7753142e03fSSimon Schubert return path;
7763142e03fSSimon Schubert }
7773142e03fSSimon Schubert
7783142e03fSSimon Schubert
7793142e03fSSimon Schubert
7803142e03fSSimon Schubert /* Return the home directory. Returns a pointer to storage
7813142e03fSSimon Schubert managed by this function or its callees (currently getenv).
7823142e03fSSimon Schubert This function will return the same thing every time it is
7833142e03fSSimon Schubert called. Returns NULL if there is no home directory.
7843142e03fSSimon Schubert
7853142e03fSSimon Schubert Note that for a pserver server, this may return root's home
7863142e03fSSimon Schubert directory. What typically happens is that upon being started from
7873142e03fSSimon Schubert inetd, before switching users, the code in cvsrc.c calls
7883142e03fSSimon Schubert get_homedir which remembers root's home directory in the static
7893142e03fSSimon Schubert variable. Then the switch happens and get_homedir might return a
7903142e03fSSimon Schubert directory that we don't even have read or execute permissions for
7913142e03fSSimon Schubert (which is bad, when various parts of CVS try to read there). One
7923142e03fSSimon Schubert fix would be to make the value returned by get_homedir only good
7933142e03fSSimon Schubert until the next call (which would free the old value). Another fix
7943142e03fSSimon Schubert would be to just always malloc our answer, and let the caller free
7953142e03fSSimon Schubert it (that is best, because some day we may need to be reentrant).
7963142e03fSSimon Schubert
7973142e03fSSimon Schubert The workaround is to put -f in inetd.conf which means that
7983142e03fSSimon Schubert get_homedir won't get called until after the switch in user ID.
7993142e03fSSimon Schubert
8003142e03fSSimon Schubert The whole concept of a "home directory" on the server is pretty
8013142e03fSSimon Schubert iffy, although I suppose some people probably are relying on it for
8023142e03fSSimon Schubert .cvsrc and such, in the cases where it works. */
8033142e03fSSimon Schubert char *
get_homedir(void)8043142e03fSSimon Schubert get_homedir (void)
8053142e03fSSimon Schubert {
8063142e03fSSimon Schubert static char *home = NULL;
8073142e03fSSimon Schubert char *env;
8083142e03fSSimon Schubert struct passwd *pw;
8093142e03fSSimon Schubert
8103142e03fSSimon Schubert if (home != NULL)
8113142e03fSSimon Schubert return home;
8123142e03fSSimon Schubert
8133142e03fSSimon Schubert if (!server_active && (env = getenv ("HOME")) != NULL)
8143142e03fSSimon Schubert home = env;
8153142e03fSSimon Schubert else if ((pw = (struct passwd *) getpwuid (getuid ()))
8163142e03fSSimon Schubert && pw->pw_dir)
8173142e03fSSimon Schubert home = xstrdup (pw->pw_dir);
8183142e03fSSimon Schubert else
8193142e03fSSimon Schubert return 0;
8203142e03fSSimon Schubert
8213142e03fSSimon Schubert return home;
8223142e03fSSimon Schubert }
8233142e03fSSimon Schubert
8243142e03fSSimon Schubert /* Compose a path to a file in the home directory. This is necessary because
8253142e03fSSimon Schubert * of different behavior on UNIX and VMS. See the notes in vms/filesubr.c.
8263142e03fSSimon Schubert *
8273142e03fSSimon Schubert * A more clean solution would be something more along the lines of a
8283142e03fSSimon Schubert * "join a directory to a filename" kind of thing which was not specific to
8293142e03fSSimon Schubert * the homedir. This should aid portability between UNIX, Mac, Windows, VMS,
8303142e03fSSimon Schubert * and possibly others. This is already handled by Perl - it might be
8313142e03fSSimon Schubert * interesting to see how much of the code was written in C since Perl is under
8323142e03fSSimon Schubert * the GPL and the Artistic license - we might be able to use it.
8333142e03fSSimon Schubert */
8343142e03fSSimon Schubert char *
strcat_filename_onto_homedir(const char * dir,const char * file)8353142e03fSSimon Schubert strcat_filename_onto_homedir (const char *dir, const char *file)
8363142e03fSSimon Schubert {
8373142e03fSSimon Schubert char *path = Xasprintf ("%s/%s", dir, file);
8383142e03fSSimon Schubert return path;
8393142e03fSSimon Schubert }
8403142e03fSSimon Schubert
8413142e03fSSimon Schubert /* See cvs.h for description. On unix this does nothing, because the
8423142e03fSSimon Schubert shell expands the wildcards. */
8433142e03fSSimon Schubert void
expand_wild(int argc,char ** argv,int * pargc,char *** pargv)8443142e03fSSimon Schubert expand_wild (int argc, char **argv, int *pargc, char ***pargv)
8453142e03fSSimon Schubert {
8463142e03fSSimon Schubert int i;
8473142e03fSSimon Schubert if (size_overflow_p (xtimes (argc, sizeof (char *)))) {
8483142e03fSSimon Schubert *pargc = 0;
8493142e03fSSimon Schubert *pargv = NULL;
8503142e03fSSimon Schubert error (0, 0, "expand_wild: too many arguments");
8513142e03fSSimon Schubert return;
8523142e03fSSimon Schubert }
8533142e03fSSimon Schubert *pargc = argc;
8543142e03fSSimon Schubert *pargv = xnmalloc (argc, sizeof (char *));
8553142e03fSSimon Schubert for (i = 0; i < argc; ++i)
8563142e03fSSimon Schubert (*pargv)[i] = xstrdup (argv[i]);
8573142e03fSSimon Schubert }
8583142e03fSSimon Schubert
8593142e03fSSimon Schubert
8603142e03fSSimon Schubert
8613142e03fSSimon Schubert static char *tmpdir_env;
8623142e03fSSimon Schubert
8633142e03fSSimon Schubert /* Return path to temp directory.
8643142e03fSSimon Schubert */
8653142e03fSSimon Schubert const char *
get_system_temp_dir(void)8663142e03fSSimon Schubert get_system_temp_dir (void)
8673142e03fSSimon Schubert {
8683142e03fSSimon Schubert if (!tmpdir_env) tmpdir_env = getenv (TMPDIR_ENV);
8693142e03fSSimon Schubert return tmpdir_env;
8703142e03fSSimon Schubert }
8713142e03fSSimon Schubert
8723142e03fSSimon Schubert
8733142e03fSSimon Schubert
8743142e03fSSimon Schubert void
push_env_temp_dir(void)8753142e03fSSimon Schubert push_env_temp_dir (void)
8763142e03fSSimon Schubert {
8773142e03fSSimon Schubert const char *tmpdir = get_cvs_tmp_dir ();
8783142e03fSSimon Schubert if (tmpdir_env && strcmp (tmpdir_env, tmpdir))
8793142e03fSSimon Schubert setenv (TMPDIR_ENV, tmpdir, 1);
8803142e03fSSimon Schubert }
881