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

📄 extract.c

📁 unix 下tar 执行程序的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*			if (head->header.linkflag == LF_SPARSE) {
				off_t pos;
				
				pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
				printf("%d at %d\n", (int) pos, sparse_ind);
				written = sparsearray[sparse_ind++].numbytes;
			} else*/
			written = endofrecs()->charptr - data;
			if (written > size)
				written = size;
			errno = 0;
			check = write(fd, data, written);
			/*
			 * The following is in violation of strict
			 * typing, since the arg to userec
			 * should be a struct rec *.  FIXME.
			 */
			userec((union record *)(data + written - 1));
			if (check == written) continue;
			/*
			 * Error in writing to file.
			 * Print it, skip to next file in archive.
			 */
			if(check<0)
				msg_perror("couldn't write to file %s",skipcrud+head->header.name);
			else
				msg("could only write %d of %d bytes to file %s",written,check,skipcrud+head->header.name);
			skip_file((long)(size - written));
			break;	/* Still do the close, mod time, chmod, etc */
		}

		if(f_multivol)
			save_name = 0;

			/* If writing to stdout, don't try to do anything
			   to the filename; it doesn't exist, or we don't
			   want to touch it anyway */
		if(f_exstdout)
			break;
			
/*		if (head->header.isextended) {
			register union record *exhdr;
			register int i;
			
			for (i = 0; i < 21; i++) {
				long offset;
				
				if (!exhdr->ext_hdr.sp[i].numbytes)
					break;
				offset = from_oct(1+12,
 						exhdr->ext_hdr.sp[i].offset);
				written = from_oct(1+12,
 						exhdr->ext_hdr.sp[i].numbytes);
				lseek(fd, offset, 0);
				check = write(fd, data, written);
				if (check == written) continue;

			}
			

		}*/
 		check = close(fd);
		if (check < 0) {
			msg_perror("Error while closing %s",skipcrud+head->header.name);
		}

		
	set_filestat:

		/*
		 * If we are root, set the owner and group of the extracted
		 * file.  This does what is wanted both on real Unix and on
		 * System V.  If we are running as a user, we extract as that
		 * user; if running as root, we extract as the original owner.
		 */
		if (we_are_root || f_do_chown) {
			if (chown(skipcrud+head->header.name, hstat.st_uid,
				  hstat.st_gid) < 0) {
				msg_perror("cannot chown file %s to uid %d gid %d",skipcrud+head->header.name,hstat.st_uid,hstat.st_gid);
			}
		}

		/*
		 * Set the modified time of the file.
		 * 
		 * Note that we set the accessed time to "now", which
		 * is really "the time we started extracting files".
		 * unless f_gnudump is used, in which case .st_atime is used
		 */
		if (!f_modified) {
			/* fixme if f_gnudump should set ctime too, but how? */
			if(f_gnudump)
				acc_upd_times[0]=hstat.st_atime;
			else acc_upd_times[0] = now;	         /* Accessed now */
			acc_upd_times[1] = hstat.st_mtime; /* Mod'd */
			if (utime(skipcrud+head->header.name,
			    acc_upd_times) < 0) {
				msg_perror("couldn't change access and modification times of %s",skipcrud+head->header.name);
			}
		}
		/* We do the utime before the chmod because some versions of
		   utime are broken and trash the modes of the file.  Since
		   we then change the mode anyway, we don't care. . . */

		/*
		 * If '-k' is not set, open() or creat() could have saved
		 * the permission bits from a previously created file,
		 * ignoring the ones we specified.
		 * Even if -k is set, if the file has abnormal
		 * mode bits, we must chmod since writing or chown() has
		 * probably reset them.
		 *
		 * If -k is set, we know *we* created this file, so the mode
		 * bits were set by our open().   If the file is "normal", we
		 * skip the chmod.  This works because we did umask(0) if -p
		 * is set, so umask will have left the specified mode alone.
		 */
		if ((!f_keep)
		    || (hstat.st_mode & (S_ISUID|S_ISGID|S_ISVTX))) {
			if (chmod(skipcrud+head->header.name,
				  notumask & (int)hstat.st_mode) < 0) {
				msg_perror("cannot change mode of file %s to %ld",skipcrud+head->header.name,notumask & (int)hstat.st_mode);
			}
		}

	quit:
		break;

	case LF_LINK:
	again_link:
	{
		struct stat st1,st2;

		check = link (head->header.linkname,
			      skipcrud+head->header.name);
		if (check == 0)
			break;
		if (make_dirs(skipcrud+head->header.name))
			goto again_link;
		if(f_gnudump && errno==EEXIST)
			break;
		if(   stat(head->header.linkname, &st1) == 0
		   && stat(skipcrud+head->header.name, &st2)==0
		   && st1.st_dev==st2.st_dev
		   && st1.st_ino==st2.st_ino)
			break;
		msg_perror("Could not link %s to %s",
			skipcrud+head->header.name,head->header.linkname);
	}
		break;

