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

📄 tar.c

📁 操作系统源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* tar - tape archiver			Author: Michiel Huisjes *//* Usage: tar [cxt][vo][F][f] tapefile [files] * * attempt to make tar to conform to POSIX 1003.1 * disclaimer: based on an old (1986) POSIX draft. * Klamer Schutte, 20/9/89 * * Changes: *  Changed to handle the original minix-tar format.	KS 22/9/89 *  Changed to handle BSD4.3 tar format.		KS 22/9/89 *  Conform to current umask if not super-user.		KS 22/9/89 *  Update usage message to show f option		KS 22/9/89 * * * 1)	tar will back itself up, should check archive inode num(&dev) and  then check the target inode number. In verbose mode, issue  warning, in all cases ignore target.  marks@mgse		Mon Sep 25 10:38:58 CDT 1989  	added global varaibles, made changes to main() and add_file();  maks@mgse Mon Sep 25 12:09:20 CDT 1989   2)	tar will not notice that a file has changed size while it was being  backed up. should issue warning.  marks@mgse		Mon Sep 25 10:38:58 CDT 1989   3)	the 'f' option was not documented in usage[].  marks@mgse		Mon Sep 25 12:03:20 CDT 1989  	changed both usage[] defines. Why are there two (one is commented out)?  	( deleted by me (was done twice) -- KS, 2/10/89 ) * *  changed stat on tar_fd to an fstat				KS 2/10/89 *  deleted mkfifo() code -- belongs in libc.a			KS 2/10/89 *  made ar_dev default to -1 : an illegal device		KS 2/10/89 *  made impossible to chown if normal user			KS 2/10/89 *  if names in owner fields not known use numirical values	KS 2/10/89 *  creat with mask 666 -- use umask if to liberal		KS 2/10/89 *  allow to make directories as ../directory			KS 2/10/89 *  allow tmagic field to end with a space (instead of \0)	KS 2/10/89 *  correct usage of tmagic field 				KS 3/10/89 *  made mkdir() to return a value if directory == "."  	KS 3/10/89 *  made lint complains less (On a BSD 4.3 system)		KS 3/10/89 *  use of directory(3) routines				KS 3/10/89 *  deleted use of d_namlen selector of struct dirent		KS 18/10/89 *  support mknod4(2)						EC 7/7/90 *  forget inodes when link count expires			EC 6/4/91 *  don't remember directories *twice*! *  added 'p' flag to ignore umask for normal user		KJB 6/10/92 *  mknod4(2) out						KJB 30/10/94 *  added 'D' flag to not recurse into directories		KJB 19/12/94 * * Bugs: *  verbose mode is not reporting consistent *  code needs cleanup *  prefix field is not used *  timestamp of a directory will not be correct if there are files to be *  unpacked in the directory *	(add you favorite bug here (or two (or three (or ...))))*/#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <pwd.h>#include <grp.h>#include <tar.h>#include <stdarg.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <utime.h>#include <sys/wait.h>#include <stdio.h>		/* need NULL */#include <errno.h>#define	POSIX_COMP		/* POSIX compatible */#define DIRECT_3		/* use directory(3) routines */#ifdef DIRECT_3#ifndef BSD/* To all minix users: i am sorry, developed this piece of code on a * BSD system. KS 18/10/89 */#include <dirent.h>#define	direct	dirent		/* stupid BSD non-POSIX compatible name! */#else				/* BSD */#include <sys/dir.h>#include <dir.h>#endif				/* BSD */#endif				/* DIRECT_3 */#ifdef S_IFIFO#define	HAVE_FIFO		/* have incorporated Simon Pooles' changes */#endif#ifdef S_IFLNK#define HAVE_SYMLINK#endiftypedef char BOOL;#define TRUE	1#define FALSE	0#define STRING_SIZE	256	/* string buffer size */#define HEADER_SIZE	TBLOCK#define NAME_SIZE	NAMSIZ/* #define BLOCK_BOUNDARY	 20 -- not in POSIX ! */typedef union hblock HEADER;/* Make the MINIX member names overlap to the POSIX names */#define	m_name		name#define m_mode		mode#define m_uid		uid#define m_gid		gid#define m_size		size#define	m_time		mtime#define	m_checksum	chksum#define	m_linked	typeflag#define	m_link		linkname#define	hdr_block	dummy#define	m		header#define	member		dbuf#if 0				/* original structure -- see tar.h for new			 * structure */typedef union {  char hdr_block[HEADER_SIZE];  struct m {	char m_name[NAME_SIZE];	char m_mode[8];	char m_uid[8];	char m_gid[8];	char m_size[12];	char m_time[12];	char m_checksum[8];	char m_linked;	char m_link[NAME_SIZE];  } member;} HEADER;#endif/* Structure used to note links */struct link {  ino_t ino;  dev_t dev;  nlink_t nlink;  struct link *next;  char name[1];} *link_top = NULL;HEADER header;#define INT_TYPE	(sizeof(header.member.m_uid))#define LONG_TYPE	(sizeof(header.member.m_size))#define NIL_HEADER	((HEADER *) 0)#define NIL_PTR		((char *) 0)#define TBLOCK_SIZE	TBLOCK#define flush()		print(NIL_PTR)BOOL show_fl, creat_fl, ext_fl;int tar_fd;/* Char usage[] = "Usage: tar [cxt] tarfile [files]."; */char usage[] = "Usage: tar [cxt][vo][F][f] tarfile [files].";char io_buffer[TBLOCK_SIZE];char path[NAME_SIZE];char pathname[NAME_SIZE];int force_flag = 0;#ifdef ORIGINAL_DEFAULTSint chown_flag = 1;int verbose_flag = 1;#elseint chown_flag = 0;int verbose_flag = 0;#endifint norec_flag = 0;/* Make sure we don't tar ourselves. marks@mgse Mon Sep 25 12:06:28 CDT 1989 */ino_t ar_inode;			/* archive inode number	 */dev_t ar_dev;			/* archive device number */int total_blocks;int u_mask;			/* one's complement of current umask */#define block_size()	(int) ((convert(header.member.m_size, LONG_TYPE) \  + (long) TBLOCK_SIZE - 1) / (long) TBLOCK_SIZE)_PROTOTYPE(int main, (int argc, char **argv));_PROTOTYPE(void error, (char *s1, char *s2));_PROTOTYPE(BOOL get_header, (void));_PROTOTYPE(void tarfile, (void));_PROTOTYPE(void skip_entry, (void));_PROTOTYPE(void extract, (char *file));_PROTOTYPE(void delete, (char *file));_PROTOTYPE(void do_chown, (char *file));_PROTOTYPE(void timestamp, (char *file));_PROTOTYPE(void copy, (char *file, int from, int to, long bytes));_PROTOTYPE(long convert, (char str[], int type));_PROTOTYPE(int checksum, (void));_PROTOTYPE(int is_dir, (char *file));_PROTOTYPE(char *path_name, (char *file));_PROTOTYPE(void add_path, (char *name));_PROTOTYPE(void add_file, (char *file));_PROTOTYPE(void verb_print, (char *s1, char *s2));_PROTOTYPE(void add_close, (int fd));_PROTOTYPE(int add_open, (char *file, struct stat * st));_PROTOTYPE(void make_header, (char *file, struct stat * st));_PROTOTYPE(void is_added, (struct stat * st, char *file));_PROTOTYPE(void is_deleted, (struct stat * st));_PROTOTYPE(char *is_linked, (struct stat * st));_PROTOTYPE(void clear_header, (void));_PROTOTYPE(void adjust_boundary, (void));_PROTOTYPE(void mread, (int fd, char *address, int bytes));_PROTOTYPE(void mwrite, (int fd, char *address, int bytes));_PROTOTYPE(int bread, (int fd, char *address, int bytes));_PROTOTYPE(int bwrite, (int fd, char *address, int bytes));_PROTOTYPE(void print, (char *str));_PROTOTYPE(char *num_out, (long number));_PROTOTYPE(void string_print, (char *buffer, char *fmt,...));void error(s1, s2)char *s1, *s2;{  string_print(NIL_PTR, "%s %s\n", s1, s2 ? s2 : "");  flush();  exit(1);}int main(argc, argv)int argc;register char *argv[];{  register char *mem_name;  register char *ptr;  struct stat st;  int i;  if (argc < 3) error(usage, NIL_PTR);  for (ptr = argv[1]; *ptr; ptr++) {	switch (*ptr) {	    case 'c':	creat_fl = TRUE;	break;	    case 'x':	ext_fl = TRUE;	break;	    case 't':	show_fl = TRUE;	break;	    case 'v':		/* verbose output  -Dal */		verbose_flag = !verbose_flag;		break;	    case 'o':		/* chown/chgrp files  -Dal */		chown_flag = TRUE;		break;	    case 'F':		/* IGNORE ERRORS  -Dal */		force_flag = TRUE;		break;	    case 'f':		/* standard U*IX usage -KS */		break;	    case 'p':		/* restore file modes right, ignore umask. */		(void) umask(0);		break;	    case 'D':		/* do not recursively add directories. */		norec_flag = TRUE;		break;	    default:	error(usage, NIL_PTR);	}  }  if (creat_fl + ext_fl + show_fl != 1) error(usage, NIL_PTR);  if (strcmp(argv[2], "-") == 0)/* only - means stdin/stdout - KS */	tar_fd = creat_fl ? 1 : 0;	/* '-' means used					 * stdin/stdout  -Dal */  else	tar_fd = creat_fl ? creat(argv[2], 0666) : open(argv[2], O_RDONLY);  if (tar_fd < 0) error("Cannot open ", argv[2]);  if (geteuid()) {		/* check if super-user */	int save_umask;	save_umask = umask(0);	u_mask = ~save_umask;	umask(save_umask);	chown_flag = TRUE;	/* normal user can't chown */  } else	u_mask = ~0;		/* don't restrict if 'privileged utility' */  ar_dev = -1;			/* impossible device nr */  if (creat_fl) {	if (tar_fd > 1 && fstat(tar_fd, &st) < 0)		error("Can't stat ", argv[2]);	/* will never be here,						 * right? */	else {			/* get archive inode & device	 */		ar_inode = st.st_ino;	/* save files inode	 */		ar_dev = st.st_dev;	/* save files device	 */	}			/* marks@mgse Mon Sep 25 11:30:45 CDT 1989 */	for (i = 3; i < argc; i++) {		add_file(argv[i]);		path[0] = '\0';	}	adjust_boundary();  } else if (ext_fl) {	/* Extraction code moved here from tarfile() MSP */	while (get_header()) {		mem_name = header.member.m_name;		if (is_dir(mem_name)) {			for (ptr = mem_name; *ptr; ptr++);			*(ptr - 1) = '\0';			header.dbuf.typeflag = '5';		}		for (i = 3; i < argc; i++)			if (!strncmp(argv[i], mem_name, strlen(argv[i])))				break;		if (argc == 3 || (i < argc)) {			extract(mem_name);		} else if (header.dbuf.typeflag == '0' ||			   header.dbuf.typeflag == 0 ||			   header.dbuf.typeflag == ' ')			skip_entry();		flush();	}  } else	tarfile();		/* tarfile() justs prints info. now MSP */  flush();  return(0);}BOOL get_header(){  register int check;  mread(tar_fd, (char *) &header, sizeof(header));  if (header.member.m_name[0] == '\0') return FALSE;  if (force_flag)		/* skip checksum verification  -Dal */	return TRUE;  check = (int) convert(header.member.m_checksum, INT_TYPE);  if (check != checksum()) error("Tar: header checksum error.", NIL_PTR);  return TRUE;}/* Tarfile() just lists info about archive now; as of the t flag. *//* Extraction has been moved into main() as that needs access to argv[] */void tarfile(){  register char *mem_name;  while (get_header()) {	mem_name = header.member.m_name;	string_print(NIL_PTR, "%s%s", mem_name,		     (verbose_flag ? " " : "\n"));	switch (header.dbuf.typeflag) {	    case '1':		verb_print("linked to", header.dbuf.linkname);		break;	    case '2':		verb_print("symbolic link to", header.dbuf.linkname);		break;	    case '6':	verb_print("", "fifo");	break;	    case '3':	    case '4':		if (verbose_flag) {			char sizebuf[TSIZLEN + 1];			strncpy(sizebuf, header.dbuf.size, (size_t) TSIZLEN);			sizebuf[TSIZLEN] = 0;			string_print(NIL_PTR,			      "%s special file major %s minor %s\n",				     (header.dbuf.typeflag == '3' ?				      "character" : "block"),				     header.dbuf.devmajor,				     header.dbuf.devminor,				     sizebuf);		}		break;	    case '0':		/* official POSIX */	    case 0:		/* also mentioned in POSIX */	    case ' ':		/* ofetn used */		if (!is_dir(mem_name)) {			if (verbose_flag)				string_print(NIL_PTR, "%d tape blocks\n",					     block_size());			skip_entry();			break;		} else		/* FALL TROUGH */	    case '5':			verb_print("", "directory");		break;	    default:		string_print(NIL_PTR, "not recogised item %d\n",			     header.dbuf.typeflag);	}	flush();  }}void skip_entry(){  register int blocks = block_size();  while (blocks--) (void) bread(tar_fd, io_buffer, TBLOCK_SIZE);}void extract(file)register char *file;{  register int fd, r;  char *pd1, *pd2;		/* walk thru failed directory path */  switch (header.dbuf.typeflag) {      case '1':			/* Link */	delete(file);	if (link(header.member.m_link, file) < 0)		string_print(NIL_PTR, "Cannot link %s to %s: %s\n",			     header.member.m_link, file, strerror(errno));	else if (verbose_flag)		string_print(NIL_PTR, "Linked %s to %s\n",			     header.member.m_link, file);	return;      case '5':			/* directory */	if (!(file[0] == '.' && file[1] == '\0')) delete(file);	if ((file[0] == '.' && file[1] == '\0') || mkdir(file, 0700) == 0) {		do_chown(file);		verb_print("created directory", file);	} else {		string_print(NIL_PTR, "Can't make directory %s: %s\n",				file, strerror(errno));	}	return;      case '3':			/* character special */      case '4':			/* block special */	{		int dmajor, dminor, mode;		dmajor = (int) convert(header.dbuf.devmajor, INT_TYPE);		dminor = (int) convert(header.dbuf.devminor, INT_TYPE);		mode = (header.dbuf.typeflag == '3' ? S_IFCHR : S_IFBLK);		delete(file);		if (mknod(file, mode, (dmajor << 8 | dminor)) == 0) {			if (verbose_flag) string_print(NIL_PTR,				     "made %s special file major %s minor %s\n",				      (header.dbuf.typeflag == '3' ?				       "character" : "block"),					     header.dbuf.devmajor,					     header.dbuf.devminor);			do_chown(file);		}		else 		{			string_print(NIL_PTR,				     "cannot make %s special file major %s minor %s: %s\n",				      (header.dbuf.typeflag == '3' ?				       "character" : "block"),					     header.dbuf.devmajor,					     header.dbuf.devminor,					     strerror(errno));		}		return;	}      case '2':			/* symbolic link */#ifdef HAVE_SYMLINK	delete(file);	if (symlink(header.member.m_link, file) < 0)		string_print(NIL_PTR, "Cannot make symbolic link %s to %s: %s\n",			     header.member.m_link, file, strerror(errno));	else if (verbose_flag)		string_print(NIL_PTR, "Symbolic link %s to %s\n",			     header.member.m_link, file);	return;#endif      case '7':			/* contiguous file -- what is this (KS) */	print("Not implemented file type\n");	return;			/* not implemented, but break out */#ifdef HAVE_FIFO      case '6':			/* fifo */	delete(file);	if (mkfifo(file, 0) == 0) {	/* is chmod'ed in do_chown */		do_chown(file);		verb_print("made fifo", file);	} else		string_print(NIL_PTR, "Can't make fifo %s: %s\n",			file, strerror(errno));	return;#endif  }  /* Create regular file.  If failure, try to make missing directories. */  if ((fd = creat(file, 0600)) < 0) {	pd1 = file;	while ((pd2 = index(pd1, '/')) > (char *) 0) {		*pd2 = '\0';		if (access(file, 1) < 0)			if (mkdir(file, 0777) < 0) {				string_print(NIL_PTR, "Cannot mkdir %s: %s\n",					file, strerror(errno));				return;			} else				string_print(NIL_PTR, "Made directory %s\n", file);		*pd2 = '/';		pd1 = ++pd2;	}	if ((fd = creat(file, 0600)) < 0) {		string_print(NIL_PTR, "Cannot create %s: %s\n",			file, strerror(errno));		return;	}  }  copy(file, tar_fd, fd, convert(header.member.m_size, LONG_TYPE));  (void) close(fd);  do_chown(file);}void delete(file)char *file;{  /* remove a file or an empty directory */  struct stat stbuf;  if (stat(file, &stbuf) < 0) return;  if (S_ISDIR(stbuf.st_mode)) (void) rmdir(file); else (void) unlink(file);  /* leave error reporting to the create following soon. */}void do_chown(file)char *file;{  int uid = -1, gid = -1;	/* these are illegal ??? -- KS */  if (!chown_flag) {		/* set correct owner and group  -Dal */	if (header.dbuf.magic[TMAGLEN] == ' ')		header.dbuf.magic[TMAGLEN] = '\0';	/* some tars out there							 * ... */	if (strncmp(TMAGIC, header.dbuf.magic, (size_t) TMAGLEN)) {		struct passwd *pwd;		struct group *grp;		pwd = getpwnam(header.dbuf.uname);		if (pwd != NULL) uid = pwd->pw_uid;		grp = getgrnam(header.dbuf.gname);		if (grp != NULL) gid = grp->gr_gid;	}	if (uid == -1) uid = (int) convert(header.member.m_uid, INT_TYPE);	if (gid == -1) gid = (int) convert(header.member.m_gid, INT_TYPE);	chown(file, uid, gid);  }  chmod(file, u_mask & (int) convert(header.member.m_mode, INT_TYPE));

⌨️ 快捷键说明

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