#include "cvs.h"
#include <assert.h>
static int deep_remove_dir PROTO((const char *path));
void
copy_file (from_file, to_file)
const char *from_file;
const char *to_file;
{
char from[PATH_MAX], to[PATH_MAX];
struct stat sb;
struct utimbuf t;
int fdin, fdout;
if (isabsolute(from_file))
strcpy(from, from_file);
else
sprintf(from, "./%s", from_file);
if (isabsolute(to_file))
strcpy(to, to_file);
else
sprintf(to, "./%s", to_file);
if (trace)
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> copy(%s,%s)\n",
(server_active) ? 'S' : ' ', from, to);
#else
(void) fprintf (stderr, "-> copy(%s,%s)\n", from, to);
#endif
if (noexec)
return;
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);
memset ((char *) &t, 0, sizeof (t));
t.actime = sb.st_atime;
t.modtime = sb.st_mtime;
(void) utime (to, &t);
}
int
isdir (file)
const char *file;
{
struct stat sb;
if (stat (file, &sb) < 0)
return (0);
return (S_ISDIR (sb.st_mode));
}
int
islink (file)
const char *file;
{
#ifdef S_ISLNK
struct stat sb;
if (lstat (file, &sb) < 0)
return (0);
return (S_ISLNK (sb.st_mode));
#else
return (0);
#endif
}
int
isfile (file)
const char *file;
{
return isaccessible(file, F_OK);
}
int
isreadable (file)
const char *file;
{
return isaccessible(file, R_OK);
}
int
iswritable (file)
const char *file;
{
return isaccessible(file, W_OK);
}
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;
if (stat(file, &sb) == -1)
return 0;
if (mode == F_OK)
return 1;
uid = geteuid();
if (uid == 0)
{
if (mode & X_OK)
return sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH);
else
return 1;
}
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;
}
if (sb.st_uid == uid)
return (sb.st_mode & umask) == umask;
else if (sb.st_gid == getegid())
return (sb.st_mode & gmask) == gmask;
else
return (sb.st_mode & omask) == omask;
#else
return access(file, mode) == 0;
#endif
}
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);
}
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);
}
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);
}
int
mkdir_if_needed (name)
char *name;
{
if (mkdir (name, 0777) < 0)
{
if (errno != EEXIST
#ifdef EACCESS
&& errno != EACCESS
#endif
)
error (1, errno, "cannot make directory %s", name);
return 1;
}
return 0;
}
void
xchmod (fname_file, writable)
char *fname_file;
int writable;
{
char fname[PATH_MAX];
struct stat sb;
mode_t mode, oumask;
if (isabsolute(fname_file))
strcpy(fname, fname_file);
else
sprintf(fname, "./%s", fname_file);
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)
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> chmod(%s,%o)\n",
(server_active) ? 'S' : ' ', fname, mode);
#else
(void) fprintf (stderr, "-> chmod(%s,%o)\n", fname, mode);
#endif
if (noexec)
return;
if (chmod (fname, mode) < 0)
error (0, errno, "cannot change mode of file %s", fname);
}
void
rename_file (from_file, to_file)
const char *from_file;
const char *to_file;
{
char from[PATH_MAX], to[PATH_MAX];
if (isabsolute(from_file))
strcpy(from, from_file);
else
sprintf(from, "./%s", from_file);
if (isabsolute(to_file))
strcpy(to, to_file);
else
sprintf(to, "./%s", to_file);
if (trace)
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> rename(%s,%s)\n",
(server_active) ? 'S' : ' ', from, to);
#else
(void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
#endif
if (noexec)
return;
if (rename (from, to) < 0)
error (1, errno, "cannot rename file %s to %s", from, to);
}
int
unlink_file (f_file)
const char *f_file;
{
char f[PATH_MAX];
if (isabsolute(f_file))
strcpy(f, f_file);
else
sprintf(f, "./%s", f_file);
if (trace)
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> unlink(%s)\n",
(server_active) ? 'S' : ' ', f);
#else
(void) fprintf (stderr, "-> unlink(%s)\n", f);
#endif
if (noexec)
return (0);
return (vms_unlink (f));
}
int
unlink_file_dir (f_file)
const char *f_file;
{
char f[PATH_MAX];
if (isabsolute(f_file))
strcpy(f, f_file);
else
sprintf(f, "./%s", f_file);
if (trace)
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> unlink_file_dir(%s)\n",
(server_active) ? 'S' : ' ', f);
#else
(void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f);
#endif
if (noexec)
return (0);
if (vms_unlink (f) != 0)
{
if (errno == EISDIR || errno == EPERM)
return deep_remove_dir (f);
else
return -1;
}
return 0;
}
static int
deep_remove_dir (path)
const char *path;
{
DIR *dirp;
struct dirent *dp;
char buf[PATH_MAX];
if (rmdir (path) != 0 && (errno == ENOTEMPTY || errno == EEXIST))
{
if ((dirp = CVS_OPENDIR (path)) == NULL)
return -1;
while ((dp = CVS_READDIR (dirp)) != NULL)
{
if (strcmp (dp->d_name, ".") == 0 ||
strcmp (dp->d_name, "..") == 0)
continue;
sprintf (buf, "%s/%s", path, dp->d_name);
if (vms_unlink (buf) != 0 )
{
if (errno == EISDIR || errno == EPERM)
{
if (deep_remove_dir (buf))
{
CVS_CLOSEDIR (dirp);
return -1;
}
}
else
{
CVS_CLOSEDIR (dirp);
return -1;
}
}
}
CVS_CLOSEDIR (dirp);
return rmdir (path);
}
return 0;
}
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;
}
int
xcmp (file1_file, file2_file)
const char *file1_file;
const char *file2_file;
{
char file1[PATH_MAX], file2[PATH_MAX];
char *buf1, *buf2;
struct stat sb1, sb2;
int fd1, fd2;
int ret;
if (isabsolute(file1_file))
strcpy(file1, file1_file);
else
sprintf(file1, "./%s", file1_file);
if (isabsolute(file2_file))
strcpy(file2, file2_file);
else
sprintf(file2, "./%s", file2_file);
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);
if (fstat (fd1, &sb1) < 0)
error (1, errno, "cannot fstat %s", file1);
if (fstat (fd2, &sb2) < 0)
error (1, errno, "cannot fstat %s", file2);
if (sb1.st_size != sb2.st_size)
ret = 1;
else if (sb1.st_size == 0)
ret = 0;
else
{
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);
}
unsigned char
VMS_filename_classes[] =
{
0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07,
0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f,
0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17,
0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f,
0x20,0x21,0x22,0x23, 0x24,0x25,0x26,0x27,
0x28,0x29,0x2a,0x2b, 0x2c,0x2d,0x2e,0x2f,
0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
0x38,0x39,0x3a,0x3b, 0x3c,0x3d,0x3e,0x3f,
0x40,0x61,0x62,0x63, 0x64,0x65,0x66,0x67,
0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f,
0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77,
0x78,0x79,0x7a,0x5b, 0x5c,0x5d,0x5e,0x5f,
0x60,0x61,0x62,0x63, 0x64,0x65,0x66,0x67,
0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f,
0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77,
0x78,0x79,0x7a,0x7b, 0x7c,0x7d,0x7e,0x7f,
0x80,0x81,0x82,0x83, 0x84,0x85,0x86,0x87,
0x88,0x89,0x8a,0x8b, 0x8c,0x8d,0x8e,0x8f,
0x90,0x91,0x92,0x93, 0x94,0x95,0x96,0x97,
0x98,0x99,0x9a,0x9b, 0x9c,0x9d,0x9e,0x9f,
0xa0,0xa1,0xa2,0xa3, 0xa4,0xa5,0xa6,0xa7,
0xa8,0xa9,0xaa,0xab, 0xac,0xad,0xae,0xaf,
0xb0,0xb1,0xb2,0xb3, 0xb4,0xb5,0xb6,0xb7,
0xb8,0xb9,0xba,0xbb, 0xbc,0xbd,0xbe,0xbf,
0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7,
0xc8,0xc9,0xca,0xcb, 0xcc,0xcd,0xce,0xcf,
0xd0,0xd1,0xd2,0xd3, 0xd4,0xd5,0xd6,0xd7,
0xd8,0xd9,0xda,0xdb, 0xdc,0xdd,0xde,0xdf,
0xe0,0xe1,0xe2,0xe3, 0xe4,0xe5,0xe6,0xe7,
0xe8,0xe9,0xea,0xeb, 0xec,0xed,0xee,0xef,
0xf0,0xf1,0xf2,0xf3, 0xf4,0xf5,0xf6,0xf7,
0xf8,0xf9,0xfa,0xfb, 0xfc,0xfd,0xfe,0xff,
};
int
fncmp (const char *n1, const char *n2)
{
while (*n1 && *n2
&& (VMS_filename_classes[(unsigned char) *n1]
== VMS_filename_classes[(unsigned char) *n2]))
n1++, n2++;
return (VMS_filename_classes[(unsigned char) *n1]
- VMS_filename_classes[(unsigned char) *n2]);
}
void
fnfold (char *filename)
{
while (*filename)
{
*filename = FOLD_FN_CHAR (*filename);
filename++;
}
}
char *
cvs_temp_name ()
{
char *fn;
FILE *fp;
fp = cvs_temp_file (&fn);
if (fp == NULL)
error (1, errno, "Failed to create temporary file");
if (fclose (fp) == EOF)
error (0, errno, "Failed to close temporary file %s", fn);
return fn;
}
FILE *cvs_temp_file (filename)
char **filename;
{
char *fn;
FILE *fp;
assert (filename != NULL);
#ifdef HAVE_MKSTEMP
{
int fd;
fn = xmalloc (strlen (Tmpdir) + 11);
sprintf (fn, "%s/%s", Tmpdir, "cvsXXXXXX" );
fd = mkstemp (fn);
if (fd == -1) fp = NULL;
else if ((fp = CVS_FDOPEN (fd, "w+")) == NULL)
{
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);
else chmod (fn, 0600);
}
#elif HAVE_TEMPNAM
fn = tempnam (Tmpdir, "cvs");
if (fn == NULL) fp = NULL;
else if ((fp = CVS_FOPEN (fn, "w+")) == NULL) free (fn);
else chmod (fn, 0600);
#elif HAVE_MKTEMP
{
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
{
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;
return fp;
}
char *
xresolvepath ( path )
const char *path;
{
char *hardpath;
char *owd;
assert ( isdir ( path ) );
owd = xgetwd();
if ( CVS_CHDIR ( path ) < 0)
error ( 1, errno, "cannot chdir to %s", path );
if ( ( hardpath = xgetwd() ) == NULL )
error (1, errno, "cannot readlink %s", hardpath);
if ( CVS_CHDIR ( owd ) < 0)
error ( 1, errno, "cannot chdir to %s", owd );
free (owd);
return hardpath;
}
char *
last_component (path)
char *path;
{
char *last = strrchr (path, '/');
if (last && (last != path))
return last + 1;
else
return path;
}
char *
get_homedir ()
{
return getenv ("HOME");
}
char *
strcat_filename_onto_homedir (dir, file)
const char *dir;
const char *file;
{
char *path = xmalloc (strlen (dir) + strlen(file) + 1);
sprintf (path, "%s%s", dir, file);
return path;
}
#ifndef __VMS_VER
#define __VMS_VER 0
#endif
#ifndef __DECC_VER
#define __DECC_VER 0
#endif
#if __VMS_VER < 70200000 || __DECC_VER < 50700000
void
expand_wild (argc, argv, pargc, pargv)
int argc;
char **argv;
int *pargc;
char ***pargv;
{
int i;
*pargc = argc;
*pargv = (char **) xmalloc (argc * sizeof (char *));
for (i = 0; i < argc; ++i)
(*pargv)[i] = xstrdup (argv[i]);
}
#else
static char CurWorkingDir[PATH_MAX+1];
static char **ArgvList;
static int CurArg;
static int MaxArgs;
static int ew_no_op (char *fname) {
(void) fname;
return 1;
}
static int ew_add_file (char *fname) {
char *lastslash, *firstper;
int i;
if (strncmp(fname,CurWorkingDir,strlen(CurWorkingDir)) == 0) {
fname += strlen(CurWorkingDir);
}
lastslash = strrchr(fname,'/');
if (!lastslash) {
lastslash = fname;
}
if ((firstper=strchr(lastslash,'.')) != strrchr(lastslash,'.')) {
*strrchr(fname,'.') = '\0';
}
if (firstper && firstper[1]=='\0') {
*firstper = '\0';
}
for (i=0; i<CurArg && strcmp(ArgvList[i],fname)!=0; ++i) {
;
}
if (i==CurArg && CurArg<MaxArgs) {
ArgvList[CurArg++] = xstrdup(fname);
}
return ArgvList[CurArg-1] != 0;
}
static void wait_and_protect_globs (void) {
return;
}
static void release_globs (void) {
return;
}
void expand_wild (int argc, char **argv, int *pargc, char ***pargv) {
int totfiles, filesgotten;
int i;
int largc;
char **largv;
for (totfiles=0,i=0; i<argc; ++i) {
char *arg = argv[i];
if (arg != 0 && ( strchr(arg,' ') != 0
|| strcmp(arg,".") == 0
|| strcmp(arg,"..") == 0) ) {
++totfiles;
}else if (arg != 0) {
int num;
char *p = arg;
while ( (p=strchr(p,',')) != 0) {
*p = '\0';
num = decc$from_vms (arg, ew_no_op, 1);
totfiles += num>0 ? num : 1;
*p++ = ',';
arg = p;
}
if (*arg != '\0') {
num = decc$from_vms (arg, ew_no_op, 1);
totfiles += num>0 ? num : 1;
}
}
}
largv = 0;
if (totfiles) {
largv = xmalloc (sizeof*largv * (totfiles + 1));
}
filesgotten = 0;
if (largv != 0) {
int len;
for (i=totfiles; --i>=0; ) {
largv[i] = 0;
}
largv[totfiles] = 0;
wait_and_protect_globs ();
(void) getcwd (CurWorkingDir, sizeof CurWorkingDir - 1, 0);
len = strlen (CurWorkingDir);
if ( len > 0 && CurWorkingDir[len-1] != '/') {
(void) strcat (CurWorkingDir, "/");
}
CurArg = 0;
ArgvList = largv;
MaxArgs = totfiles + 1;
for (i=0; i<argc; ++i) {
char *arg = argv[i];
if (arg != 0 && ( strchr(arg,' ') != 0
|| strcmp(arg,".") == 0
|| strcmp(arg,"..") == 0) ) {
if (CurArg < MaxArgs) {
ArgvList[CurArg++] = xstrdup(arg);
}
++filesgotten;
}else if (arg != 0) {
char *p = arg;
int num;
while ( (p=strchr(p,',')) != 0) {
*p = '\0';
num = decc$from_vms (arg, ew_add_file, 1);
if (num <= 0 && CurArg < MaxArgs) {
ArgvList[CurArg++] = xstrdup(arg);
}
filesgotten += num>0 ? num : 1;
*p++ = ',';
arg = p;
}
if (*arg != '\0') {
num = decc$from_vms (arg, ew_add_file, 1);
if (num <= 0 && CurArg < MaxArgs) {
ArgvList[CurArg++] = xstrdup(arg);
}
filesgotten += num>0 ? num : 1;
}
}
}
if (filesgotten != totfiles) {
;
}
filesgotten = CurArg;
release_globs();
}
if (!largv) {
(*pargv) = xmalloc (sizeof(char *));
if ((*pargv) != 0) {
*(*pargv) = 0;
}
}else {
(*pargv) = largv;
}
(*pargc) = largv ? filesgotten : 0;
return;
}
#endif