#ifdef S_IFLNK
	case LF_SYMLINK:
	again_symlink:
		check = symlink(head->header.linkname,
			        skipcrud+head->header.name);
		/* FIXME, don't worry uid, gid, etc... */
		if (check == 0)
			break;
		if (make_dirs(skipcrud+head->header.name))
			goto again_symlink;
		msg_perror("Could not create symlink to %s",head->header.linkname);
		break;
#endif

#ifdef S_IFCHR
	case LF_CHR:
		hstat.st_mode |= S_IFCHR;
		goto make_node;
#endif

#ifdef S_IFBLK
	case LF_BLK:
		hstat.st_mode |= S_IFBLK;
		goto make_node;
#endif

#ifdef S_IFIFO
	/* If local system doesn't support FIFOs, use default case */
	case LF_FIFO:
		hstat.st_mode |= S_IFIFO;
		hstat.st_rdev = 0;		/* FIXME, do we need this? */
		goto make_node;
#endif

	make_node:
		check = mknod(skipcrud+head->header.name,
			      (int) hstat.st_mode, (int) hstat.st_rdev);
		if (check != 0) {
			if (make_dirs(skipcrud+head->header.name))
				goto make_node;
			msg_perror("Could not make %s",skipcrud+head->header.name);
			break;
		};
		goto set_filestat;

	case LF_DIR:
	case LF_DUMPDIR:
		namelen = strlen(skipcrud+head->header.name)-1;
	really_dir:
		/* Check for trailing /, and zap as many as we find. */
		while (namelen && head->header.name[skipcrud+namelen] == '/')
			head->header.name[skipcrud+namelen--] = '\0';
		if(f_gnudump) {		/* Read the entry and delete files
					   that aren't listed in the archive */
			gnu_restore(skipcrud);
		
		} else if(head->header.linkflag==LF_DUMPDIR)
			skip_file((long)(hstat.st_size));

	
	again_dir:
		check = mkdir(skipcrud+head->header.name,
			      (we_are_root ? 0 : 0300) | (int)hstat.st_mode);
		if (check != 0) {
			struct stat st1;

			if (make_dirs(skipcrud+head->header.name))
				goto again_dir;
			/* If we're trying to create '.', let it be. */
			if (head->header.name[skipcrud+namelen] == '.' && 
			    (namelen==0 ||
			     head->header.name[skipcrud+namelen-1]=='/'))
				goto check_perms;
			if(   errno==EEXIST
 			   && stat(skipcrud+head->header.name,&st1)==0
 			   && (st1.st_mode&S_IFMT)==S_IFDIR)
				break;
			msg_perror("Could not create directory %s",skipcrud+head->header.name);
			break;
		}
		
	check_perms:
		if (!we_are_root && 0300 != (0300 & (int) hstat.st_mode)) {
			hstat.st_mode |= 0300;
			msg("Added write and execute permission to directory %s",
			  skipcrud+head->header.name);
		}

		goto set_filestat;
		/* FIXME, Remember timestamps for after files created? */
		/* FIXME, change mode after files created (if was R/O dir) */
	case LF_VOLHDR:
		if(f_verbose) {
			printf("Reading %s\n",head->header.name);
		}
		break;

	case LF_NAMES:
		extract_mangle(head);
		break;

	case LF_MULTIVOL:
		msg("Can't extract '%s'--file is continued from another volume\n",head->header.name);
		skip_file((long)hstat.st_size);
		break;

	}

	/* We don't need to save it any longer. */
	saverec((union record **) 0);	/* Unsave it */
}

