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

📄 file_subs.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
	return(0);}/* * unlnk_exist() *	Remove node from file system with the specified name. We pass the type *	of the node that is going to replace it. When we try to create a *	directory and find that it already exists, we allow processing to *	continue as proper modes etc will always be set for it later on. * Return: *	0 is ok to proceed, no file with the specified name exists *	-1 we were unable to remove the node, or we should not remove it (-k) *	1 we found a directory and we were going to create a directory. */#if __STDC__intunlnk_exist(register char *name, register int type)#elseintunlnk_exist(name, type)	register char *name;	register int type;#endif{	struct stat sb;	/*	 * the file does not exist, or -k we are done	 */	if (lstat(name, &sb) < 0)		return(0);	if (kflag)		return(-1);	if (S_ISDIR(sb.st_mode)) {		/*		 * try to remove a directory, if it fails and we were going to		 * create a directory anyway, tell the caller (return a 1)		 */		if (rmdir(name) < 0) {			if (type == PAX_DIR)				return(1); 			syswarn(1,errno,"Unable to remove directory %s", name);			return(-1);		}		return(0);	}	/*	 * try to get rid of all non-directory type nodes	 */	if (unlink(name) < 0) {		syswarn(1, errno, "Could not unlink %s", name);		return(-1);	}	return(0);}/* * chk_path() *	We were trying to create some kind of node in the file system and it *	failed. chk_path() makes sure the path up to the node exists and is *	writeable. When we have to create a directory that is missing along the *	path somewhere, the directory we create will be set to the same *	uid/gid as the file has (when uid and gid are being preserved). *	NOTE: this routine is a real performance loss. It is only used as a *	last resort when trying to create entries in the file system. * Return: *	-1 when it could find nothing it is allowed to fix. *	0 otherwise */#if __STDC__intchk_path( register char *name, uid_t st_uid, gid_t st_gid)#elseintchk_path(name, st_uid, st_gid)	register char *name;	uid_t st_uid;	gid_t st_gid;#endif{	register char *spt = name;	struct stat sb;	int retval = -1;	/*	 * watch out for paths with nodes stored directly in / (e.g. /bozo)	 */	if (*spt == '/')		++spt;	for(;;) {		/*		 * work foward from the first / and check each part of the path		 */		spt = strchr(spt, '/');		if (spt == NULL)			break;		*spt = '\0';		/*		 * if it exists we assume it is a directory, it is not within		 * the spec (at least it seems to read that way) to alter the		 * file system for nodes NOT EXPLICITLY stored on the archive.		 * If that assumption is changed, you would test the node here		 * and figure out how to get rid of it (probably like some		 * recursive unlink()) or fix up the directory permissions if		 * required (do an access()).		 */		if (lstat(name, &sb) == 0) {			*(spt++) = '/';			continue;		}		/*		 * the path fails at this point, see if we can create the		 * needed directory and continue on		 */		if (mkdir(name, S_IRWXU | S_IRWXG | S_IRWXO) < 0) {			*spt = '/';			retval = -1;			break;		}		/*		 * we were able to create the directory. We will tell the		 * caller that we found something to fix, and it is ok to try		 * and create the node again.		 */		retval = 0;		if (pids)			(void)set_ids(name, st_uid, st_gid);		/*		 * make sure the user doen't have some strange umask that		 * causes this newly created directory to be unusable. We fix		 * the modes and restore them back to the creation default at		 * the end of pax		 */		if ((access(name, R_OK | W_OK | X_OK) < 0) &&		    (lstat(name, &sb) == 0)) {			set_pmode(name, ((sb.st_mode & FILEBITS) | S_IRWXU));			add_dir(name, spt - name, &sb, 1);		}		*(spt++) = '/';		continue;	}	return(retval);}/* * set_ftime() *	Set the access time and modification time for a named file. If frc is *	non-zero we force these times to be set even if the the user did not *	request access and/or modification time preservation (this is also *	used by -t to reset access times). *	When ign is zero, only those times the user has asked for are set, the *	other ones are left alone. We do not assume the un-documented feature *	of many utimes() implementations that consider a 0 time value as a do *	not set request. */#if __STDC__voidset_ftime(char *fnm, time_t mtime, time_t atime, int frc)#elsevoidset_ftime(fnm, mtime, atime, frc)	char *fnm;	time_t mtime;	time_t atime;	int frc;#endif{	static struct timeval tv[2] = {{0L, 0L}, {0L, 0L}};	struct stat sb;	tv[0].tv_sec = (long)atime;	tv[1].tv_sec = (long)mtime;	if (!frc && (!patime || !pmtime)) {		/*		 * if we are not forcing, only set those times the user wants		 * set. We get the current values of the times if we need them.		 */		if (lstat(fnm, &sb) == 0) {			if (!patime)				tv[0].tv_sec = (long)sb.st_atime;			if (!pmtime)				tv[1].tv_sec = (long)sb.st_mtime;		} else			syswarn(0,errno,"Unable to obtain file stats %s", fnm);	}	/*	 * set the times	 */	if (utimes(fnm, tv) < 0)		syswarn(1, errno, "Access/modification time set failed on: %s",		    fnm);	return;}/* * set_ids() *	set the uid and gid of a file system node * Return: *	0 when set, -1 on failure */#if __STDC__intset_ids(char *fnm, uid_t uid, gid_t gid)#elseintset_ids(fnm, uid, gid)	char *fnm;	uid_t uid;	gid_t gid;#endif{	if (chown(fnm, uid, gid) < 0) {		syswarn(1, errno, "Unable to set file uid/gid of %s", fnm);		return(-1);	}	return(0);}/* * set_pmode() *	Set file access mode */#if __STDC__voidset_pmode(char *fnm, mode_t mode)#elsevoidset_pmode(fnm, mode)	char *fnm;	mode_t mode;#endif{	mode &= ABITS;	if (chmod(fnm, mode) < 0)		syswarn(1, errno, "Could not set permissions on %s", fnm);	return;}/* * file_write() *	Write/copy a file (during copy or archive extract). This routine knows *	how to copy files with lseek holes in it. (Which are read as file *	blocks containing all 0's but do not have any file blocks associated *	with the data). Typical examples of these are files created by dbm *	variants (.pag files). While the file size of these files are huge, the *	actual storage is quite small (the files are sparse). The problem is *	the holes read as all zeros so are probably stored on the archive that *	way (there is no way to determine if the file block is really a hole, *	we only know that a file block of all zero's can be a hole). *	At this writing, no major archive format knows how to archive files *	with holes. However, on extraction (or during copy, -rw) we have to *	deal with these files. Without detecting the holes, the files can *	consume a lot of file space if just written to disk. This replacement *	for write when passed the basic allocation size of a file system block, *	uses lseek whenever it detects the input data is all 0 within that *	file block. In more detail, the strategy is as follows: *	While the input is all zero keep doing an lseek. Keep track of when we *	pass over file block boundries. Only write when we hit a non zero *	input. once we have written a file block, we continue to write it to *	the end (we stop looking at the input). When we reach the start of the *	next file block, start checking for zero blocks again. Working on file *	block boundries significantly reduces the overhead when copying files *	that are NOT very sparse. This overhead (when compared to a write) is *	almost below the measurement resolution on many systems. Without it, *	files with holes cannot be safely copied. It does has a side effect as *	it can put holes into files that did not have them before, but that is *	not a problem since the file contents are unchanged (in fact it saves *	file space). (Except on paging files for diskless clients. But since we *	cannot determine one of those file from here, we ignore them). If this *	ever ends up on a system where CTG files are supported and the holes *	are not desired, just do a conditional test in those routines that *	call file_write() and have it call write() instead. BEFORE CLOSING THE *	FILE, make sure to call file_flush() when the last write finishes with *	an empty block. A lot of file systems will not create an lseek hole at *	the end. In this case we drop a single 0 at the end to force the *	trailing 0's in the file. *	---Parameters--- *	rem: how many bytes left in this file system block *	isempt: have we written to the file block yet (is it empty) *	sz: basic file block allocation size *	cnt: number of bytes on this write *	str: buffer to write * Return: *	number of bytes written, -1 on write (or lseek) error. */#if __STDC__intfile_write(int fd, char *str, register int cnt, int *rem, int *isempt, int sz,	char *name)#elseintfile_write(fd, str, cnt, rem, isempt, sz, name)	int fd;	char *str;	register int cnt;	int *rem;	int *isempt;	int sz;	char *name;#endif{	register char *pt;	register char *end;	register int wcnt;	register char *st = str;		/*	 * while we have data to process	 */	while (cnt) {		if (!*rem) {			/*			 * We are now at the start of file system block again			 * (or what we think one is...). start looking for			 * empty blocks again			 */			*isempt = 1;			*rem = sz;		}		/*		 * only examine up to the end of the current file block or		 * remaining characters to write, whatever is smaller		 */		wcnt = MIN(cnt, *rem);		cnt -= wcnt;		*rem -= wcnt;		if (*isempt) {			/*			 * have not written to this block yet, so we keep			 * looking for zero's			 */			pt = st;			end = st + wcnt;			/*			 * look for a zero filled buffer			 */			while ((pt < end) && (*pt == '\0'))				++pt;			if (pt == end) {				/*				 * skip, buf is empty so far				 */				if (lseek(fd, (off_t)wcnt, SEEK_CUR) < 0) {					syswarn(1,errno,"File seek on %s",					    name);					return(-1);				}				st = pt;				continue;			}			/*			 * drat, the buf is not zero filled			 */			*isempt = 0;		}		/*		 * have non-zero data in this file system block, have to write		 */		if (write(fd, st, wcnt) != wcnt) {			syswarn(1, errno, "Failed write to file %s", name);			return(-1);		}		st += wcnt;	}	return(st - str);}/* * file_flush() *	when the last file block in a file is zero, many file systems will not *	let us create a hole at the end. To get the last block with zeros, we *	write the last BYTE with a zero (back up one byte and write a zero). */#if __STDC__voidfile_flush(int fd, char *fname, int isempt)#elsevoidfile_flush(fd, fname, isempt)	int fd;	char *fname;	int isempt;#endif{	static char blnk[] = "\0";	/*	 * silly test, but make sure we are only called when the last block is	 * filled with all zeros.	 */	if (!isempt)		return;	/*	 * move back one byte and write a zero	 */	if (lseek(fd, (off_t)-1, SEEK_CUR) < 0) {		syswarn(1, errno, "Failed seek on file %s", fname);		return;	}	if (write(fd, blnk, 1) < 0)		syswarn(1, errno, "Failed write to file %s", fname);	return;}/* * rdfile_close() *	close a file we have beed reading (to copy or archive). If we have to *	reset access time (tflag) do so (the times are stored in arcn). */#if __STDC__voidrdfile_close(register ARCHD *arcn, register int *fd)#elsevoidrdfile_close(arcn, fd)	register ARCHD *arcn;	register int *fd;#endif{	/*	 * make sure the file is open	 */	if (*fd < 0)		return;	(void)close(*fd);	*fd = -1;	if (!tflag)		return;	/*	 * user wants last access time reset	 */	set_ftime(arcn->org_name, arcn->sb.st_mtime, arcn->sb.st_atime, 1);	return;}/* * set_crc() *	read a file to calculate its crc. This is a real drag. Archive formats *	that have this, end up reading the file twice (we have to write the *	header WITH the crc before writing the file contents. Oh well... * Return: *	0 if was able to calculate the crc, -1 otherwise */#if __STDC__intset_crc(register ARCHD *arcn, register int fd)#elseintset_crc(arcn, fd)	register ARCHD *arcn;	register int fd;#endif{	register int i;	register int res;	off_t cpcnt = 0L;	u_long size;	unsigned long crc = 0L;	char tbuf[FILEBLK];	struct stat sb;	if (fd < 0) {		/*		 * hmm, no fd, should never happen. well no crc then.		 */		arcn->crc = 0L;		return(0);	}	if ((size = (u_long)arcn->sb.st_blksize) > (u_long)sizeof(tbuf))		size = (u_long)sizeof(tbuf);	/*	 * read all the bytes we think that there are in the file. If the user	 * is trying to archive an active file, forget this file.	 */	for(;;) {		if ((res = read(fd, tbuf, size)) <= 0)			break;		cpcnt += res;		for (i = 0; i < res; ++i)			crc += (tbuf[i] & 0xff);	}	/*	 * safety check. we want to avoid archiving files that are active as	 * they can create inconsistant archive copies.	 */	if (cpcnt != arcn->sb.st_size)		warn(1, "File changed size %s", arcn->org_name);	else if (fstat(fd, &sb) < 0)		syswarn(1, errno, "Failed stat on %s", arcn->org_name);	else if (arcn->sb.st_mtime != sb.st_mtime)		warn(1, "File %s was modified during read", arcn->org_name);	else if (lseek(fd, (off_t)0L, SEEK_SET) < 0)		syswarn(1, errno, "File rewind failed on: %s", arcn->org_name);	else {		arcn->crc = crc;		return(0);	}	return(-1);}

⌨️ 快捷键说明

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