211 lines
3.9 KiB
C
211 lines
3.9 KiB
C
/* 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);
|
|
}
|