#include <io.h>
#include <windows.h>
#include "cvs.h"
static int deep_remove_dir PROTO((const char *path));
void
copy_file (from, to)
const char *from;
const char *to;
{
struct stat sb;
struct utimbuf t;
int fdin, fdout;
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 | O_BINARY)) < 0)
error (1, errno, "cannot open %s for copying", from);
if (fstat (fdin, &sb) < 0)
error (1, errno, "cannot fstat %s", from);
if ((fdout = open (to, O_CREAT | O_TRUNC | O_RDWR | O_BINARY,
(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) < 0)
error (1, errno, "cannot make directory %s", name);
}
void
make_directories (name)
const char *name;
{
char *cp;
if (noexec)
return;
if (mkdir (name) == 0 || errno == EEXIST)
return;
if (errno != ENOENT)
{
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);
}
int
mkdir_if_needed (name)
char *name;
{
if (mkdir (name) < 0)
{
if (errno != EEXIST
#ifdef EACCESS
&& errno != EACCESS
#endif
#ifdef EACCES
&& errno != EACCES
#endif
)
error (1, errno, "cannot make directory %s", name);
return 1;
}
return 0;
}
void
xchmod (fname, writable)
char *fname;
int writable;
{
struct stat sb;
mode_t mode, oumask;
if (stat (fname, &sb) < 0)
{
if (!noexec)
error (0, errno, "cannot stat %s", fname);
return;
}
if (writable)
{
oumask = umask (0);
(void) umask (oumask);
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);
}
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);
}
int
readlink (char *path, char *buf, int buf_size)
{
errno = EINVAL;
return -1;
}
void
rename_file (from, to)
const char *from;
const char *to;
{
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;
chmod(to, S_IWRITE);
unlink(to);
if (rename (from, to) < 0)
error (1, errno, "cannot rename file %s to %s", from, to);
}
int
unlink_file (f)
const char *f;
{
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);
chmod (f, _S_IWRITE);
return (unlink (f));
}
int
unlink_file_dir (f)
const char *f;
{
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);
chmod (f, _S_IWRITE);
if (unlink (f) != 0)
{
if (errno == EISDIR || errno == EACCES || errno == ENOENT)
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 == EACCES))
{
if ((dirp = opendir (path)) == NULL)
return -1;
while ((dp = readdir (dirp)) != NULL)
{
if (strcmp (dp->d_name, ".") == 0 ||
strcmp (dp->d_name, "..") == 0)
continue;
sprintf (buf, "%s/%s", path, dp->d_name);
chmod (buf, _S_IWRITE);
if (unlink (buf) != 0 )
{
if (errno == EISDIR || errno == EACCES || errno == ENOENT)
{
if (deep_remove_dir (buf))
{
closedir (dirp);
return -1;
}
}
else
{
closedir (dirp);
return -1;
}
}
}
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, file2)
const char *file1;
const char *file2;
{
char *buf1, *buf2;
struct stat sb1, sb2;
int fd1, fd2;
int ret;
if ((fd1 = open (file1, O_RDONLY | O_BINARY)) < 0)
error (1, errno, "cannot open file %s for comparing", file1);
if ((fd2 = open (file2, O_RDONLY | O_BINARY)) < 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);
ret = memcmp(buf1, buf2, read1);
} while (ret == 0 && read1 == buf_size);
free (buf1);
free (buf2);
}
(void) close (fd1);
(void) close (fd2);
return (ret);
}
char *
cvs_temp_name ()
{
char *retval;
retval = _tempnam (NULL, NULL);
if (retval == NULL)
error (1, errno, "cannot generate temporary filename");
return retval;
}
int
isabsolute (filename)
const char *filename;
{
return (ISDIRSEP (filename[0])
|| (filename[0] != '\0'
&& filename[1] == ':'
&& ISDIRSEP (filename[2])));
}
char *
last_component (char *path)
{
char *scan;
char *last = 0;
for (scan = path; *scan; scan++)
if (ISDIRSEP (*scan))
last = scan;
if (last && (last != path))
return last + 1;
else
return path;
}
char *
get_homedir ()
{
static char *pathbuf;
char *hd, *hp;
if (pathbuf != NULL)
return pathbuf;
else if ((hd = getenv ("HOME")))
return hd;
else if ((hd = getenv ("HOMEDRIVE")) && (hp = getenv ("HOMEPATH")))
{
pathbuf = xmalloc (strlen (hd) + strlen (hp) + 5);
strcpy (pathbuf, hd);
strcat (pathbuf, hp);
return pathbuf;
}
else
return NULL;
}
void
expand_wild (argc, argv, pargc, pargv)
int argc;
char **argv;
int *pargc;
char ***pargv;
{
int i;
int new_argc;
char **new_argv;
int max_new_argc;
new_argc = 0;
max_new_argc = argc + 1;
new_argv = (char **) xmalloc (max_new_argc * sizeof (char *));
for (i = 0; i < argc; ++i)
{
HANDLE h;
WIN32_FIND_DATA fdata;
char *last_forw_slash, *last_back_slash, *end_of_dirname;
int dirname_length = 0;
last_forw_slash = strrchr (argv[i], '/');
last_back_slash = strrchr (argv[i], '\\');
#define cvs_max(x,y) ((x >= y) ? (x) : (y))
end_of_dirname = cvs_max (last_forw_slash, last_back_slash);
if (end_of_dirname == NULL)
dirname_length = 0;
else
dirname_length = end_of_dirname - argv[i] + 1;
h = FindFirstFile (argv[i], &fdata);
if (h == INVALID_HANDLE_VALUE)
{
if (GetLastError () == ENOENT)
{
new_argv [new_argc++] = xstrdup (argv[i]);
if (new_argc == max_new_argc)
{
max_new_argc *= 2;
new_argv = xrealloc (new_argv, max_new_argc * sizeof (char *));
}
}
else
{
error (1, errno, "cannot find %s", argv[i]);
}
}
else
{
while (1)
{
new_argv[new_argc] =
(char *) xmalloc (strlen (fdata.cFileName) + 1
+ dirname_length);
if (dirname_length)
{
strncpy (new_argv[new_argc], argv[i], dirname_length);
new_argv[new_argc][dirname_length] = '\0';
}
else
new_argv[new_argc][0] = '\0';
if (fncmp (argv[i] + dirname_length, fdata.cFileName) == 0)
strcpy (new_argv[new_argc], argv[i]);
else
strcat (new_argv[new_argc], fdata.cFileName);
new_argc++;
if (new_argc == max_new_argc)
{
max_new_argc *= 2;
new_argv = xrealloc (new_argv, max_new_argc * sizeof (char *));
}
if (!FindNextFile (h, &fdata))
{
if (GetLastError () == ERROR_NO_MORE_FILES)
break;
else
error (1, errno, "cannot find %s", argv[i]);
}
}
if (!FindClose (h))
error (1, GetLastError (), "cannot close %s", argv[i]);
}
}
*pargc = new_argc;
*pargv = new_argv;
}
static void check_statbuf (const char *file, struct stat *sb)
{
if (sb->st_mtime == (time_t) -1)
error (1, 0, "invalid modification time for %s", file);
if (sb->st_ctime == (time_t) -1)
error (1, 0, "invalid ctime for %s", file);
if (sb->st_atime == (time_t) -1)
error (1, 0, "invalid access time for %s", file);
}
int
wnt_stat (const char *file, struct stat *sb)
{
int retval;
retval = stat (file, sb);
if (retval < 0)
return retval;
check_statbuf (file, sb);
return retval;
}
int
wnt_lstat (const char *file, struct stat *sb)
{
int retval;
retval = lstat (file, sb);
if (retval < 0)
return retval;
check_statbuf (file, sb);
return retval;
}