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

📄 cp.c

📁 操作系统源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
			if (!affirmative()) return;		}		errno= EISDIR;		if (S_ISDIR(dstst->st_mode) || unlink(dst) < 0) {			report(dst);			return;		}	}	if (!sflag && !(rflag && S_ISLNK(srcst->st_mode)) && !(Sflag && xdev)) {		/* A normal link. */		if (link(src, dst) < 0) {			if (!Sflag || errno != EXDEV) {				report2(src, dst);				return;			}			/* Can't do a cross-device link, we have to symlink. */			xdev= 1;		} else {			if (vflag) printf("ln %s %s\n", src, dst);			return;		}	}	/* Do a symlink. */	if (!rflag && !Sflag) {		/* We can get away with a "don't care if it works" symlink. */		if (symlink(src, dst) < 0) {			report(dst);			return;		}		if (vflag) printf("ln -s %s %s\n", src, dst);		return;	}	/* If the source is a symlink then it is simply copied. */	if (S_ISLNK(srcst->st_mode)) {		int r;		char buf[1024+1];		if ((r= readlink(src, buf, sizeof(buf)-1)) < 0) {			report(src);			return;		}		buf[r]= 0;		if (symlink(buf, dst) < 0) {			report(dst);			return;		}		if (vflag) printf("ln -s %s %s\n", buf, dst);		return;	}	/* Make a symlink that has to work, i.e. we must be able to access the	 * source now, and the link must work.	 */	if (dst[0] == '/' && src[0] != '/') {		/* ln -[rsS] relative/path /full/path. */		fprintf(stderr,	"%s: Symlinking %s to %s can't be made to work, too difficult\n",			prog_name, src, dst);		exit(1);	}	/* Count the number of subdirectories in the destination file and	 * add one '..' for each.	 */	path_init(&sym);	if (src[0] != '/') {		p= dst;		while (*p != 0) {			while (*p != 0 && *p != '/') p++;			while (*p == '/') p++;			if (*p == 0) break;			path_add(&sym, "..");		}	}	path_add(&sym, src);	if (symlink(path_name(&sym), dst) < 0) {		report(dst);	} else {		if (vflag) printf("ln -s %s %s\n", path_name(&sym), dst);	}	path_drop(&sym);}typedef struct entrylist {	struct entrylist	*next;	char			*name;} entrylist_t;int eat_dir(const char *dir, entrylist_t **dlist)/* Make a linked list of all the names in a directory. */{	DIR *dp;	struct dirent *entry;	if ((dp= opendir(dir)) == nil) return 0;	while ((entry= readdir(dp)) != nil) {		if (strcmp(entry->d_name, ".") == 0) continue;		if (strcmp(entry->d_name, "..") == 0) continue;		*dlist= allocate(nil, sizeof(**dlist));		(*dlist)->name= allocate(nil, strlen(entry->d_name)+1);		strcpy((*dlist)->name, entry->d_name);		dlist= &(*dlist)->next;	}	closedir(dp);	*dlist= nil;	return 1;}void chop_dlist(entrylist_t **dlist)/* Chop an entry of a name list. */{	entrylist_t *junk= *dlist;	*dlist= junk->next;	deallocate(junk->name);	deallocate(junk);}void drop_dlist(entrylist_t *dlist)/* Get rid of a whole list. */{	while (dlist != nil) chop_dlist(&dlist);}void do1(pathname_t *src, pathname_t *dst, int depth)/* Perform the appropriate action on a source and destination file. */{	size_t slashsrc, slashdst;	struct stat srcst, dstst;	entrylist_t *dlist;	static ino_t topdst_ino;	static dev_t topdst_dev;	static dev_t topsrc_dev;#if DEBUG	if (vflag && depth == 0) {		char flags[100], *pf= flags;		if (pflag) *pf++= 'p';		if (iflag) *pf++= 'i';		if (fflag) *pf++= 'f';		if (sflag) *pf++= 's';		if (Sflag) *pf++= 'S';		if (mflag) *pf++= 'm';		if (rflag) *pf++= 'r';		if (vflag) *pf++= 'v';		if (xflag) *pf++= 'x';		if (expand) *pf++= 'L';		if (conforming) *pf++= 'C';		*pf= 0;		printf(": %s -%s %s %s\n", prog_name, flags,					path_name(src), path_name(dst));	}#endif	/* st_ino == 0 if not stat()'ed yet, or nonexistent. */	srcst.st_ino= 0;	dstst.st_ino= 0;	if (action != LINK || !sflag || rflag) {		/* Source must exist unless symlinking. */		if ((expand ? stat : lstat)(path_name(src), &srcst) < 0) {			report(path_name(src));			return;		}	}	if (depth == 0) {		/* First call: Not cross-device yet, first dst not seen yet,		 * remember top device number.		 */		xdev= 0;		topdst_ino= 0;		topsrc_dev= srcst.st_dev;	}	/* Inspect the intended destination unless removing. */	if (action != REMOVE) {		if ((expand ? stat : lstat)(path_name(dst), &dstst) < 0) {			if (errno != ENOENT) {				report(path_name(dst));				return;			}		}	}	if (action == MOVE && !xdev) {		if (dstst.st_ino != 0 && srcst.st_dev != dstst.st_dev) {			/* It's a cross-device rename, i.e. copy and remove. */			xdev= 1;		} else		if (!mflag || dstst.st_ino == 0 || !S_ISDIR(dstst.st_mode)) {			/* Try to simply rename the file (not merging trees). */			if (srcst.st_ino == dstst.st_ino) {				fprintf(stderr,					"%s: Can't move %s onto itself\n",					prog_name, path_name(src));				ex_code= 1;				return;			}			if (dstst.st_ino != 0) {				if (iflag || (!fflag && !writable(&dstst))) {					fprintf(stderr,						"Replace %s? (mode = %03o) ",						path_name(dst),						dstst.st_mode & 07777);					if (!affirmative()) return;				}				if (!S_ISDIR(dstst.st_mode))					(void) unlink(path_name(dst));			}			if (rename(path_name(src), path_name(dst)) == 0) {				/* Success. */				if (vflag) {					printf("mv %s %s\n", path_name(src),							path_name(dst));				}				return;			}			if (errno == EXDEV) {				xdev= 1;			} else {				report2(path_name(src), path_name(dst));				return;			}		}	}	if (!S_ISDIR(srcst.st_mode)) {		/* Copy/move/remove/link a single file. */		switch (action) {		case COPY:		case MOVE:			copy1(path_name(src), path_name(dst), &srcst, &dstst);			break;		case REMOVE:			remove1(path_name(src), &srcst);			break;		case LINK:			link1(path_name(src), path_name(dst), &srcst, &dstst);			break;		}		return;	}	/* Recursively copy/move/remove/link a directory if -r or -R. */	if (!rflag) {		errno= EISDIR;		report(path_name(src));		return;	}	/* Ok to remove contents of dir? */	if (action == REMOVE) {		if (xflag && topsrc_dev != srcst.st_dev) {			/* Don't recurse past a mount point. */			return;		}		if (iflag) {			fprintf(stderr, "Remove contents of %s? ",							path_name(src));			if (!affirmative()) return;		}	}	/* Gather the names in the source directory. */	if (!eat_dir(path_name(src), &dlist)) {		report(path_name(src));		return;	}	/* Check/create the target directory. */	if (action != REMOVE && dstst.st_ino != 0 && !S_ISDIR(dstst.st_mode)) {		if (action != MOVE && !fflag) {			errno= ENOTDIR;			report(path_name(dst));			return;		}		if (iflag) {			fprintf(stderr, "Replace %s? ", path_name(dst));			if (!affirmative()) {				drop_dlist(dlist);				return;			}		}		if (unlink(path_name(dst)) < 0) {			report(path_name(dst));			drop_dlist(dlist);			return;		}		dstst.st_ino= 0;	}	if (action != REMOVE) {		if (dstst.st_ino == 0) {			/* Create a new target directory. */			if (!pflag && conforming) srcst.st_mode&= fc_mask;			if (mkdir(path_name(dst), srcst.st_mode | S_IRWXU) < 0					|| stat(path_name(dst), &dstst) < 0) {				report(path_name(dst));				drop_dlist(dlist);				return;			}			if (vflag) printf("mkdir %s\n", path_name(dst));		} else {			/* Target directory already exists. */			if (action == MOVE && !mflag) {				errno= EEXIST;				report(path_name(dst));				drop_dlist(dlist);				return;			}			if (!pflag) {				/* Keep the existing attributes. */				srcst.st_mode= dstst.st_mode;				srcst.st_uid= dstst.st_uid;				srcst.st_gid= dstst.st_gid;				srcst.st_mtime= dstst.st_mtime;			}		}		if (topdst_ino == 0) {			/* Remember the top destination. */			topdst_dev= dstst.st_dev;			topdst_ino= dstst.st_ino;		}		if (srcst.st_ino == topdst_ino && srcst.st_dev == topdst_dev) {			/* E.g. cp -r /shallow /shallow/deep. */			fprintf(stderr,				"%s%s %s/ %s/: infinite recursion avoided\n",				prog_name, action != MOVE ? " -r" : "",				path_name(src), path_name(dst));			drop_dlist(dlist);			return;		}		if (xflag && topsrc_dev != srcst.st_dev) {			/* Don't recurse past a mount point. */			drop_dlist(dlist);			return;		}	}	/* Go down. */	slashsrc= path_length(src);	slashdst= path_length(dst);	while (dlist != nil) {		path_add(src, dlist->name);		if (action != REMOVE) path_add(dst, dlist->name);		do1(src, dst, depth+1);		path_trunc(src, slashsrc);		path_trunc(dst, slashdst);		chop_dlist(&dlist);	}	if (action == MOVE || action == REMOVE) {		/* The contents of the source directory should have		 * been (re)moved above.  Get rid of the empty dir.		 */		if (action == REMOVE && iflag) {			fprintf(stderr, "Remove directory %s? ",							path_name(src));			if (!affirmative()) return;		}		if (rmdir(path_name(src)) < 0) {			if (errno != ENOTEMPTY) report(path_name(src));			return;		}		if (vflag) printf("rmdir %s\n", path_name(src));	}	if (action != REMOVE) {		/* Set the attributes of a new directory. */		struct utimbuf ut;		/* Copy the ownership. */		if ((pflag || !conforming)			&& (dstst.st_uid != srcst.st_uid				|| dstst.st_gid != srcst.st_gid)		) {			if (chown(path_name(dst), srcst.st_uid,							srcst.st_gid) < 0) {				if (errno != EPERM) {					report(path_name(dst));					return;				}			}		}		/* Copy the mode. */		if (dstst.st_mode != srcst.st_mode) {			if (chmod(path_name(dst), srcst.st_mode) < 0) {				report(path_name(dst));				return;			}		}		/* Copy the file modification time. */		if (dstst.st_mtime != srcst.st_mtime) {			ut.actime= action == MOVE ? srcst.st_atime : time(nil);			ut.modtime= srcst.st_mtime;			if (utime(path_name(dst), &ut) < 0) {				if (errno != EPERM) {					report(path_name(dst));					return;				}				fprintf(stderr,					"%s: Can't set the time of %s\n",					prog_name, path_name(dst));			}		}	}}void usage(void){	char *flags1, *flags2;	switch (identity) {	case CP:		flags1= "pifsmrRvx";		flags2= "pifsrRvx";		break;	case MV:		flags1= "ifsmvx";		flags2= "ifsvx";		break;	case RM:		fprintf(stderr, "Usage: rm [-ifrRvx] file ...\n");		exit(1);	case LN:		flags1= "ifsSmrRvx";		flags2= "ifsSrRvx";		break;	case CPDIR:		flags1= "ifvx";		flags2= nil;		break;	case CLONE:		flags1= "ifsSvx";		flags2= nil;		break;	}	fprintf(stderr, "Usage: %s [-%s] file1 file2\n", prog_name, flags1);    if (flags2 != nil)	fprintf(stderr, "       %s [-%s] file ... dir\n", prog_name, flags2);	exit(1);}void main(int argc, char **argv){	int i;	char *flags;	struct stat st;	pathname_t src, dst;	size_t slash;#if DEBUG >= 3	/* The first argument is the call name while debugging. */	if (argc < 2) exit(-1);	argv++;	argc--;#endif#if DEBUG	vflag= isatty(1);#endif	/* Call name of this program. */	prog_name= basename(argv[0]);	/* Required action. */	if (strcmp(prog_name, "cp") == 0) {		identity= CP;		action= COPY;		flags= "pifsmrRvx";		expand= 1;	} else	if (strcmp(prog_name, "mv") == 0) {		identity= MV;		action= MOVE;		flags= "ifsmvx";		rflag= pflag= 1;	} else	if (strcmp(prog_name, "rm") == 0) {		identity= RM;		action= REMOVE;		flags= "ifrRvx";	} else	if (strcmp(prog_name, "ln") == 0) {		identity= LN;		action= LINK;		flags= "ifsSmrRvx";	} else	if (strcmp(prog_name, "cpdir") == 0) {		identity= CPDIR;		action= COPY;		flags= "pifsmrRvx";		rflag= mflag= pflag= 1;		conforming= 0;	} else	if (strcmp(prog_name, "clone") == 0) {		identity= CLONE;		action= LINK;		flags= "ifsSmrRvx";		rflag= mflag= fflag= 1;	} else {		fprintf(stderr,	"%s: Identity crisis, not called cp, mv, rm, ln, cpdir, or clone\n",			prog_name);		exit(1);	}	/* Who am I?, where am I?, how protective am I? */	uid= geteuid();	gid= getegid();	istty= isatty(0);	fc_mask= ~umask(0);	/* Gather flags. */	i= 1;	while (i < argc && argv[i][0] == '-') {		char *opt= argv[i++] + 1;		if (opt[0] == '-' && opt[1] == 0) break;	/* -- */		while (*opt != 0) {			/* Flag supported? */			if (strchr(flags, *opt) == nil) usage();			switch (*opt++) {			case 'p':				pflag= 1;				break;			case 'i':				iflag= 1;				if (action == MOVE) fflag= 0;				break;			case 'f':				fflag= 1;				if (action == MOVE) iflag= 0;				break;			case 's':				if (action == LINK) {					sflag= 1;				} else {					/* Forget about POSIX, do it right. */					conforming= 0;				}				break;			case 'S':				Sflag= 1;				break;			case 'm':				mflag= 1;				break;			case 'r':				expand= 0;				/*FALL THROUGH*/			case 'R':				rflag= 1;				break;			case 'v':				vflag= 1;				break;			case 'x':				xflag= 1;				break;			default:				assert(0);			}		}	}	switch (action) {	case REMOVE:		if (i == argc) usage();		break;	case LINK:		/* 'ln dir/file' is to be read as 'ln dir/file .'. */		if ((argc - i) == 1 && action == LINK) argv[argc++]= ".";		/*FALL THROUGH*/	default:		if ((argc - i) < 2) usage();	}	path_init(&src);	path_init(&dst);	if (action != REMOVE && !mflag && stat(argv[argc-1], &st) >= 0						&& S_ISDIR(st.st_mode)) {		/* The last argument is a directory, this means we have to		 * throw the whole lot into this directory.  This is the		 * Right Thing unless you use -r.		 */		path_add(&dst, argv[argc-1]);		slash= path_length(&dst);		do {			path_add(&src, argv[i]);			path_add(&dst, basename(argv[i]));			do1(&src, &dst, 0);			path_trunc(&src, 0);			path_trunc(&dst, slash);		} while (++i < argc-1);	} else	if (action == REMOVE || (argc - i) == 2) {		/* Just two files (or many files for rm). */		do {			path_add(&src, argv[i]);			if (action != REMOVE) path_add(&dst, argv[i+1]);			do1(&src, &dst, 0);			path_trunc(&src, 0);		} while (action == REMOVE && ++i < argc);	} else {		usage();	}	path_drop(&src);	path_drop(&dst);#if DEBUG	(void) trylink(nil, nil, nil, nil);	if (nchunks != 0) {		fprintf(stderr, "(%ld chunks of memory not freed)\n",			(long) nchunks);	}#endif	exit(ex_code);}

⌨️ 快捷键说明

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