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

📄 create.c

📁 unix 下tar 执行程序的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Create a tar archive.
   Copyright (C) 1988 Free Software Foundation

This file is part of GNU Tar.

GNU Tar is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

GNU Tar is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Tar; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */

/*
 * Create a tar archive.
 *
 * Written 25 Aug 1985 by John Gilmore, ihnp4!hoptoad!gnu.
 *
 * @(#)create.c 1.36 11/6/87 - gnu
 */
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>

#ifndef V7
#include <fcntl.h>
#endif

#ifndef	__MSDOS__
#include <sys/file.h>
#include <sys/param.h>		/* for MAXPATHLEN */
#include <pwd.h>
#include <grp.h>
#endif

#ifdef BSD42
#include <sys/dir.h>
#else
#ifdef __MSDOS__
#include "msd_dir.h"
#else
#ifdef USG
#ifdef NDIR
#include <ndir.h>
#else
#include <dirent.h>
#endif
#ifndef DIRECT
#define direct dirent
#endif
#define DP_NAMELEN(x) strlen((x)->d_name)
#else
/*
 * FIXME: On other systems there is no standard place for the header file
 * for the portable directory access routines.  Change the #include line
 * below to bring it in from wherever it is.
 */
#include "ndir.h"
#endif
#endif
#endif

#ifndef DP_NAMELEN
#define DP_NAMELEN(x)	(x)->d_namlen
#endif

#ifdef USG
#include <sys/sysmacros.h>	/* major() and minor() defined here */
#endif

/*
 * V7 doesn't have a #define for this.
 */
#ifndef O_RDONLY
#define	O_RDONLY	0
#endif

/*
 * Most people don't have a #define for this.
 */
#ifndef	O_BINARY
#define	O_BINARY	0
#endif

#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif

#include "tar.h"
#include "port.h"

extern struct stat hstat;		/* Stat struct corresponding */

#ifndef __MSDOS__
extern dev_t ar_dev;
extern ino_t ar_ino;
#endif

/* JF */
extern struct name *gnu_list_name;

/*
 * If there are no symbolic links, there is no lstat().  Use stat().
 */
#ifndef S_IFLNK
#define lstat stat
#endif

extern char	*malloc();
extern char	*strcpy();
extern char	*strncpy();
extern void	bzero();
extern void	bcopy();
extern int	errno;

extern void print_header();

union record *start_header();
void finish_header();
void finduname();
void findgname();
char *name_next();
void to_oct();
void dump_file();


/* This code moved from tar.h since create.c is the only file that cares
   about 'struct link's.  This means that other files might not have to
   include sys/types.h any more.
 */

struct link {
	struct link	*next;
	dev_t		dev;
	ino_t		ino;
	short		linkcount;
	char		name[1];
};

struct link	*linklist;	/* Points to first link in list */

static nolinks;			/* Gets set if we run out of RAM */

/*
 * "Scratch" space to store the information about a sparse file before
 * writing the info into the header or extended header
 */
/* struct sp_array	 *sparsearray;*/

/* number of elts storable in the sparsearray */
/*int 	sparse_array_size = 10;*/

void
create_archive()
{
	register char	*p;
	char *name_from_list();

	open_archive(0);		/* Open for writing */

	if(f_gnudump) {
		char buf[MAXNAMLEN],*q,*bufp;

		collect_and_sort_names();

		while(p=name_from_list())
			dump_file(p,-1);
		/* if(!f_dironly) { */
			blank_name_list();
			while(p=name_from_list()) {
				strcpy(buf,p);
				if(p[strlen(p)-1]!='/')
					strcat(buf,"/");
				bufp=buf+strlen(buf);
				for(q=gnu_list_name->dir_contents;q && *q;q+=strlen(q)+1) {
					if(*q=='Y') {
						strcpy(bufp,q+1);
						dump_file(buf,-1);
					}
				}
			}
		/* } */
	
	} else {
		p = name_next(1);
		if(!p)
			dump_file(".", -1);
		else {
			do dump_file(p, -1);
			while (p = name_next(1));
		}
	}

	write_mangled();
	write_eot();
	close_archive();
	if(f_gnudump)
		write_dir_file();
	name_close();
}

/*
 * Dump a single file.  If it's a directory, recurse.
 * Result is 1 for success, 0 for failure.
 * Sets global "hstat" to stat() output for this file.
 */
