summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src/filesubr.c
diff options
context:
space:
mode:
authoreadler <eadler@FreeBSD.org>2013-06-15 20:29:07 +0000
committereadler <eadler@FreeBSD.org>2013-06-15 20:29:07 +0000
commitbf7c0f2705c32e44d3c3b62d60453a30dbbffe3f (patch)
treedca088b474d4fedf5e6d4ef16e823d7756d587bc /contrib/cvs/src/filesubr.c
parentb95c459e182fd072e6dac884c7eed86a220534e7 (diff)
downloadFreeBSD-src-bf7c0f2705c32e44d3c3b62d60453a30dbbffe3f.zip
FreeBSD-src-bf7c0f2705c32e44d3c3b62d60453a30dbbffe3f.tar.gz
Remove CVS from the base system.
Discussed with: many Reviewed by: peter, zi Approved by: core
Diffstat (limited to 'contrib/cvs/src/filesubr.c')
-rw-r--r--contrib/cvs/src/filesubr.c1100
1 files changed, 0 insertions, 1100 deletions
diff --git a/contrib/cvs/src/filesubr.c b/contrib/cvs/src/filesubr.c
deleted file mode 100644
index 1e1f901..0000000
--- a/contrib/cvs/src/filesubr.c
+++ /dev/null
@@ -1,1100 +0,0 @@
-/* filesubr.c --- subroutines for dealing with files
- Jim Blandy <jimb@cyclic.com>
-
- This file is part of GNU CVS.
-
- GNU CVS is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details. */
-
-/* These functions were moved out of subr.c because they need different
- definitions under operating systems (like, say, Windows NT) with different
- file system semantics. */
-
-#include <assert.h>
-#include "cvs.h"
-
-#include "xsize.h"
-
-static int deep_remove_dir PROTO((const char *path));
-
-/*
- * Copies "from" to "to".
- */
-void
-copy_file (from, to)
- const char *from;
- const char *to;
-{
- struct stat sb;
- struct utimbuf t;
- int fdin, fdout;
-
- if (trace)
- (void) fprintf (stderr, "%s-> copy(%s,%s)\n",
- CLIENT_SERVER_STR, from, to);
- if (noexec)
- return;
-
- /* If the file to be copied is a link or a device, then just create
- the new link or device appropriately. */
- if (islink (from))
- {
- char *source = xreadlink (from);
- symlink (source, to);
- free (source);
- return;
- }
-
- if (isdevice (from))
- {
-#if defined(HAVE_MKNOD) && defined(HAVE_STRUCT_STAT_ST_RDEV)
- if (stat (from, &sb) < 0)
- error (1, errno, "cannot stat %s", from);
- mknod (to, sb.st_mode, sb.st_rdev);
-#else
- error (1, 0, "cannot copy device files on this system (%s)", from);
-#endif
- }
- else
- {
- /* Not a link or a device... probably a regular file. */
- if ((fdin = open (from, O_RDONLY)) < 0)
- error (1, errno, "cannot open %s for copying", from);
- if (fstat (fdin, &sb) < 0)
- error (1, errno, "cannot fstat %s", from);
- if ((fdout = creat (to, (int) sb.st_mode & 07777)) < 0)
- error (1, errno, "cannot create %s for copying", to);
- if (sb.st_size > 0)
- {
- char buf[BUFSIZ];
- int n;
-
- for (;;)
- {
- n = read (fdin, buf, sizeof(buf));
- if (n == -1)
- {
-#ifdef EINTR
- if (errno == EINTR)
- continue;
-#endif
- error (1, errno, "cannot read file %s for copying", from);
- }
- else if (n == 0)
- break;
-
- if (write(fdout, buf, n) != n) {
- error (1, errno, "cannot write file %s for copying", to);
- }
- }
-
-#ifdef HAVE_FSYNC
- if (fsync (fdout))
- error (1, errno, "cannot fsync file %s after copying", to);
-#endif
- }
-
- if (close (fdin) < 0)
- error (0, errno, "cannot close %s", from);
- if (close (fdout) < 0)
- error (1, errno, "cannot close %s", to);
- }
-
- /* preserve last access & modification times */
- memset ((char *) &t, 0, sizeof (t));
- t.actime = sb.st_atime;
- t.modtime = sb.st_mtime;
- (void) utime (to, &t);
-}
-
-/* FIXME-krp: these functions would benefit from caching the char * &
- stat buf. */
-
-/*
- * Returns non-zero if the argument file is a directory, or is a symbolic
- * link which points to a directory.
- */
-int
-isdir (file)
- const char *file;
-{
- struct stat sb;
-
- if (stat (file, &sb) < 0)
- return (0);
- return (S_ISDIR (sb.st_mode));
-}
-
-/*
- * Returns non-zero if the argument file is a symbolic link.
- */
-int
-islink (file)
- const char *file;
-{
-#ifdef S_ISLNK
- struct stat sb;
-
- if (CVS_LSTAT (file, &sb) < 0)
- return (0);
- return (S_ISLNK (sb.st_mode));
-#else
- return (0);
-#endif
-}
-
-/*
- * Returns non-zero if the argument file is a block or
- * character special device.
- */
-int
-isdevice (file)
- const char *file;
-{
- struct stat sb;
-
- if (CVS_LSTAT (file, &sb) < 0)
- return (0);
-#ifdef S_ISBLK
- if (S_ISBLK (sb.st_mode))
- return 1;
-#endif
-#ifdef S_ISCHR
- if (S_ISCHR (sb.st_mode))
- return 1;
-#endif
- return 0;
-}
-
-/*
- * Returns non-zero if the argument file exists.
- */
-int
-isfile (file)
- const char *file;
-{
- return isaccessible(file, F_OK);
-}
-
-/*
- * Returns non-zero if the argument file is readable.
- */
-int
-isreadable (file)
- const char *file;
-{
- return isaccessible(file, R_OK);
-}
-
-/*
- * Returns non-zero if the argument file is writable.
- */
-int
-iswritable (file)
- const char *file;
-{
- return isaccessible(file, W_OK);
-}
-
-/*
- * Returns non-zero if the argument file is accessable according to
- * mode. If compiled with SETXID_SUPPORT also works if cvs has setxid
- * bits set.
- */
-int
-isaccessible (file, mode)
- const char *file;
- const int mode;
-{
-#ifdef SETXID_SUPPORT
- struct stat sb;
- int umask = 0;
- int gmask = 0;
- int omask = 0;
- int uid, mask;
-
- if (stat(file, &sb) == -1)
- return 0;
- if (mode == F_OK)
- return 1;
-
- uid = geteuid();
- if (uid == 0) /* superuser */
- {
- if (!(mode & X_OK) || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
- return 1;
-
- errno = EACCES;
- return 0;
- }
-
- if (mode & R_OK)
- {
- umask |= S_IRUSR;
- gmask |= S_IRGRP;
- omask |= S_IROTH;
- }
- if (mode & W_OK)
- {
- umask |= S_IWUSR;
- gmask |= S_IWGRP;
- omask |= S_IWOTH;
- }
- if (mode & X_OK)
- {
- umask |= S_IXUSR;
- gmask |= S_IXGRP;
- omask |= S_IXOTH;
- }
-
- mask = sb.st_uid == uid ? umask : sb.st_gid == getegid() ? gmask : omask;
- if ((sb.st_mode & mask) == mask)
- return 1;
- errno = EACCES;
- return 0;
-#else
- return access(file, mode) == 0;
-#endif
-}
-
-/*
- * Open a file and die if it fails
- */
-FILE *
-open_file (name, mode)
- const char *name;
- const char *mode;
-{
- FILE *fp;
-
- if ((fp = fopen (name, mode)) == NULL)
- error (1, errno, "cannot open %s", name);
- return (fp);
-}
-
-/*
- * Make a directory and die if it fails
- */
-void
-make_directory (name)
- const char *name;
-{
- struct stat sb;
-
- if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode)))
- error (0, 0, "%s already exists but is not a directory", name);
- if (!noexec && mkdir (name, 0777) < 0)
- error (1, errno, "cannot make directory %s", name);
-}
-
-/*
- * Make a path to the argument directory, printing a message if something
- * goes wrong.
- */
-void
-make_directories (name)
- const char *name;
-{
- char *cp;
-
- if (noexec)
- return;
-
- if (mkdir (name, 0777) == 0 || errno == EEXIST)
- return;
- if (! existence_error (errno))
- {
- error (0, errno, "cannot make path to %s", name);
- return;
- }
- if ((cp = strrchr (name, '/')) == NULL)
- return;
- *cp = '\0';
- make_directories (name);
- *cp++ = '/';
- if (*cp == '\0')
- return;
- (void) mkdir (name, 0777);
-}
-
-/* Create directory NAME if it does not already exist; fatal error for
- other errors. Returns 0 if directory was created; 1 if it already
- existed. */
-int
-mkdir_if_needed (name)
- const char *name;
-{
- if (mkdir (name, 0777) < 0)
- {
- int save_errno = errno;
- if (save_errno != EEXIST && !isdir (name))
- error (1, save_errno, "cannot make directory %s", name);
- return 1;
- }
- return 0;
-}
-
-/*
- * Change the mode of a file, either adding write permissions, or removing
- * all write permissions. Either change honors the current umask setting.
- *
- * Don't do anything if PreservePermissions is set to `yes'. This may
- * have unexpected consequences for some uses of xchmod.
- */
-void
-xchmod (fname, writable)
- const char *fname;
- int writable;
-{
- struct stat sb;
- mode_t mode, oumask;
-
- if (preserve_perms)
- return;
-
- if (stat (fname, &sb) < 0)
- {
- if (!noexec)
- error (0, errno, "cannot stat %s", fname);
- return;
- }
- oumask = umask (0);
- (void) umask (oumask);
- if (writable)
- {
- mode = sb.st_mode | (~oumask
- & (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0)
- | ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0)
- | ((sb.st_mode & S_IROTH) ? S_IWOTH : 0)));
- }
- else
- {
- mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH) & ~oumask;
- }
-
- if (trace)
- (void) fprintf (stderr, "%s-> chmod(%s,%o)\n",
- CLIENT_SERVER_STR, fname,
- (unsigned int) mode);
- if (noexec)
- return;
-
- if (chmod (fname, mode) < 0)
- error (0, errno, "cannot change mode of file %s", fname);
-}
-
-/*
- * Rename a file and die if it fails
- */
-void
-rename_file (from, to)
- const char *from;
- const char *to;
-{
- if (trace)
- (void) fprintf (stderr, "%s-> rename(%s,%s)\n",
- CLIENT_SERVER_STR, from, to);
- if (noexec)
- return;
-
- if (rename (from, to) < 0)
- error (1, errno, "cannot rename file %s to %s", from, to);
-}
-
-/*
- * unlink a file, if possible.
- */
-int
-unlink_file (f)
- const char *f;
-{
- if (trace)
- (void) fprintf (stderr, "%s-> unlink_file(%s)\n",
- CLIENT_SERVER_STR, f);
- if (noexec)
- return (0);
-
- return (CVS_UNLINK (f));
-}
-
-/*
- * Unlink a file or dir, if possible. If it is a directory do a deep
- * removal of all of the files in the directory. Return -1 on error
- * (in which case errno is set).
- */
-int
-unlink_file_dir (f)
- const char *f;
-{
- struct stat sb;
-
- /* This is called by the server parent process in contexts where
- it is not OK to send output (e.g. after we sent "ok" to the
- client). */
- if (trace && !server_active)
- (void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f);
-
- if (noexec)
- return (0);
-
- /* For at least some unices, if root tries to unlink() a directory,
- instead of doing something rational like returning EISDIR,
- the system will gleefully go ahead and corrupt the filesystem.
- So we first call stat() to see if it is OK to call unlink(). This
- doesn't quite work--if someone creates a directory between the
- call to stat() and the call to unlink(), we'll still corrupt
- the filesystem. Where is the Unix Haters Handbook when you need
- it? */
- if (stat (f, &sb) < 0)
- {
- if (existence_error (errno))
- {
- /* The file or directory doesn't exist anyhow. */
- return -1;
- }
- }
- else if (S_ISDIR (sb.st_mode))
- return deep_remove_dir (f);
-
- return CVS_UNLINK (f);
-}
-
-/* Remove a directory and everything it contains. Returns 0 for
- * success, -1 for failure (in which case errno is set).
- */
-
-static int
-deep_remove_dir (path)
- const char *path;
-{
- DIR *dirp;
- struct dirent *dp;
-
- if (rmdir (path) != 0)
- {
- if (errno == ENOTEMPTY
- || errno == EEXIST
- /* Ugly workaround for ugly AIX 4.1 (and 3.2) header bug
- (it defines ENOTEMPTY and EEXIST to 17 but actually
- returns 87). */
- || (ENOTEMPTY == 17 && EEXIST == 17 && errno == 87))
- {
- if ((dirp = CVS_OPENDIR (path)) == NULL)
- /* If unable to open the directory return
- * an error
- */
- return -1;
-
- errno = 0;
- while ((dp = CVS_READDIR (dirp)) != NULL)
- {
- char *buf;
-
- if (strcmp (dp->d_name, ".") == 0 ||
- strcmp (dp->d_name, "..") == 0)
- continue;
-
- buf = xmalloc (strlen (path) + strlen (dp->d_name) + 5);
- sprintf (buf, "%s/%s", path, dp->d_name);
-
- /* See comment in unlink_file_dir explanation of why we use
- isdir instead of just calling unlink and checking the
- status. */
- if (isdir(buf))
- {
- if (deep_remove_dir(buf))
- {
- CVS_CLOSEDIR(dirp);
- free (buf);
- return -1;
- }
- }
- else
- {
- if (CVS_UNLINK (buf) != 0)
- {
- CVS_CLOSEDIR(dirp);
- free (buf);
- return -1;
- }
- }
- free (buf);
-
- errno = 0;
- }
- if (errno != 0)
- {
- int save_errno = errno;
- CVS_CLOSEDIR (dirp);
- errno = save_errno;
- return -1;
- }
- CVS_CLOSEDIR (dirp);
- return rmdir (path);
- }
- else
- return -1;
- }
-
- /* Was able to remove the directory return 0 */
- return 0;
-}
-
-/* Read NCHARS bytes from descriptor FD into BUF.
- Return the number of characters successfully read.
- The number returned is always NCHARS unless end-of-file or error. */
-static size_t
-block_read (fd, buf, nchars)
- int fd;
- char *buf;
- size_t nchars;
-{
- char *bp = buf;
- size_t nread;
-
- do
- {
- nread = read (fd, bp, nchars);
- if (nread == (size_t)-1)
- {
-#ifdef EINTR
- if (errno == EINTR)
- continue;
-#endif
- return (size_t)-1;
- }
-
- if (nread == 0)
- break;
-
- bp += nread;
- nchars -= nread;
- } while (nchars != 0);
-
- return bp - buf;
-}
-
-
-/*
- * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
- * If FILE1 and FILE2 are special files, compare their salient characteristics
- * (i.e. major/minor device numbers, links, etc.
- */
-int
-xcmp (file1, file2)
- const char *file1;
- const char *file2;
-{
- char *buf1, *buf2;
- struct stat sb1, sb2;
- int fd1, fd2;
- int ret;
-
- if (CVS_LSTAT (file1, &sb1) < 0)
- error (1, errno, "cannot lstat %s", file1);
- if (CVS_LSTAT (file2, &sb2) < 0)
- error (1, errno, "cannot lstat %s", file2);
-
- /* If FILE1 and FILE2 are not the same file type, they are unequal. */
- if ((sb1.st_mode & S_IFMT) != (sb2.st_mode & S_IFMT))
- return 1;
-
- /* If FILE1 and FILE2 are symlinks, they are equal if they point to
- the same thing. */
-#ifdef S_ISLNK
- if (S_ISLNK (sb1.st_mode) && S_ISLNK (sb2.st_mode))
- {
- int result;
- buf1 = xreadlink (file1);
- buf2 = xreadlink (file2);
- result = (strcmp (buf1, buf2) == 0);
- free (buf1);
- free (buf2);
- return result;
- }
-#endif
-
- /* If FILE1 and FILE2 are devices, they are equal if their device
- numbers match. */
- if (S_ISBLK (sb1.st_mode) || S_ISCHR (sb1.st_mode))
- {
-#ifdef HAVE_STRUCT_STAT_ST_RDEV
- if (sb1.st_rdev == sb2.st_rdev)
- return 0;
- else
- return 1;
-#else
- error (1, 0, "cannot compare device files on this system (%s and %s)",
- file1, file2);
-#endif
- }
-
- if ((fd1 = open (file1, O_RDONLY)) < 0)
- error (1, errno, "cannot open file %s for comparing", file1);
- if ((fd2 = open (file2, O_RDONLY)) < 0)
- error (1, errno, "cannot open file %s for comparing", file2);
-
- /* A generic file compare routine might compare st_dev & st_ino here
- to see if the two files being compared are actually the same file.
- But that won't happen in CVS, so we won't bother. */
-
- if (sb1.st_size != sb2.st_size)
- ret = 1;
- else if (sb1.st_size == 0)
- ret = 0;
- else
- {
- /* FIXME: compute the optimal buffer size by computing the least
- common multiple of the files st_blocks field */
- size_t buf_size = 8 * 1024;
- size_t read1;
- size_t read2;
-
- buf1 = xmalloc (buf_size);
- buf2 = xmalloc (buf_size);
-
- do
- {
- read1 = block_read (fd1, buf1, buf_size);
- if (read1 == (size_t)-1)
- error (1, errno, "cannot read file %s for comparing", file1);
-
- read2 = block_read (fd2, buf2, buf_size);
- if (read2 == (size_t)-1)
- error (1, errno, "cannot read file %s for comparing", file2);
-
- /* assert (read1 == read2); */
-
- ret = memcmp(buf1, buf2, read1);
- } while (ret == 0 && read1 == buf_size);
-
- free (buf1);
- free (buf2);
- }
-
- (void) close (fd1);
- (void) close (fd2);
- return (ret);
-}
-
-/* Generate a unique temporary filename. Returns a pointer to a newly
- * malloc'd string containing the name. Returns successfully or not at
- * all.
- *
- * THIS FUNCTION IS DEPRECATED!!! USE cvs_temp_file INSTEAD!!!
- *
- * and yes, I know about the way the rcs commands use temp files. I think
- * they should be converted too but I don't have time to look into it right
- * now.
- */
-char *
-cvs_temp_name ()
-{
- char *fn;
- FILE *fp;
-
- fp = cvs_temp_file (&fn);
- if (fp == NULL)
- error (1, errno, "Failed to create temporary file %s",
- fn ? fn : "(null)");
- if (fclose (fp) == EOF)
- error (0, errno, "Failed to close temporary file %s", fn);
- return fn;
-}
-
-/* Generate a unique temporary filename and return an open file stream
- * to the truncated file by that name
- *
- * INPUTS
- * filename where to place the pointer to the newly allocated file
- * name string
- *
- * OUTPUTS
- * filename dereferenced, will point to the newly allocated file
- * name string. This value is undefined if the function
- * returns an error.
- *
- * RETURNS
- * An open file pointer to a read/write mode empty temporary file with the
- * unique file name or NULL on failure.
- *
- * ERRORS
- * on error, errno will be set to some value either by CVS_FOPEN or
- * whatever system function is called to generate the temporary file name
- */
-/* There are at least four functions for generating temporary
- * filenames. We use mkstemp (BSD 4.3) if possible, else tempnam (SVID 3),
- * else mktemp (BSD 4.3), and as last resort tmpnam (POSIX). Reason is that
- * mkstemp, tempnam, and mktemp both allow to specify the directory in which
- * the temporary file will be created.
- *
- * And the _correct_ way to use the deprecated functions probably involves
- * opening file descriptors using O_EXCL & O_CREAT and even doing the annoying
- * NFS locking thing, but until I hear of more problems, I'm not going to
- * bother.
- */
-FILE *
-cvs_temp_file (filename)
- char **filename;
-{
- char *fn;
- FILE *fp;
-
- /* FIXME - I'd like to be returning NULL here in noexec mode, but I think
- * some of the rcs & diff functions which rely on a temp file run in
- * noexec mode too.
- */
-
- assert (filename != NULL);
-
-#ifdef HAVE_MKSTEMP
-
- {
- int fd;
-
- fn = xmalloc (strlen (Tmpdir) + 11);
- sprintf (fn, "%s/%s", Tmpdir, "cvsXXXXXX" );
- fd = mkstemp (fn);
-
- /* a NULL return will be interpreted by callers as an error and
- * errno should still be set
- */
- if (fd == -1) fp = NULL;
- else if ((fp = CVS_FDOPEN (fd, "w+")) == NULL)
- {
- /* Attempt to close and unlink the file since mkstemp returned
- * sucessfully and we believe it's been created and opened.
- */
- int save_errno = errno;
- if (close (fd))
- error (0, errno, "Failed to close temporary file %s", fn);
- if (CVS_UNLINK (fn))
- error (0, errno, "Failed to unlink temporary file %s", fn);
- errno = save_errno;
- }
-
- if (fp == NULL)
- {
- free (fn);
- fn = NULL;
- }
- /* mkstemp is defined to open mode 0600 using glibc 2.0.7+ */
- /* FIXME - configure can probably tell us which version of glibc we are
- * linking to and not chmod for 2.0.7+
- */
- else chmod (fn, 0600);
-
- }
-
-#elif HAVE_TEMPNAM
-
- /* tempnam has been deprecated due to under-specification */
-
- fn = tempnam (Tmpdir, "cvs");
- if (fn == NULL) fp = NULL;
- else if ((fp = CVS_FOPEN (fn, "w+")) == NULL)
- {
- free (fn);
- fn = NULL;
- }
- else chmod (fn, 0600);
-
- /* tempnam returns a pointer to a newly malloc'd string, so there's
- * no need for a xstrdup
- */
-
-#elif HAVE_MKTEMP
-
- /* mktemp has been deprecated due to the BSD 4.3 specification specifying
- * that XXXXXX will be replaced by a PID and a letter, creating only 26
- * possibilities, a security risk, and a race condition.
- */
-
- {
- char *ifn;
-
- ifn = xmalloc (strlen (Tmpdir) + 11);
- sprintf (ifn, "%s/%s", Tmpdir, "cvsXXXXXX" );
- fn = mktemp (ifn);
-
- if (fn == NULL) fp = NULL;
- else fp = CVS_FOPEN (fn, "w+");
-
- if (fp == NULL) free (ifn);
- else chmod (fn, 0600);
-
- }
-
-#else /* use tmpnam if all else fails */
-
- /* tmpnam is deprecated */
-
- {
- char ifn[L_tmpnam + 1];
-
- fn = tmpnam (ifn);
-
- if (fn == NULL) fp = NULL;
- else if ((fp = CVS_FOPEN (ifn, "w+")) != NULL)
- {
- fn = xstrdup (ifn);
- chmod (fn, 0600);
- }
-
- }
-
-#endif
-
- *filename = fn;
- if (fn == NULL && fp != NULL)
- {
- fclose (fp);
- fp = NULL;
- }
- return fp;
-}
-
-
-
-#ifdef HAVE_READLINK
-/* char *
- * xreadlink ( const char *link )
- *
- * Like the X/OPEN and 4.4BSD readlink() function, but allocates and returns
- * its own buf.
- *
- * INPUTS
- * link The original path.
- *
- * RETURNS
- * The resolution of the final symbolic link in the path.
- *
- * ERRORS
- * This function exits with a fatal error if it fails to read the link for
- * any reason.
- */
-#define MAXSIZE (SIZE_MAX < SSIZE_MAX ? SIZE_MAX : SSIZE_MAX)
-
-char *
-xreadlink (link)
- const char *link;
-{
- char *file = NULL;
- size_t buflen = BUFSIZ;
-
- /* Get the name of the file to which `from' is linked. */
- while (1)
- {
- ssize_t r;
- size_t link_name_len;
-
- file = xrealloc (file, buflen);
- r = readlink (link, file, buflen);
- link_name_len = r;
-
- if (r < 0
-#ifdef ERANGE
- /* AIX 4 and HP-UX report ERANGE if the buffer is too small. */
- && errno != ERANGE
-#endif
- )
- error (1, errno, "cannot readlink %s", link);
-
- /* If there is space for the NUL byte, set it and return. */
- if (r >= 0 && link_name_len < buflen)
- {
- file[link_name_len] = '\0';
- return file;
- }
-
- if (buflen <= MAXSIZE / 2)
- buflen *= 2;
- else if (buflen < MAXSIZE)
- buflen = MAXSIZE;
- else
- /* Our buffer cannot grow any bigger. */
- error (1, ENAMETOOLONG, "cannot readlink %s", link);
- }
-}
-#endif /* HAVE_READLINK */
-
-
-
-/* char *
- * xresolvepath ( const char *path )
- *
- * Like xreadlink(), but resolve all links in a path.
- *
- * INPUTS
- * path The original path.
- *
- * RETURNS
- * The path with any symbolic links expanded.
- *
- * ERRORS
- * This function exits with a fatal error if it fails to read the link for
- * any reason.
- */
-char *
-xresolvepath ( path )
- const char *path;
-{
- char *hardpath;
- char *owd;
-
- assert ( isdir ( path ) );
-
- /* FIXME - If HAVE_READLINK is defined, we should probably walk the path
- * bit by bit calling xreadlink().
- */
-
- owd = xgetwd();
- if ( CVS_CHDIR ( path ) < 0)
- error ( 1, errno, "cannot chdir to %s", path );
- if ( ( hardpath = xgetwd() ) == NULL )
- error (1, errno, "cannot getwd in %s", path);
- if ( CVS_CHDIR ( owd ) < 0)
- error ( 1, errno, "cannot chdir to %s", owd );
- free (owd);
- return hardpath;
-}
-
-
-
-/* Return a pointer into PATH's last component. */
-const char *
-last_component (path)
- const char *path;
-{
- const char *last = strrchr (path, '/');
-
- assert (path);
- if (last && (last != path))
- return last + 1;
- else
- return path;
-}
-
-/* Return the home directory. Returns a pointer to storage
- managed by this function or its callees (currently getenv).
- This function will return the same thing every time it is
- called. Returns NULL if there is no home directory.
-
- Note that for a pserver server, this may return root's home
- directory. What typically happens is that upon being started from
- inetd, before switching users, the code in cvsrc.c calls
- get_homedir which remembers root's home directory in the static
- variable. Then the switch happens and get_homedir might return a
- directory that we don't even have read or execute permissions for
- (which is bad, when various parts of CVS try to read there). One
- fix would be to make the value returned by get_homedir only good
- until the next call (which would free the old value). Another fix
- would be to just always malloc our answer, and let the caller free
- it (that is best, because some day we may need to be reentrant).
-
- The workaround is to put -f in inetd.conf which means that
- get_homedir won't get called until after the switch in user ID.
-
- The whole concept of a "home directory" on the server is pretty
- iffy, although I suppose some people probably are relying on it for
- .cvsrc and such, in the cases where it works. */
-char *
-get_homedir ()
-{
- static char *home = NULL;
- char *env;
- struct passwd *pw;
-
- if (home != NULL)
- return home;
-
- if (!server_active && (env = getenv ("HOME")) != NULL)
- home = env;
- else if ((pw = (struct passwd *) getpwuid (getuid ()))
- && pw->pw_dir)
- home = xstrdup (pw->pw_dir);
- else
- return 0;
-
- return home;
-}
-
-/* Compose a path to a file in the home directory. This is necessary because
- * of different behavior on UNIX and VMS. See the notes in vms/filesubr.c.
- *
- * A more clean solution would be something more along the lines of a
- * "join a directory to a filename" kind of thing which was not specific to
- * the homedir. This should aid portability between UNIX, Mac, Windows, VMS,
- * and possibly others. This is already handled by Perl - it might be
- * interesting to see how much of the code was written in C since Perl is under
- * the GPL and the Artistic license - we might be able to use it.
- */
-char *
-strcat_filename_onto_homedir (dir, file)
- const char *dir;
- const char *file;
-{
- char *path = xmalloc (strlen (dir) + 1 + strlen(file) + 1);
- sprintf (path, "%s/%s", dir, file);
- return path;
-}
-
-/* See cvs.h for description. On unix this does nothing, because the
- shell expands the wildcards. */
-void
-expand_wild (argc, argv, pargc, pargv)
- int argc;
- char **argv;
- int *pargc;
- char ***pargv;
-{
- int i;
- assert (argv || !argc);
- if (size_overflow_p (xtimes (argc, sizeof (char *)))) {
- *pargc = 0;
- *pargv = NULL;
- error (0, 0, "expand_wild: too many arguments");
- return;
- }
- *pargc = argc;
- *pargv = xmalloc (xtimes (argc, sizeof (char *)));
- for (i = 0; i < argc; ++i)
- (*pargv)[i] = xstrdup (argv[i]);
-}
-
-
-
-#ifdef SERVER_SUPPORT
-/* Case-insensitive string compare. I know that some systems
- have such a routine, but I'm not sure I see any reasons for
- dealing with the hair of figuring out whether they do (I haven't
- looked into whether this is a performance bottleneck; I would guess
- not). */
-int
-cvs_casecmp (str1, str2)
- const char *str1;
- const char *str2;
-{
- const char *p;
- const char *q;
- int pqdiff;
-
- p = str1;
- q = str2;
- while ((pqdiff = tolower (*p) - tolower (*q)) == 0)
- {
- if (*p == '\0')
- return 0;
- ++p;
- ++q;
- }
- return pqdiff;
-}
-#endif /* SERVER_SUPPORT */
OpenPOWER on IntegriCloud