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

📄 file_subs.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 *	The Regents of the University of California.  All rights reserved. * * This code is derived from software contributed to Berkeley by * Keith Muller of the University of California, San Diego. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)file_subs.c	8.1 (Berkeley) 5/31/93";#endif /* not lint */#include <sys/types.h>#include <sys/time.h>#include <sys/stat.h>#include <unistd.h>#include <sys/param.h>#include <fcntl.h>#include <string.h>#include <stdio.h>#include <ctype.h>#include <errno.h>#include <sys/uio.h>#include <stdlib.h>#include "pax.h"#include "extern.h"static intmk_link __P((register char *,register struct stat *,register char *, int));/* * routines that deal with file operations such as: creating, removing; * and setting access modes, uid/gid and times of files */#define FILEBITS		(S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)#define SETBITS			(S_ISUID | S_ISGID)#define ABITS			(FILEBITS | SETBITS)/* * file_creat() *	Create and open a file. * Return: *	file descriptor or -1 for failure */#if __STDC__intfile_creat(register ARCHD *arcn)#elseintfile_creat(arcn)	register ARCHD *arcn;#endif{	int fd = -1;	mode_t file_mode;	int oerrno;	/*	 * assume file doesn't exist, so just try to create it, most times this	 * works. We have to take special handling when the file does exist. To	 * detect this, we use O_EXCL. For example when trying to create a	 * file and a character device or fifo exists with the same name, we	 * can accidently open the device by mistake (or block waiting to open)	 * If we find that the open has failed, then figure spend the effore to	 * figure out why. This strategy was found to have better average	 * performance in common use than checking the file (and the path)	 * first with lstat.	 */	file_mode = arcn->sb.st_mode & FILEBITS;	if ((fd = open(arcn->name, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,	    file_mode)) >= 0)		return(fd);	/*	 * the file seems to exist. First we try to get rid of it (found to be	 * the second most common failure when traced). If this fails, only	 * then we go to the expense to check and create the path to the file	 */	if (unlnk_exist(arcn->name, arcn->type) != 0)		return(-1);	for (;;) {		/*		 * try to open it again, if this fails, check all the nodes in		 * the path and give it a final try. if chk_path() finds that		 * it cannot fix anything, we will skip the last attempt		 */		if ((fd = open(arcn->name, O_WRONLY | O_CREAT | O_TRUNC,		    file_mode)) >= 0)			break;		oerrno = errno;		if (chk_path(arcn->name,arcn->sb.st_uid,arcn->sb.st_gid) < 0) {			syswarn(1, oerrno, "Unable to create %s", arcn->name);			return(-1);		}	}	return(fd);}/* * file_close() *	Close file descriptor to a file just created by pax. Sets modes, *	ownership and times as required. * Return: *	0 for success, -1 for failure */#if __STDC__voidfile_close(register ARCHD *arcn, int fd)#elsevoidfile_close(arcn, fd)	register ARCHD *arcn;	int fd;#endif{	int res = 0;	if (fd < 0)		return;	if (close(fd) < 0)		syswarn(0, errno, "Unable to close file descriptor on %s",		    arcn->name);	/*	 * set owner/groups first as this may strip off mode bits we want	 * then set file permission modes. Then set file access and	 * modification times. 	 */	if (pids)		res = set_ids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid);	/*	 * IMPORTANT SECURITY NOTE:	 * if not preserving mode or we cannot set uid/gid, then PROHIBIT	 * set uid/gid bits	 */	if (!pmode || res)		arcn->sb.st_mode &= ~(SETBITS);	if (pmode)		set_pmode(arcn->name, arcn->sb.st_mode);	if (patime || pmtime)		set_ftime(arcn->name, arcn->sb.st_mtime, arcn->sb.st_atime, 0);}/* * lnk_creat() *	Create a hard link to arcn->ln_name from arcn->name. arcn->ln_name *	must exist;  * Return: *	0 if ok, -1 otherwise */#if __STDC__intlnk_creat(register ARCHD *arcn)#elseintlnk_creat(arcn)	register ARCHD *arcn;#endif{	struct stat sb;	/*	 * we may be running as root, so we have to be sure that link target	 * is not a directory, so we lstat and check	 */	if (lstat(arcn->ln_name, &sb) < 0) {		syswarn(1,errno,"Unable to link to %s from %s", arcn->ln_name,		    arcn->name);		return(-1);	}	if (S_ISDIR(sb.st_mode)) {		warn(1, "A hard link to the directory %s is not allowed",		    arcn->ln_name);		return(-1);	}	return(mk_link(arcn->ln_name, &sb, arcn->name, 0));}/* * cross_lnk() *	Create a hard link to arcn->org_name from arcn->name. Only used in copy *	with the -l flag. No warning or error if this does not succeed (we will *	then just create the file) * Return: *	1 if copy() should try to create this file node *	0 if cross_lnk() ok, -1 for fatal flaw (like linking to self). */#if __STDC__intcross_lnk(register ARCHD *arcn)#elseintcross_lnk(arcn)	register ARCHD *arcn;#endif{	/*	 * try to make a link to orginal file (-l flag in copy mode). make sure	 * we do not try to link to directories in case we are running as root	 * (and it might succeed).	 */	if (arcn->type == PAX_DIR)		return(1);	return(mk_link(arcn->org_name, &(arcn->sb), arcn->name, 1));}/* * chk_same() *	In copy mode if we are not trying to make hard links between the src *	and destinations, make sure we are not going to overwrite ourselves by *	accident. This slows things down a little, but we have to protect all *	those people who make typing errors. * Return: *	1 the target does not exist, go ahead and copy *	0 skip it file exists (-k) or may be the same as source file */#if __STDC__intchk_same(register ARCHD *arcn)#elseintchk_same(arcn)	register ARCHD *arcn;#endif{	struct stat sb;	/* 	 * if file does not exist, return. if file exists and -k, skip it	 * quietly	 */	if (lstat(arcn->name, &sb) < 0)		return(1);	if (kflag)		return(0);	/*	 * better make sure the user does not have src == dest by mistake	 */	if ((arcn->sb.st_dev == sb.st_dev) && (arcn->sb.st_ino == sb.st_ino)) {		warn(1, "Unable to copy %s, file would overwrite itself",		    arcn->name);		return(0);	}	return(1);}/* * mk_link() *	try to make a hard link between two files. if ign set, we do not *	complain. * Return: *	0 if successful (or we are done with this file but no error, such as *	finding the from file exists and the user has set -k). *	1 when ign was set to indicates we could not make the link but we *	should try to copy/extract the file as that might work (and is an *	allowed option). -1 an error occurred. */#if __STDC__static intmk_link(register char *to, register struct stat *to_sb, register char *from,	int ign)#elsestatic intmk_link(to, to_sb, from, ign)	register char *to;	register struct stat *to_sb;	register char *from;	int ign;#endif{	struct stat sb;	int oerrno;	/*	 * if from file exists, it has to be unlinked to make the link. If the	 * file exists and -k is set, skip it quietly	 */	if (lstat(from, &sb) == 0) {		if (kflag)			return(0);		/*		 * make sure it is not the same file, protect the user		 */		if ((to_sb->st_dev==sb.st_dev)&&(to_sb->st_ino == sb.st_ino)) {			warn(1, "Unable to link file %s to itself", to);			return(-1);;		}		/*		 * try to get rid of the file, based on the type		 */		if (S_ISDIR(sb.st_mode)) {			if (rmdir(from) < 0) {				syswarn(1, errno, "Unable to remove %s", from);				return(-1);			}		} else if (unlink(from) < 0) {			if (!ign) {				syswarn(1, errno, "Unable to remove %s", from);				return(-1);			}			return(1);		}	}	/*	 * from file is gone (or did not exist), try to make the hard link.	 * if it fails, check the path and try it again (if chk_path() says to	 * try again)	 */	for (;;) {		if (link(to, from) == 0)			break;		oerrno = errno;		if (chk_path(from, to_sb->st_uid, to_sb->st_gid) == 0)			continue;		if (!ign) {			syswarn(1, oerrno, "Could not link to %s from %s", to,			    from);			return(-1);		}		return(1);	}	/*	 * all right the link was made	 */	return(0);}/* * node_creat() *	create an entry in the file system (other than a file or hard link). *	If successful, sets uid/gid modes and times as required. * Return: *	0 if ok, -1 otherwise */#if __STDC__intnode_creat(register ARCHD *arcn)#elseintnode_creat(arcn)	register ARCHD *arcn;#endif{	register int res;	register int ign = 0;	register int oerrno;	register int pass = 0;	mode_t file_mode;	struct stat sb;	/*	 * create node based on type, if that fails try to unlink the node and	 * try again. finally check the path and try again. As noted in the	 * file and link creation routines, this method seems to exhibit the	 * best performance in general use workloads.	 */	file_mode = arcn->sb.st_mode & FILEBITS;	for (;;) {		switch(arcn->type) {		case PAX_DIR:			res = mkdir(arcn->name, file_mode);			if (ign)				res = 0;			break;		case PAX_CHR:			file_mode |= S_IFCHR;			res = mknod(arcn->name, file_mode, arcn->sb.st_rdev);			break;		case PAX_BLK:			file_mode |= S_IFBLK;			res = mknod(arcn->name, file_mode, arcn->sb.st_rdev);			break;		case PAX_FIF:			res = mkfifo(arcn->name, file_mode);			break;		case PAX_SCK:			/*			 * Skip sockets, operation has no meaning under BSD			 */			warn(0,			    "%s skipped. Sockets cannot be copied or extracted",			    arcn->name);			return(-1);		case PAX_SLK:			if ((res = symlink(arcn->ln_name, arcn->name)) == 0)				return(0);			break;		case PAX_CTG:		case PAX_HLK:		case PAX_HRG:		case PAX_REG:		default:			/*			 * we should never get here			 */			warn(0, "%s has an unknown file type, skipping",				arcn->name);			return(-1);		}		/*		 * if we were able to create the node break out of the loop,		 * otherwise try to unlink the node and try again. if that		 * fails check the full path and try a final time.		 */		if (res == 0)			break;		/*		 * we failed to make the node		 */		oerrno = errno;		if ((ign = unlnk_exist(arcn->name, arcn->type)) < 0)			return(-1);		if (++pass <= 1)			continue;		if (chk_path(arcn->name,arcn->sb.st_uid,arcn->sb.st_gid) < 0) {			syswarn(1, oerrno, "Could not create: %s", arcn->name);			return(-1);		}	}	/*	 * we were able to create the node. set uid/gid, modes and times	 */	if (pids)		res = set_ids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid);	else		res = 0;	/*	 * IMPORTANT SECURITY NOTE:	 * if not preserving mode or we cannot set uid/gid, then PROHIBIT any	 * set uid/gid bits	 */	if (!pmode || res)		arcn->sb.st_mode &= ~(SETBITS);	if (pmode)		set_pmode(arcn->name, arcn->sb.st_mode);	if (arcn->type == PAX_DIR) {		/*		 * Dirs must be processed again at end of extract to set times		 * and modes to agree with those stored in the archive. However		 * to allow extract to continue, we may have to also set owner		 * rights. This allows nodes in the archive that are children		 * of this directory to be extracted without failure. Both time		 * and modes will be fixed after the entire archive is read and		 * before pax exits.		 */		if (access(arcn->name, R_OK | W_OK | X_OK) < 0) {			if (lstat(arcn->name, &sb) < 0) {				syswarn(0, errno,"Could not access %s (stat)",				    arcn->name);				set_pmode(arcn->name,file_mode | S_IRWXU);			} else {				/*				 * We have to add rights to the dir, so we make				 * sure to restore the mode. The mode must be				 * restored AS CREATED and not as stored if				 * pmode is not set.				 */				set_pmode(arcn->name,				    ((sb.st_mode & FILEBITS) | S_IRWXU));				if (!pmode)					arcn->sb.st_mode = sb.st_mode;			}			/*			 * we have to force the mode to what was set here,			 * since we changed it from the default as created.			 */			add_dir(arcn->name, arcn->nlen, &(arcn->sb), 1);		} else if (pmode || patime || pmtime)			add_dir(arcn->name, arcn->nlen, &(arcn->sb), 0);	}	if (patime || pmtime)		set_ftime(arcn->name, arcn->sb.st_mtime, arcn->sb.st_atime, 0);

⌨️ 快捷键说明

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