void
dump_file (p, curdev)
	char	*p;			/* File name to dump */
	int	curdev;			/* Device our parent dir was on */
{
	union record	*header;
	char type;
	extern char *save_name;		/* JF for multi-volume support */
	extern long save_totsize;
	extern long save_sizeleft;
	union record	*exhdr;
	char save_linkflag;
	extern time_t new_time;
	int sparse_ind = 0;


	if(f_confirm && !confirm("add",p))
		return;

	/*
	 * Use stat if following (rather than dumping) 4.2BSD's
	 * symbolic links.  Otherwise, use lstat (which, on non-4.2
	 * systems, is #define'd to stat anyway.
	 */
#ifdef AIX
	if (0 != f_follow_links ?
	    statx (p, &hstat, STATSIZE, STX_HIDDEN):
	    statx (p, &hstat, STATSIZE, STX_HIDDEN|STX_LINK))
#else
	if (0 != f_follow_links? stat(p, &hstat): lstat(p, &hstat))
#endif /* AIX */
	{
badperror:
		msg_perror("can't add file %s",p);
badfile:
		errors++;
		return;
	}

#ifdef AIX
	if (S_ISHIDDEN (hstat.st_mode)) {
		char *new = (char *)allocate (strlen (p) + 2);
		if (new) {
			strcpy (new, p);
			strcat (new, "@");
			p = new;
		}
	}
#endif /* AIX */

	/* See if we only want new files, and check if this one is too old to
	   put in the archive. */
	if(   f_new_files
	   && !f_gnudump
 	   && new_time>hstat.st_mtime
 	   && (hstat.st_mode&S_IFMT)!=S_IFDIR
 	   && (f_new_files>1 || new_time>hstat.st_ctime)) {
		if(curdev<0) {
			msg("%s: is unchanged; not dumped",p);
		}
		return;
	}

#ifndef __MSDOS__
	/* See if we are trying to dump the archive */
	if(ar_dev && hstat.st_dev==ar_dev && hstat.st_ino==ar_ino) {
		msg("%s is the archive; not dumped",p);
		return;
	}
#endif
	/*
	 * Check for multiple links.
	 *
	 * We maintain a list of all such files that we've written so
	 * far.  Any time we see another, we check the list and
	 * avoid dumping the data again if we've done it once already.
	 */
	if (hstat.st_nlink > 1) switch (hstat.st_mode & S_IFMT) {
		register struct link	*lp;

	case S_IFREG:			/* Regular file */
#ifdef S_IFCTG
	case S_IFCTG:			/* Contigous file */
#endif
#ifdef S_IFCHR
	case S_IFCHR:			/* Character special file */
#endif

#ifdef S_IFBLK
	case S_IFBLK:			/* Block     special file */
#endif

#ifdef S_IFIFO
	case S_IFIFO:			/* Fifo      special file */
#endif

		/* First quick and dirty.  Hashing, etc later FIXME */
		for (lp = linklist; lp; lp = lp->next) {
			if (lp->ino == hstat.st_ino &&
			    lp->dev == hstat.st_dev) {
				char *link_name = lp->name;

				/* We found a link. */
				hstat.st_size = 0;
				header = start_header(p, &hstat);
				if (header == NULL) goto badfile;
				while(!f_absolute_paths && *link_name == '/') {
					static int link_warn = 0;

					if (!link_warn) {
						msg("Removing leading / from absolute links");
						link_warn++;
					}
					link_name++;
				}
  				strncpy(header->header.linkname,
					link_name,NAMSIZ);
				if(header->header.linkname[NAMSIZ-1]) {
					char *mangled;
					extern char *find_mangled();

					mangled=find_mangled(link_name);
					msg("%s: link name too long: mangled to %s",link_name,mangled);
					strncpy(header->header.linkname,mangled,NAMSIZ);
				}
				header->header.linkflag = LF_LINK;
				finish_header(header);
		/* FIXME: Maybe remove from list after all links found? */
				return;		/* We dumped it */
			}
		}

		/* Not found.  Add it to the list of possible links. */
		lp = (struct link *)malloc((unsigned)(sizeof(struct link)+strlen(p)));
		if (!lp) {
			if (!nolinks) {
				msg(
	"no memory for links, they will be dumped as separate files");
				nolinks++;
			}
		}
		lp->ino = hstat.st_ino;
		lp->dev = hstat.st_dev;
		strcpy(lp->name, p);
		lp->next = linklist;
		linklist = lp;
	}

	/*
	 * This is not a link to a previously dumped file, so dump it.
	 */
	switch (hstat.st_mode & S_IFMT) {

	case S_IFREG:			/* Regular file */
#ifdef S_IFCTG
	case S_IFCTG:			/* Contiguous file */
#endif
	{
		int	f;		/* File descriptor */
		long	bufsize, count;
		long	sizeleft;
		register union record 	*start;
		int 	header_moved;
		char	isextended = 0;
		int 	upperbound;
		int	end_nulls = 0;
		
		header_moved = 0;

#ifdef BSD42
		if (f_sparse_files) {
		/*
	 	 * JK - This is the test for sparseness: whether the
		 * "size" of the file matches the number of blocks
		 * allocated for it.  If there is a smaller number
		 * of blocks that would be necessary to accommodate
		 * a file of this size, we have a sparse file, i.e.,
		 * at least one of those records in the file is just
		 * a useless hole.
		 */
#ifdef hpux	/* Nice of HPUX to gratuitiously change it, huh?  - mib */
		        if (hstat.st_size - (hstat.st_blocks * 1024) > 1024 ) {
#else
			if (hstat.st_size - (hstat.st_blocks * RECORDSIZE) > RECORDSIZE) {
#endif
				int	filesize = hstat.st_size;
				register int i;
				
				header = start_header(p, &hstat);
				if (header == NULL)
					goto badfile;
				header->header.linkflag = LF_SPARSE;
				header_moved++;
				
			/*
			 * Call the routine that figures out the
			 * layout of the sparse file in question.
			 * UPPERBOUND is the index of the last
			 * element of the "sparsearray," i.e.,
			 * the number of elements it needed to
			 * describe the file.
			 */
				 
				upperbound = deal_with_sparse(p, header);
 						
			/* 
			 * See if we'll need an extended header
			 * later
			 */
				if (upperbound > SPARSE_IN_HDR-1)
		 			header->header.isextended++;
			/*
			 * We store the "real" file size so
			 * we can show that in case someone wants
			 * to list the archive, i.e., tar tvf <file>.
			 * It might be kind of disconcerting if the
			 * shrunken file size was the one that showed
			 * up.
			 */
				 to_oct((long) hstat.st_size, 1+12, 
				 		header->header.realsize);
					
			/*

⌨️ 快捷键说明

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