/*
 * After a file/link/symlink/dir creation has failed, see if
 * it's because some required directory was not present, and if
 * so, create all required dirs.
 */
int
make_dirs(pathname)
	char *pathname;
{
	char *p;			/* Points into path */
	int madeone = 0;		/* Did we do anything yet? */
	int save_errno = errno;		/* Remember caller's errno */
	int check;

	if (errno != ENOENT)
		return 0;		/* Not our problem */

	for (p = index(pathname, '/'); p != NULL; p = index(p+1, '/')) {
		/* Avoid mkdir of empty string, if leading or double '/' */
		if (p == pathname || p[-1] == '/')
			continue;
		/* Avoid mkdir where last part of path is '.' */
		if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
			continue;
		*p = 0;				/* Truncate the path there */
		check = mkdir (pathname, 0777);	/* Try to create it as a dir */
		if (check == 0) {
			/* Fix ownership */
			if (we_are_root) {
				if (chown(pathname, hstat.st_uid,
					  hstat.st_gid) < 0) {
					msg_perror("cannot change owner of %s to uid %d gid %d",pathname,hstat.st_uid,hstat.st_gid);
				}
			}
			pr_mkdir(pathname, p-pathname, notumask&0777);
			madeone++;		/* Remember if we made one */
			*p = '/';
			continue;
		}
		*p = '/';
		if (errno == EEXIST)		/* Directory already exists */
			continue;
		/*
		 * Some other error in the mkdir.  We return to the caller.
		 */
		break;
	}

	errno = save_errno;		/* Restore caller's errno */
	return madeone;			/* Tell them to retry if we made one */
}

extract_sparse_file(fd, sizeleft, totalsize, name)
	int	fd;
	long	*sizeleft,
		totalsize;
	char	*name;
{		
	register char	*data;
	union record	*datarec;
	int	sparse_ind = 0;
	int	written,
		count;
	
	/* assuming sizeleft is initially totalsize */


	while (*sizeleft > 0) {
		datarec = findrec();
		if (datarec == NULL) {
			msg("Unexpected EOF on archive file");
			return;
		}
		lseek(fd, sparsearray[sparse_ind].offset, 0);
		written = sparsearray[sparse_ind++].numbytes;
		while (written > RECORDSIZE) {
			count = write(fd, datarec->charptr, RECORDSIZE);
			if (count < 0) 
				msg_perror("couldn't write to file %s", name);
			written -= count;
			*sizeleft -= count;
			userec(datarec);
			datarec = findrec();
		}

		count = write(fd, datarec->charptr, written);
	        
		if (count < 0) {
			msg_perror("couldn't write to file %s", name);
		} else if (count != written) {
			msg("could only write %d of %d bytes to file %s", totalsize - *sizeleft, totalsize, name);
			skip_file((long) (*sizeleft));
		}

		written -= count;
		*sizeleft -= count;		
		userec(datarec);
	}
	free(sparsearray);
/*	if (end_nulls) {
		register int i;

		printf("%d\n", (int) end_nulls);
		for (i = 0; i < end_nulls; i++)
			write(fd, "\000", 1);
	}*/
	userec(datarec);
}

⌨️ 快捷键说明

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