|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 6868 (0x1ad4)
Types: TextFile
Notes: UNIX file
Names: »mv.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »cmd/mv.c«
/*
* Move (rename) files.
* mv file1 file2
* or
* mv file ... directory
*/
#include <stdio.h>
#include <stat.h>
#include <errno.h>
#include <access.h>
#include <signal.h>
#include <dir.h>
#define NOTREACHED return
char *usage = "\
Usage: mv [-f] file1 file2\n\
mv [-f] file ... directory\n\
";
char *nowrite = "unwritable: %s";
char *nolink = "link %s %s failed";
char *nounlink = "unlink %s failed";
char *cmd = "mv: "; /* for error routines */
int myuid;
int mygid;
int newid;
char *child;
struct stat sb1, sb2, sb3;
int estat;
int fflag;
int interrupted;
char *concat(),
*strcpy(),
*strcat(),
*strncpy(),
*getparent(),
*getchild();
main(argc, argv)
char *argv[];
{
register int i;
if (argc>1 && *argv[1]=='-')
if (argv[1][1] == 'f' && argv[1][2] == '\0') {
fflag = 1;
argc--;
argv++;
} else {
fputs(usage, stderr);
exit(EINVAL);
NOTREACHED;
}
catch(SIGINT);
catch(SIGHUP);
signal(SIGQUIT, SIG_IGN);
myuid = getuid();
mygid = getgid();
if (--argc >= 2
&& stat(argv[argc], &sb2) >= 0
&& (sb2.st_mode&S_IFMT) == S_IFDIR)
for (i = 1; i < argc && !interrupted; i += 1) {
child = getchild(argv[i]);
mv(argv[i], concat(0, argv[argc], child));
}
else if (argc == 2) {
child = getchild(argv[1]);
mv(argv[1], argv[2]);
} else {
fputs(usage, stderr);
exit(EINVAL);
NOTREACHED;
}
exit(interrupted ? EINTR : estat);
}
/*
* move f1 to f2 if at all possible.
*/
mv(f1, f2)
char *f1, *f2;
{
int isdir, isxdev, nocopy;
char *p2, *lp2;
/* Check existence, format, delete permission on source */
if (stat(f1, &sb1) < 0)
return (warn(ENOENT, f1));
nocopy = (sb1.st_mode&S_IFMT) != S_IFREG;
isdir = (sb1.st_mode&S_IFMT) == S_IFDIR;
newid = (sb1.st_uid != myuid);
if (access(getparent(f1), ADEL) < 0)
return (warn(EACCES, f1));
/* Check existence, format, create permission on parent of dest */
if (stat(p2 = getparent(f2), &sb2) < 0)
return (warn(ENOENT, p2));
if ((sb2.st_mode&S_IFMT) != S_IFDIR)
return (warn(ENOTDIR, p2));
if (access(p2, ADEL) < 0)
return (warn(EACCES, p2));
/* Check for cross device mv's */
isxdev = sb1.st_dev != sb2.st_dev;
if (isxdev && nocopy)
return (warn(EXDEV, "%s to %s", f1, f2));
/* Check for legal directory moves */
if (isdir) {
/* Can't mv . or .. */
if (equals(".", child) || equals("..", child))
return (warn(-1, "rename %s forbidden", f1));
/* Can't mv directory to child of itself */
for (lp2 = p2; ; ) {
/* If dev and ino of source file appear in the path
* from dest parent to root, then the dest
* will be a child of the source.
*/
if (sb1.st_dev==sb2.st_dev && sb1.st_ino==sb2.st_ino)
return (warn(-1, "%s parent of %s", f1, f2));
sb3 = sb2;
lp2 = concat(1, lp2, "..");
if (stat(lp2, &sb2) < 0)
return (warn(errno, "%s", lp2));
if (sb2.st_dev==sb3.st_dev && sb2.st_ino==sb3.st_ino)
break;
}
}
/* Check for existence, format, and writability of dest */
if (stat(f2, &sb2) >= 0) {
if ((sb2.st_mode&S_IFMT) == S_IFDIR)
return (warn(EISDIR, f2));
if (!fflag && access(f2, AWRITE) < 0)
return (warn(-1, nowrite, f2));
/* Check for identity of source and dest */
if (sb1.st_dev == sb2.st_dev && sb1.st_ino == sb2.st_ino)
return (warn(-1, "%s and %s are identical", f1, f2));
if (unlink(f2)) {
fatal(errno, nounlink, f2);
NOTREACHED;
}
}
/* Do the mv, either cp or ln/rm */
if (isxdev)
cp(f1, f2, sb1.st_mode);
else {
if (link(f1, f2))
return (warn(errno, nolink, f1, f2));
if (isdir) {
if (unlink(lp2 = concat(1, f2, ".."))) {
fatal(errno, nounlink, lp2);
NOTREACHED;
}
if (link(p2, lp2)) {
fatal(errno, nolink, p2, lp2);
NOTREACHED;
}
}
}
if (unlink(f1)) {
fatal(errno, nounlink, f1);
NOTREACHED;
}
}
/*
* Copy f1 to f2.
* The mode must be maintained.
*/
cp(f1, f2, mode)
char *f1, *f2;
{
register int fd1, fd2;
register int n;
char iobuf[BUFSIZ];
if ((fd1 = open(f1, 0)) < 0) {
fatal(errno, "open %s failed", f1);
NOTREACHED;
}
if ((fd2 = creat(f2, 0)) < 0) {
fatal(errno, "create %s failed", f2);
NOTREACHED;
}
if (newid)
mode &= 0777;
chmod(f2, mode&07777);
chown(f2, myuid, mygid);
while ((n = read(fd1, iobuf, BUFSIZ)) != 0) {
if (n < 0) {
fatal(errno, "read %s failed", f1);
NOTREACHED;
}
if (n == BUFSIZ && iszero(iobuf)) {
if (lseek(fd2, (long) BUFSIZ, 1) < 0) {
fatal(errno, "seek %s failed", f2);
NOTREACHED;
}
} else if (write(fd2, iobuf, n) != n) {
fatal(errno, "write %s failed", f2);
NOTREACHED;
}
}
close(fd1);
close(fd2);
}
/*
* Check for zeroes in buffer.
*/
iszero(buf)
char *buf;
{
register int i;
register char *bp;
i = BUFSIZ;
bp = buf;
do if (*bp++) return (0); while (--i);
return (1);
}
/*
* Check two path names for equality knowing that p2 could be '/' terminated.
*/
equals(p1, p2)
register char *p1, *p2;
{
while (*p1++ == *p2)
if (*p2++ == '\0')
return (1);
if (*p2 == '/' && *--p1 == '\0')
return (1);
return (0);
}
/*
* Concatenate s1 and s2 with a '/' between them.
*/
char *
concat(l, s1, s2)
int l;
register char *s1, *s2;
{
register char *s3;
static char *tmp[2];
int n;
n = strlen(s1) + strlen(s2) + 2;
if ((s3 = malloc(n)) == NULL) {
nomemory();
NOTREACHED;
}
strcpy(s3, s1);
strcat(s3, "/");
strcat(s3, s2);
if (tmp[l] != NULL)
free(tmp[l]);
tmp[l] = s3;
return (s3);
}
warn(err, arg1)
int err;
char *arg1;
{
fprintf(stderr, "%s%r", cmd, &arg1);
if (err > 0 && err < sys_nerr)
fprintf(stderr, " %s", sys_errlist[err]);
fputs("\n", stderr);
estat = err;
}
/*
* return name of parent
*/
char *
getparent(dir)
char *dir;
{
register i;
register char *p;
static char *par;
if (par)
free( par);
i = strlen( dir);
par = malloc( i+1);
if (par == NULL) {
nomemory( );
NOTREACHED;
}
strcpy( par, dir);
for (p=par+i; p>par; )
if (*--p != '/')
break;
for (++p; *--p!='/'; )
if (p == par) {
*p = '.';
break;
}
*++p = '\0';
return (par);
}
/*
* return rightmost component of pathname
*/
char *
getchild(dir)
register char *dir;
{
register i;
register char *p;
static char ch[DIRSIZ+1];
i = strlen( dir);
if (i == 0) {
fatal( -1, "NULL?");
NOTREACHED;
}
for (p=dir+i; *--p=='/'; )
if (p == dir) {
fatal( -1, "don't be silly");
NOTREACHED;
}
while (p > dir)
if (*--p == '/') {
++p;
break;
}
return (strncpy( ch, p, DIRSIZ));
}
nomemory( )
{
fatal( ENOMEM, "out of mem");
NOTREACHED;
}
onintr( )
{
signal( SIGINT, SIG_IGN);
signal( SIGHUP, SIG_IGN);
++interrupted;
}
catch( sig)
{
if( signal( sig, SIG_IGN) == SIG_DFL)
signal( sig, onintr);
}
fatal(err, arg1)
unsigned int err;
char *arg1;
{
fputs(cmd, stderr);
if (err < sys_nerr) {
fputs(sys_errlist[err], stderr);
fputs(": ", stderr);
}
fprintf(stderr, "%r\n", &arg1);
exit(err);
NOTREACHED;
}