⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cp.c

📁 操作系统源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	cp 1.9 - copy files				Author: Kees J. Bot *	mv     - move files					20 Jul 1993 *	rm     - remove files *	ln     - make a link *	cpdir  - copy a directory tree (cp -psmr) *	clone  - make a link farm (ln -fmr) */#define nil 0#include <stdio.h>#include <sys/types.h>#include <stdlib.h>#include <string.h>#include <stddef.h>#include <unistd.h>#include <fcntl.h>#include <time.h>#include <sys/stat.h>#include <utime.h>#include <dirent.h>#include <errno.h>#ifndef DEBUG#define DEBUG	0#define NDEBUG	1#endif#include <assert.h>/* Copy files in this size chunks: */#if __minix && !__minix_vmd#define CHUNK	(8192 * sizeof(char *))#else#define CHUNK	(1024 << (sizeof(int) + sizeof(char *)))#endif#ifndef CONFORMING#define CONFORMING	1	/* Precisely POSIX conforming. */#endif#define arraysize(a)	(sizeof(a) / sizeof((a)[0]))#define arraylimit(a)	((a) + arraysize(a))char *prog_name;		/* Call name of this program. */int ex_code= 0;			/* Final exit code. */typedef enum identity { CP, MV, RM, LN, CPDIR, CLONE } identity_t;typedef enum action { COPY, MOVE, REMOVE, LINK } action_t;identity_t identity;		/* How did the user call me? */action_t action;		/* Copying, moving, or linking. */int pflag= 0;			/* -p/-s: Make orginal and copy the same. */int iflag= 0;			/* -i: Interactive overwriting/deleting. */int fflag= 0;			/* -f: Force. */int sflag= 0;			/* -s: Make a symbolic link (ln/clone). */int Sflag= 0;			/* -S: Make a symlink if across devices. */int mflag= 0;			/* -m: Merge trees, no target dir trickery. */int rflag= 0;			/* -r/-R: Recursively copy a tree. */int vflag= 0;			/* -v: Verbose. */int xflag= 0;			/* -x: Don't traverse past mount points. */int xdev= 0;			/* Set when moving or linking cross-device. */int expand= 0;			/* Expand symlinks, ignore links. */int conforming= CONFORMING;	/* Sometimes standards are a pain. */int fc_mask;			/* File creation mask. */int uid, gid;			/* Effective uid & gid. */int istty;			/* Can have terminal input. */#ifndef S_ISLNK/* There were no symlinks in medieval times. */#define S_ISLNK(mode)			(0)#define lstat				stat#define symlink(path1, path2)		(errno= ENOSYS, -1)#define readlink(path, buf, len)	(errno= ENOSYS, -1)#endifvoid report(const char *label){	if (action == REMOVE && fflag) return;	fprintf(stderr, "%s: %s: %s\n", prog_name, label, strerror(errno));	ex_code= 1;}void fatal(const char *label){	report(label);	exit(1);}void report2(const char *src, const char *dst){	fprintf(stderr, "%s %s %s: %s\n", prog_name, src, dst, strerror(errno));	ex_code= 1;}#if DEBUGsize_t nchunks= 0;	/* Number of allocated cells. */#endifvoid *allocate(void *mem, size_t size)/* Like realloc, but with checking of the return value. */{#if DEBUG	if (mem == nil) nchunks++;#endif	if ((mem= mem == nil ? malloc(size) : realloc(mem, size)) == nil)		fatal("malloc()");	return mem;}void deallocate(void *mem)/* Release a chunk of memory. */{	if (mem != nil) {#if DEBUG		nchunks--;#endif		free(mem);	}}typedef struct pathname {	char		*path;	/* The actual pathname. */	size_t		idx;	/* Index for the terminating null byte. */	size_t		lim;	/* Actual length of the path array. */} pathname_t;void path_init(pathname_t *pp)/* Initialize a pathname to the null string. */{	pp->path= allocate(nil, pp->lim= 16);	pp->path[pp->idx= 0]= 0;}void path_add(pathname_t *pp, const char *name)/* Add a component to a pathname. */{	size_t lim;	char *p;	lim= pp->idx + strlen(name) + 2;	if (lim > pp->lim) {		pp->lim= lim += lim/2;	/* add an extra 50% growing space. */		pp->path= allocate(pp->path, lim);	}	p= pp->path + pp->idx;	if (p > pp->path && p[-1] != '/') *p++ = '/';	while (*name != 0) {		if (*name != '/' || p == pp->path || p[-1] != '/')			*p++ = *name;		name++;	}	*p = 0;	pp->idx= p - pp->path;}void path_trunc(pathname_t *pp, size_t didx)/* Delete part of a pathname to a remembered length. */{	pp->path[pp->idx= didx]= 0;}#if DEBUGconst char *path_name(const pathname_t *pp)/* Return the actual name as a C string. */{	return pp->path;}size_t path_length(const pathname_t *pp)/* The length of the pathname. */{	return pp->idx;}void path_drop(pathname_t *pp)/* Release the storage occupied by the pathname. */{	deallocate(pp->path);}#else /* !DEBUG */#define path_name(pp)		((const char *) (pp)->path)#define path_length(pp)		((pp)->idx)#define path_drop(pp)		deallocate((void *) (pp)->path)#endif /* !DEBUG */char *basename(const char *path)/* Return the last component of a pathname.  (Note: declassifies a const * char * just like strchr. */{	const char *p= path;	for (;;) {		while (*p == '/') p++;		/* Trailing slashes? */		if (*p == 0) break;		path= p;		while (*p != 0 && *p != '/') p++;	/* Skip component. */	}	return (char *) path;}int affirmative(void)/* Get a yes/no answer from the suspecting user. */{	int c;	int ok;	fflush(stdout);	fflush(stderr);	while ((c= getchar()) == ' ') {}	ok= (c == 'y' || c == 'Y');	while (c != EOF && c != '\n') c= getchar();	return ok;}int writable(const struct stat *stp)/* True iff the file with the given attributes allows writing.  (And we have * a terminal to ask if ok to overwrite.) */{	if (!istty || uid == 0) return 1;	if (stp->st_uid == uid) return stp->st_mode & S_IWUSR;	if (stp->st_gid == gid) return stp->st_mode & S_IWGRP;	return stp->st_mode & S_IWOTH;}int trylink(const char *src, const char *dst, struct stat *srcst,						struct stat *dstst)/* Keep the link structure intact if src has been seen before. */{	typedef struct oldlink {		struct oldlink	*next;		char		*olddst;		dev_t		dev;		ino_t		ino;		ino_t		count;	} oldlink_t;	static oldlink_t *oldies[0x100];	oldlink_t *op, **pop;	int found, linked;#if DEBUG	if (src == nil) {		/* Time to clean house (consistency freak on the loose). */		for (pop= oldies; pop < arraylimit(oldies); pop++) {			while ((op= *pop) != nil) {				*pop= op->next;				deallocate(op->olddst);				deallocate(op);			}		}		return 0;	}#endif	if (action == COPY && expand) return 0;	pop= &oldies[(unsigned) srcst->st_ino % arraysize(oldies)];	found= 0;	while ((op= *pop) != nil && srcst->st_ino <= op->ino) {		if (srcst->st_ino == op->ino && srcst->st_dev == op->dev) {			found= 1;			break;		}		pop= &op->next;	}	if (!found) {		if (srcst->st_nlink > 1) {			/* Remember this one for later. */			op= allocate(nil, sizeof(*op));			op->olddst= allocate(nil,				(strlen(dst) + 1) * sizeof(*op->olddst));			strcpy(op->olddst, dst);			op->ino= srcst->st_ino;			op->dev= srcst->st_dev;			op->count= srcst->st_nlink;			op->next= *pop;			*pop= op;		}		return 0;	}	/* Try to link the file copied earlier to the new file. */	if (dstst->st_ino != 0) (void) unlink(dst);	if ((linked= (link(op->olddst, dst) == 0)) && vflag)		printf("ln %s %s\n", op->olddst, dst);	if (--op->count == 1) {		/* All the links to the file have been seen. */		*pop= op->next;		deallocate(op->olddst);		deallocate(op);	}	return linked;}int copy(const char *src, const char *dst, struct stat *srcst,						struct stat *dstst)/* Copy one file to another and copy (some of) the attributes. */{	char buf[CHUNK];	int srcfd, dstfd;	ssize_t n;	assert(srcst->st_ino != 0);	if (dstst->st_ino == 0) {		/* The file doesn't exist yet. */		if (!S_ISREG(srcst->st_mode)) {			/* Making a new mode 666 regular file. */			srcst->st_mode= (S_IFREG | 0666) & fc_mask;		} else		if (!pflag && conforming) {			/* Making a new file copying mode with umask applied. */			srcst->st_mode &= fc_mask;		}	} else {		/* File exists, ask if ok to overwrite if '-i'. */		if (iflag || (action == MOVE && !fflag && !writable(dstst))) {			fprintf(stderr, "Overwrite %s? (mode = %03o) ",						dst, dstst->st_mode & 07777);			if (!affirmative()) return 0;		}		if (action == MOVE) {			/* Don't overwrite, remove first. */			if (unlink(dst) < 0 && errno != ENOENT) {				report(dst);				return 0;			}		} else {			/* Overwrite. */			if (!pflag) {				/* Keep the existing mode and ownership. */				srcst->st_mode= dstst->st_mode;				srcst->st_uid= dstst->st_uid;				srcst->st_gid= dstst->st_gid;			}		}	}	/* Keep the link structure if possible. */	if (trylink(src, dst, srcst, dstst)) return 1;	if ((srcfd= open(src, O_RDONLY)) < 0) {		report(src);		return 0;	}	dstfd= open(dst, O_WRONLY|O_CREAT|O_TRUNC, srcst->st_mode & 0777);	if (dstfd < 0 && fflag && errno == EACCES) {		/* Retry adding a "w" bit. */		(void) chmod(dst, dstst->st_mode | S_IWUSR);		dstfd= open(dst, O_WRONLY|O_CREAT|O_TRUNC, 0);	}	if (dstfd < 0 && fflag && errno == EACCES) {		/* Retry after trying to delete. */		(void) unlink(dst);		dstfd= open(dst, O_WRONLY|O_CREAT|O_TRUNC, 0);	}	if (dstfd < 0) {		report(dst);		close(srcfd);		return 0;	}	/* Get current parameters. */	if (fstat(dstfd, dstst) < 0) {		report(dst);		close(srcfd);		close(dstfd);		return 0;	}	/* Copy the little bytes themselves. */	while ((n= read(srcfd, buf, sizeof(buf))) > 0) {		char *bp = buf;		ssize_t r;		while (n > 0 && (r= write(dstfd, bp, n)) > 0) {			bp += r;			n -= r;		}		if (r <= 0) {			if (r == 0) {				fprintf(stderr,					"%s: Warning: EOF writing to %s\n",					prog_name, dst);				break;			}			fatal(dst);		}	}	if (n < 0) {		report(src);		close(srcfd);		close(dstfd);		return 0;	}	close(srcfd);	close(dstfd);	/* Copy the ownership. */	if ((pflag || !conforming)		&& S_ISREG(dstst->st_mode)		&& (dstst->st_uid != srcst->st_uid				|| dstst->st_gid != srcst->st_gid)	) {		if (chmod(dst, 0) == 0) dstst->st_mode&= ~07777;		if (chown(dst, srcst->st_uid, srcst->st_gid) < 0) {			if (errno != EPERM) {				report(dst);				return 0;			}		} else {			dstst->st_uid= srcst->st_uid;			dstst->st_gid= srcst->st_gid;		}	}	if (conforming && S_ISREG(dstst->st_mode)		&& (dstst->st_uid != srcst->st_uid				|| dstst->st_gid != srcst->st_gid)	) {		/* Suid bits must be cleared in the holy name of		 * security (and the assumed user stupidity).		 */		srcst->st_mode&= ~06000;	}	/* Copy the mode. */	if (S_ISREG(dstst->st_mode) && dstst->st_mode != srcst->st_mode) {		if (chmod(dst, srcst->st_mode) < 0) {			if (errno != EPERM) {				report(dst);				return 0;			}			fprintf(stderr, "%s: Can't change the mode of %s\n",				prog_name, dst);		}	}	/* Copy the file modification time. */	if ((pflag || !conforming) && S_ISREG(dstst->st_mode)) {		struct utimbuf ut;		ut.actime= action == MOVE ? srcst->st_atime : time(nil);		ut.modtime= srcst->st_mtime;		if (utime(dst, &ut) < 0) {			if (errno != EPERM) {				report(dst);				return 0;			}			if (pflag) {				fprintf(stderr,					"%s: Can't set the time of %s\n",					prog_name, dst);			}		}	}	if (vflag) {		printf(action == COPY ? "cp %s %s\n" : "mv %s %s\n", src, dst);	}	return 1;}void copy1(const char *src, const char *dst, struct stat *srcst,							struct stat *dstst)/* Inspect the source file and then copy it.  Treatment of symlinks and * special files is a bit complicated.  The filetype and link-structure are * ignored if (expand && !rflag), symlinks and link-structure are ignored * if (expand && rflag), everything is copied precisely if !expand. */{	int r, linked;	assert(srcst->st_ino != 0);	if (srcst->st_ino == dstst->st_ino && srcst->st_dev == dstst->st_dev) {		fprintf(stderr, "%s: can't copy %s onto itself\n",			prog_name, src);		ex_code= 1;		return;	}	/* You can forget it if the destination is a directory. */	if (dstst->st_ino != 0 && S_ISDIR(dstst->st_mode)) {		errno= EISDIR;		report(dst);		return;	}	if (S_ISREG(srcst->st_mode) || (expand && !rflag)) {		if (!copy(src, dst, srcst, dstst)) return;		if (action == MOVE && unlink(src) < 0) {			report(src);			return;		}		return;	}	if (dstst->st_ino != 0) {		if (iflag || (action == MOVE && !fflag && !writable(dstst))) {			fprintf(stderr, "Replace %s? (mode = %03o) ",						dst, dstst->st_mode & 07777);			if (!affirmative()) return;		}		if (unlink(dst) < 0) {			report(dst);			return;		}		dstst->st_ino= 0;	}	/* Apply the file creation mask if so required. */	if (!pflag && conforming) srcst->st_mode &= fc_mask;	linked= 0;	if (S_ISLNK(srcst->st_mode)) {		char buf[1024+1];		if ((r= readlink(src, buf, sizeof(buf)-1)) < 0) {			report(src);			return;		}		buf[r]= 0;		r= symlink(buf, dst);		if (vflag && r == 0)			printf("ln -s %s %s\n", buf, dst);	} else	if (trylink(src, dst, srcst, dstst)) {		linked= 1;		r= 0;	} else	if (S_ISFIFO(srcst->st_mode)) {		r= mkfifo(dst, srcst->st_mode);		if (vflag && r == 0)			printf("mkfifo %s\n", dst);	} else	if (S_ISBLK(srcst->st_mode) || S_ISCHR(srcst->st_mode)) {		r= mknod(dst, srcst->st_mode, srcst->st_rdev);		if (vflag && r == 0) {			printf("mknod %s %c %d %d\n",				dst,				S_ISBLK(srcst->st_mode) ? 'b' : 'c',				(srcst->st_rdev >> 8) & 0xFF,				(srcst->st_rdev >> 0) & 0xFF);		}	} else {		fprintf(stderr, "%s: %s: odd filetype %5o (not copied)\n",			prog_name, src, srcst->st_mode);		ex_code= 1;		return;	}	if (r < 0 || lstat(dst, dstst) < 0) {		report(dst);		return;	}	if (action == MOVE && unlink(src) < 0) {		report(src);		(void) unlink(dst);	/* Don't want it twice. */		return;	}	if (linked) return;	if (S_ISLNK(srcst->st_mode)) return;	/* Copy the ownership. */	if ((pflag || !conforming)		&& (dstst->st_uid != srcst->st_uid				|| dstst->st_gid != srcst->st_gid)	) {		if (chown(dst, srcst->st_uid, srcst->st_gid) < 0) {			if (errno != EPERM) {				report(dst);				return;			}		}	}	/* Copy the file modification time. */	if (pflag || !conforming) {		struct utimbuf ut;		ut.actime= action == MOVE ? srcst->st_atime : time(nil);		ut.modtime= srcst->st_mtime;		if (utime(dst, &ut) < 0) {			if (errno != EPERM) {				report(dst);				return;			}			fprintf(stderr, "%s: Can't set the time of %s\n",				prog_name, dst);		}	}}void remove1(const char *src, struct stat *srcst){	if (iflag || (!fflag && !writable(srcst))) {		fprintf(stderr, "Remove %s? (mode = %03o) ", src,						srcst->st_mode & 07777);		if (!affirmative()) return;	}	if (unlink(src) < 0) {		report(src);	} else {		if (vflag) printf("rm %s\n", src);	}}void link1(const char *src, const char *dst, struct stat *srcst,							struct stat *dstst){	pathname_t sym;	const char *p;	if (dstst->st_ino != 0 && (iflag || fflag)) {		if (srcst->st_ino == dstst->st_ino) {			if (fflag) return;			fprintf(stderr, "%s: Can't link %s onto itself\n",				prog_name, src);			ex_code= 1;			return;		}		if (iflag) {			fprintf(stderr, "Remove %s? ", dst);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -