Minix1.5/commands/cp.c

Compare this file to the similar file:
Show the results in this format:

/* cp - copy files		Author: Andy Tanenbaum */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define TRANSFER_UNIT    16384
char cpbuf[TRANSFER_UNIT];
int isfloppy;			/* set to 1 for cp x /dev/fd? */


main(argc, argv)
int argc;
char *argv[];
{
  int fd1, fd2, m, s;
  struct stat sbuf, sbuf2;

  if (argc < 3) usage();

  /* Get the status of the last named file.  See if it is a directory. */
  s = stat(argv[argc - 1], &sbuf);
  m = sbuf.st_mode & S_IFMT;
  if (s >= 0 && m == S_IFDIR) {
	/* Last argument is a directory. */
	exit(cp_to_dir(argc, argv));
  } else if (argc > 3) {
	/* More than 2 arguments and last one is not a directory. */
	usage();
  } else if (s < 0 || m == S_IFREG || m == S_IFCHR || m == S_IFBLK) {
	/* Exactly two arguments.  Check for cp f1 f1. */
	if (equal(argv[1], argv[2])) {
		std_err("cp: cannot copy a file to itself\n");
		exit(-1);
	}

	/* Command is of the form cp f1 f2. */
	fd1 = open(argv[1], O_RDONLY);
	if (fd1 < 0) {
		stderr3("cannot open ", argv[1], "\n");
		exit(1);
	}
	fstat(fd1, &sbuf);
	m = sbuf.st_mode & S_IFMT;
	if (m == S_IFDIR) {
		stderr3("<", argv[1], "> directory\n");
		exit(1);
	}
	fd2 = creat(argv[2], sbuf.st_mode & 0777);
	if (fd2 < 0) {
		stderr3("cannot create ", argv[2], "\n");
		exit(2);
	}
	fstat(fd2, &sbuf2);
	if ((sbuf2.st_mode & S_IFMT) == S_IFBLK) isfloppy = 1;
	copyfile(fd1, fd2, argv[2]);
  } else {
	stderr3("cannot copy to ", argv[2], "\n");
	exit(3);
  }
  exit(0);
}





cp_to_dir(argc, argv)
int argc;
char *argv[];
{
  int i, mode, fd1, fd2, exit_status = 0;
  char dirname[256], *ptr, *dp;
  struct stat sbuf;

  for (i = 1; i < argc - 1; i++) {
	fd1 = open(argv[i], O_RDONLY);
	if (fd1 < 0) {
		stderr3("cannot open ", argv[i], "\n");
		exit_status = 1;
		continue;
	}
	ptr = argv[argc - 1];
	dp = dirname;
	while (*ptr != 0) *dp++ = *ptr++;

	*dp++ = '/';
	ptr = argv[i];

	/* Concatenate dir and file name in dirname buffer. */
	while (*ptr != 0) ptr++;/* go to end of file name */
	while (ptr > argv[i] && *ptr != '/') ptr--;	/* get last component */
	if (*ptr == '/') ptr++;
	while (*ptr != 0) *dp++ = *ptr++;
	*dp++ = 0;
	fstat(fd1, &sbuf);
	mode = sbuf.st_mode & S_IFMT;
	if (mode == S_IFDIR) {
		stderr3("<", argv[i], "> directory\n");
		exit_status = 1;
		close(fd1);
		continue;
	}
	fd2 = creat(dirname, sbuf.st_mode & 0777);
	if (fd2 < 0) {
		stderr3("cannot create ", dirname, "\n");
		exit_status = 2;
		close(fd1);
		continue;
	}
	copyfile(fd1, fd2, dirname);
  }
  return(exit_status);
}





copyfile(fd1, fd2, name)
int fd1, fd2;
char *name;
{
  int n, m, mode;
  struct stat sbuf;

  do {
	n = read(fd1, cpbuf, TRANSFER_UNIT);
	if (n < 0) {
		std_err("cp: read error\n");
		break;
	}
	if (n > 0) {
		m = write(fd2, cpbuf, n);
		if (m != n) {
			/* Write failed.  Don't keep truncated
			 * regular file. */
			perror("cp");
			fstat(fd2, &sbuf);	/* check for special files */
			mode = sbuf.st_mode & S_IFMT;
			if (mode == S_IFREG) unlink(name);
			exit(1);
		}
		if (isfloppy) sync();	/* purge the cache all at once */
	}
  } while (n == TRANSFER_UNIT);
  close(fd1);
  close(fd2);
}

usage()
{
  std_err("Usage:  cp f1 f2;  or  cp f1 ... fn d2\n");
  exit(-1);
}

typedef char *cptr;

int equal(s1, s2)
char *s1, *s2;
{
  struct stat sb1, sb2;

  /* Same file, different name? */
  stat(s1, &sb1);
  stat(s2, &sb2);
  if (memcmp((cptr) & sb1, (cptr) & sb2, sizeof(struct stat)) == 0)
	return(1);
  /* Same file, same name? */
  while (1) {
	if (*s1 == 0 && *s2 == 0) return(1);
	if (*s1 != *s2) return (0);
	if (*s1 == 0 || *s2 == 0) return (0);
	s1++;
	s2++;
  }
}

int match(s1, s2, n)
char *s1, *s2;
int n;
{
  while (n--) {
	if (*s1++ != *s2++) return(0);
  }
  return(1);
}


stderr3(s1, s2, s3)
char *s1, *s2, *s3;
{
  std_err("cp: ");
  std_err(s1);
  std_err(s2);
  std_err(s3);
}


int memcmp(b1, b2, n)
cptr b1, b2;
int n;
{
  while (n--) {
	if (*b1 != *b2) return((int) (*b1 - *b2));
	++b1;
	++b2;
  }
  return(0);
}