[comp.os.minix] update of POSIX compatible tar

n62@nikhefh.nikhef.nl (Klamer Schutte) (10/18/89)

Here is a new version of tar. The difference with the version posted
22 september is a lot of bugs. 
Needed besides this posting:
	getcwd.c	Posted with the previous posting of tar (22/9)
	directory(3)	Posted several times. When you don't have them
			undefine DIRECT_3.

This is not posted as cdiffs to the previous posting; this posting is only 
5 kbytes bigger so i think this will save others (that's you) a lot of trouble.

Klamer. (.signature at end).
------------------------------------ cut here -------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	tar.c
#	tar.h
# This archive created: Wed Oct 18 15:15:22 1989
export PATH; PATH=/bin:$PATH
echo shar: extracting "'tar.c'" '(21445 characters)'
if test -f 'tar.c'
then
	echo shar: will not over-write existing file "'tar.c'"
else
sed 's/^X//' << \SHAR_EOF > 'tar.c'
X/* tar - tape archiver			Author: Michiel Huisjes */
X
X/* Usage: tar [cxt][vo][F][f] tapefile [files]
X *
X * attempt to make tar to conform to POSIX 1003.1
X * disclaimer: based on an old (1986) POSIX draft.
X * Klamer Schutte, 20/9/89
X *
X * Changes:
X *  Changed to handle the original minix-tar format.	KS 22/9/89
X *  Changed to handle BSD4.3 tar format.		KS 22/9/89
X *  Conform to current umask if not super-user.		KS 22/9/89
X *  Update usage message to show f option		KS 22/9/89
X *
X *
X1)	tar will back itself up, should check archive inode num(&dev) and
X		then check the target inode number. In verbose mode, issue
X		warning, in all cases ignore target.
X		marks@mgse	Mon Sep 25 10:38:58 CDT 1989
X	added global varaibles, made changes to main() and add_file();
X		maks@mgse Mon Sep 25 12:09:20 CDT 1989
X
X2)	tar will not notice that a file has changed size while it was being
X		backed up. should issue warning.
X		marks@mgse	Mon Sep 25 10:38:58 CDT 1989
X
X3)	the 'f' option was not documented in usage[].
X		marks@mgse	Mon Sep 25 12:03:20 CDT 1989
X	changed both usage[] defines. Why are there two (one is commented out)?
X	( deleted by me (was done twice) -- KS, 2/10/89 )
X *
X *  changed stat on tar_fd to an fstat				KS 2/10/89
X *  deleted mkfifo() code -- belongs in libc.a			KS 2/10/89
X *  made ar_dev default to -1 : an illegal device		KS 2/10/89
X *  made impossible to chown if normal user			KS 2/10/89
X *  if names in owner fields not known use numirical values	KS 2/10/89
X *  creat with mask 666 -- use umask if to liberal		KS 2/10/89
X *  allow to make directories as ../directory			KS 2/10/89
X *  allow tmagic field to end with a space (instead of \0)	KS 2/10/89
X *  correct usage of tmagic field 				KS 3/10/89
X *  made mkdir() to return a value if directory == "."  	KS 3/10/89
X *  made lint complains less (On a BSD 4.3 system)		KS 3/10/89
X *  use of directory(3) routines				KS 3/10/89
X *  deleted use of d_namlen selector of struct dirent		KS 18/10/89
X *
X * Bugs:
X *  verbose mode is not reporting consistent
X *  code needs cleanup
X *  prefix field is not used
X *  timestamp of a directory will not be correct if there are files to be
X *  unpacked in the directory
X *	(add you favorite bug here (or two (or three (or ...))))
X*/
X
X#include <stdio.h>	/* need NULL */
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <pwd.h>
X#include <grp.h>
X#include "tar.h"
X
X#define	POSIX_COMP	/* POSIX compatible */
X#define DIRECT_3	/* use directory(3) routines */
X
X#ifdef DIRECT_3
X#ifndef BSD
X/* To all minix users: i am sorry, developed this piece of code on a 
X * BSD system. KS 18/10/89 */
X#include <dirent.h>
X#define	direct	dirent	/* stupid BSD non-POSIX compatible name! */
X#else	/* BSD */
X#include <sys/dir.h>
X#include <dir.h>
X#endif	/* BSD */
X#endif	/* DIRECT_3 */
X
X#ifdef S_IFIFO
X#define	HAVE_FIFO	/* have incorporated Simon Pooles' changes */
X#endif
X
Xtypedef char BOOL;
X#define TRUE	1
X#define FALSE	0
X
X#define HEADER_SIZE	TBLOCK
X#define NAME_SIZE	NAMSIZ
X/* #define BLOCK_BOUNDARY	 20 -- not in POSIX ! */
X
Xtypedef union hblock	HEADER;
X
X/* make the MINIX member names overlap to the POSIX names */
X#define	m_name		name
X#define m_mode		mode
X#define m_uid		uid
X#define m_gid		gid
X#define m_size		size
X#define	m_time		mtime
X#define	m_checksum	chksum
X#define	m_linked	typeflag
X#define	m_link		linkname
X#define	hdr_block	dummy
X#define	m		header
X#define	member		dbuf
X
X#if 0	/* original structure -- see tar.h for new structure */
Xtypedef union {
X  char hdr_block[HEADER_SIZE];
X  struct m {
X	char m_name[NAME_SIZE];
X	char m_mode[8];
X	char m_uid[8];
X	char m_gid[8];
X	char m_size[12];
X	char m_time[12];
X	char m_checksum[8];
X	char m_linked;
X	char m_link[NAME_SIZE];
X  } member;
X} HEADER;
X#endif
X
X/* structure used to note links */
Xstruct link
X{	
X	ino_t		ino;
X	dev_t		dev;
X	char		name[NAMSIZ];
X	struct link	*next;
X}	*link_top = NULL;
X
XHEADER header;
X
X#define INT_TYPE	(sizeof(header.member.m_uid))
X#define LONG_TYPE	(sizeof(header.member.m_size))
X
X#define MKDIR		"/bin/mkdir"
X
X#define NIL_HEADER	((HEADER *) 0)
X#define NIL_PTR		((char *) 0)
X#define BLOCK_SIZE	TBLOCK
X
X#define flush()		print(NIL_PTR)
X
XBOOL show_fl, creat_fl, ext_fl;
X
Xint tar_fd;
X/* char usage[] = "Usage: tar [cxt] tarfile [files]."; */
Xchar usage[] = "Usage: tar [cxt][vo][F][f] tarfile [files].";
Xchar io_buffer[BLOCK_SIZE];
Xchar path[NAME_SIZE];
Xchar pathname[NAME_SIZE];
Xint force_flag = 0;
X#ifdef ORIGINAL_DEFAULTS
Xint chown_flag = 1;
Xint verbose_flag = 1;
X#else
Xint chown_flag = 0;
Xint verbose_flag = 0;
X#endif
X
X/* make sure we don't tar ourselves. marks@mgse Mon Sep 25 12:06:28 CDT 1989 */
Xino_t	ar_inode;				/* archive inode number	*/
Xdev_t	ar_dev;					/* archive device number */
X
Xint total_blocks;
Xint u_mask;			/* one's complement of current umask */
X
Xlong convert();
X
X#define block_size()	(int) ((convert(header.member.m_size, LONG_TYPE) \
X			+ (long) BLOCK_SIZE - 1) / (long) BLOCK_SIZE)
X
Xerror(s1, s2)
Xchar *s1, *s2;
X{
X  string_print(NIL_PTR, "%s %s\n", s1, s2 ? s2 : "");
X  flush();
X  exit(1);
X}
X
Xmain(argc, argv)
Xint argc;
Xregister char *argv[];
X{
X  register char *ptr;
X  struct stat st;
X  int i;
X
X  if (argc < 3)
X	error(usage, NIL_PTR);
X  
X  for (ptr = argv[1]; *ptr; ptr++) {
X	switch (*ptr) {
X		case 'c' :
X			creat_fl = TRUE;
X			break;
X		case 'x' :
X			ext_fl = TRUE;
X			break;
X		case 't' :
X			show_fl = TRUE;
X			break;
X		case 'v' :			/* verbose output  -Dal */
X			verbose_flag = !verbose_flag;
X			break;
X		case 'o' :			/* chown/chgrp files  -Dal */
X			chown_flag = TRUE;
X			break;
X		case 'F' :			/* IGNORE ERRORS  -Dal */
X			force_flag = TRUE;
X			break;
X		case 'f':			/* standard U*IX usage -KS */
X			break;
X		default :
X			error(usage, NIL_PTR);
X	}
X  }
X
X  if (creat_fl + ext_fl + show_fl != 1) 
X	error(usage, NIL_PTR);
X  
X  if (strcmp(argv[2], "-") == 0)	/* only - means stdin/stdout - KS */
X	tar_fd = creat_fl ? 1 : 0;	/* '-' means used stdin/stdout  -Dal */
X  else
X	tar_fd = creat_fl ? creat(argv[2], 0666) : open(argv[2], 0);
X
X  if (tar_fd < 0)
X	error("Cannot open ", argv[2]);
X
X  if (geteuid())			/* check if super-user */
X  {	int	save_umask;
X	save_umask = umask( 0 );
X	u_mask = ~ save_umask;
X	umask( save_umask );
X	chown_flag = TRUE;	/* normal user can't chown */
X  } else
X	u_mask = 0777;	/* don't restrict if 'privileged utiliy' */
X
X  ar_dev = -1;					/* impossible device nr */
X  if (creat_fl) {
X	if (tar_fd > 1 && fstat(tar_fd, &st) < 0)
X		error("Can't stat ", argv[2]);	/* will never be here, right? */
X	else {				/* get archive inode & device	*/
X		ar_inode= st.st_ino;		/* save files inode	*/
X		ar_dev	= st.st_dev;		/* save files device	*/
X	}			/* marks@mgse Mon Sep 25 11:30:45 CDT 1989 */
X
X	for (i = 3; i < argc; i++) {
X		add_file(argv[i]);
X		path[0] = '\0';
X	}
X	adjust_boundary();
X  }
X  else
X	tarfile();
X
X  flush();
X  exit(0);
X}
X
XBOOL get_header()
X{
X  register int check;
X
X  mread(tar_fd, (char *) &header, sizeof(header));
X  if (header.member.m_name[0] == '\0')
X	return FALSE;
X
X  if (force_flag)		/* skip checksum verification  -Dal */
X	return TRUE;
X
X  check = (int) convert(header.member.m_checksum, INT_TYPE);
X  
X  if (check != checksum())
X	error("Tar: header checksum error.", NIL_PTR);
X
X  return TRUE;
X}
X
Xtarfile()
X{
X  register char *ptr;
X  register char *mem_name;
X
X  while (get_header()) {
X	mem_name = header.member.m_name;
X	if (ext_fl) {
X		if (is_dir(mem_name)) {
X			for (ptr = mem_name; *ptr; ptr++)
X				;
X			*(ptr - 1) = '\0';
X			header.dbuf.typeflag = '5';
X		}
X		extract(mem_name);
X	}
X	else  {
X		string_print(NIL_PTR, "%s%s", mem_name,
X				(verbose_flag ? " " : "\n"));
X		switch(header.dbuf.typeflag)
X		{ case '1':
X			verbose_print("linked to", header.dbuf.linkname );
X			break;
X		case '6':
X			verbose_print("","fifo");
X			break;
X		case '3':
X		case '4':
X			if (verbose_flag)
X				string_print(NIL_PTR, 
X				    "%s special file major %s minor %s\n",
X				    (header.dbuf.typeflag == '3' ?
X				    "character" : "block" ),
X				    header.dbuf.devmajor, header.dbuf.devminor );
X			break;
X		case '0':	/* official POSIX */
X		case 0:		/* also mentioned in POSIX */
X		case ' ':	/* ofetn used */
X			if (!is_dir(mem_name))
X			{
X				if (verbose_flag)
X					string_print(NIL_PTR, "%d tape blocks\n",
X							block_size());
X				skip_entry();
X				break;
X			} else /* FALL TROUGH */
X		case '5':
X			verbose_print("","directory");
X			break;
X		default:
X			string_print(NIL_PTR,"not recogised item %d\n",
X				header.dbuf.typeflag );
X		}
X	}
X	flush();
X  }
X}
X
Xskip_entry()
X{
X  register int blocks = block_size();
X
X  while (blocks--)
X	(void) read(tar_fd, io_buffer, BLOCK_SIZE);
X}
X
Xextract(file)
Xregister char *file;
X{
X  register int fd;
X
X  switch( header.dbuf.typeflag )
X  { case '1':		/* Link */
X	if (link(header.member.m_link, file) < 0)
X		string_print(NIL_PTR, "Cannot link %s to %s\n",
X						    header.member.m_link, file);
X	else if (verbose_flag)
X		string_print(NIL_PTR, "Linked %s to %s\n",
X						    header.member.m_link, file);
X	return;
X  case '5':		/* directory */
X	if (mkdir(file) == 0)
X	{	
X  		do_chown( file );
X		verbose_print("created directory", file );
X	} /* no else: mkdir will print a message if it fails */
X	return;
X  case '3':		/* character special */
X  case '4':		/* block special */
X	{	int	dmajor, dminor, mode;
X
X		dmajor = (int)convert(header.dbuf.devmajor, INT_TYPE);
X		dminor = (int)convert(header.dbuf.devminor, INT_TYPE);
X		mode = (header.dbuf.typeflag == '3' ? S_IFCHR : S_IFBLK);
X		if (mknod( file, mode, (dmajor << 8 | dminor)) == 0)
X		{
X			if (verbose_flag)
X				string_print( NIL_PTR, 
X				    "made %s special file major %s minor %s\n",
X				    (header.dbuf.typeflag == '3' ?
X					"character" : "block" ),
X				    header.dbuf.devmajor, header.dbuf.devminor );
X	  		do_chown( file );
X		}
X		return;
X	}
X  case '2':		/* symbolic link */
X  case '7':		/* contiguous file -- what is this (KS) */
X	print("Not implemented file type\n");
X	return;	/* not implemented, but break out */		
X#ifdef HAVE_FIFO
X  case '6':		/* fifo */
X	if (mkfifo(file,0) == 0)	/* is chmod'ed in do_chown */
X	{	
X  		do_chown( file );
X		verbose_print("made fifo", file );
X	}
X	else
X		string_print(NIL_PTR, "Can't make fifo %s\n", file );
X	return;
X#endif
X  }
X
X  /* security change: creat with mode 0600, chown and then chmod -- KS */
X  if ((fd = creat(file, 0600)) < 0) {
X	string_print(NIL_PTR, "Cannot create %s\n", file);
X	return;
X  }
X
X  copy(file, tar_fd, fd, convert(header.member.m_size, LONG_TYPE));
X  (void) close(fd);
X
X  do_chown( file );
X}
X
Xdo_chown( file )
Xchar	*file;
X{	int uid = -1, gid = -1;	/* these are illegal ??? -- KS */
X
X  if(!chown_flag) {		/* set correct owner and group  -Dal */
X	if (header.dbuf.magic[TMAGLEN] == ' ')
X		header.dbuf.magic[TMAGLEN] == '\0';	/* some tars out there ... */
X	if (strncmp(TMAGIC, header.dbuf.magic, TMAGLEN))
X	{	struct passwd	*pwd, *getpwnam();
X		struct group	*grp, *getgrnam();
X
X		pwd = getpwnam(header.dbuf.uname);
X		if (pwd != NULL) 
X			uid = pwd->pw_uid;
X		grp = getgrnam(header.dbuf.gname);
X		if (grp != NULL) 
X			gid = grp->gr_gid;
X	}
X	if (uid == -1)
X		uid = (int)convert(header.member.m_uid, INT_TYPE);
X	if (gid == -1)
X		gid = (int)convert(header.member.m_gid, INT_TYPE);
X	chown(file, uid, gid );  
X  }
X  chmod(file, u_mask & (int)convert(header.member.m_mode, INT_TYPE));
X
X  /* should there be a timestamp if the chown failes? -- KS */
X  timestamp(file);
X
X}
X
Xtimestamp( file )
Xchar	*file;
X{
X	time_t	times[2];
X	
X	times[0] = times[1] = (long)convert(header.dbuf.mtime, LONG_TYPE);
X	utime( file, times );
X}
X
Xcopy(file, from, to, bytes)
Xchar *file;
Xint from, to;
Xregister long bytes;
X{
X  register int rest;
X  int blocks = (int) ((bytes + (long) BLOCK_SIZE - 1) / (long) BLOCK_SIZE);
X
X  if (verbose_flag)
X	string_print(NIL_PTR, "%s, %d tape blocks\n", file, blocks);
X
X  while (blocks--) {
X	(void) read(from, io_buffer, BLOCK_SIZE);
X	rest = (bytes > (long) BLOCK_SIZE) ? BLOCK_SIZE : (int) bytes;
X	mwrite(to, io_buffer, (to == tar_fd) ? BLOCK_SIZE : rest);
X	bytes -= (long) rest;
X  }
X}
X
Xlong convert(str, type)
Xchar str[];
Xint type;
X{
X  register long ac = 0L;
X  register int i;
X
X  for (i = 0; i < type; i++) {
X	if (str[i] >= '0' && str[i] <= '7') {
X		ac <<= 3;
X		ac += (long) (str[i] - '0');
X	}
X  }
X
X  return ac;
X}
X
Xmkdir(dir_name)
Xchar *dir_name;
X{
X  register int pid, w;
X  int	ret;
X
X  /* why not allow to mkdir(../directory)? -- changed now	KS 2/10/89 */
X  if ((dir_name[0] == '.') && (dir_name[1] == '\0'))
X	return 0;
X
X  if ((pid = fork()) < 0)
X	error("Cannot fork().", NIL_PTR);
X  
X  if (pid == 0) {
X	execl(MKDIR, "mkdir", dir_name, (char *) 0);
X	error("Cannot execute mkdir.", NIL_PTR);
X  }
X
X  do {
X	w = wait(&ret);
X  } while (w != -1 && w != pid);
X  
X  return ret;
X}
X
Xchecksum()
X{
X  register char *ptr = header.member.m_checksum;
X  register int ac = 0;
X
X  while (ptr < &header.member.m_checksum[INT_TYPE])
X	*ptr++ = ' ';
X
X  ptr = header.hdr_block;
X  while (ptr < &header.hdr_block[BLOCK_SIZE])
X	ac += *ptr++;
X
X  return ac;
X}
X
Xis_dir(file)
Xregister char *file;
X{
X  while (*file++ != '\0')
X	;
X
X  return (*(file - 2) == '/');
X}
X
X
Xchar *path_name(file)
Xregister char *file;
X{
X
X  string_print(pathname, "%s%s", path, file);
X  return pathname;
X}
X
Xadd_path(name)
Xregister char *name;
X{
X  register char *path_ptr = path;
X
X  while (*path_ptr)
X	path_ptr++;
X  
X  if (name == NIL_PTR) {
X	while (*path_ptr-- != '/')
X		;
X	while (*path_ptr != '/' && path_ptr != path)
X		path_ptr--;
X	if (*path_ptr == '/')
X		path_ptr++;
X	*path_ptr = '\0';
X  }
X  else {
X	while (*name) {
X		if (path_ptr == &path[NAME_SIZE])
X			error("Pathname too long", NIL_PTR);
X		*path_ptr++ = *name++;
X	}
X	*path_ptr++ = '/';
X	*path_ptr = '\0';
X  }
X}
X
X/*
X *	add a file to the archive
X*/
Xadd_file(file)
Xregister char *file;
X{
X  struct stat st;
X#ifdef DIRECT_3
X  struct direct dir;
X#endif
X  register int fd = -1;
X  char namebuf[16];	/* -Dal */
X  char	cwd[129];	/* -KS */
X  char	*getcwd();		/* marks@mgse Mon Sep 25 10:06:08 CDT 1989 */
X
X  if (stat(file, &st) < 0) {
X	string_print(NIL_PTR, "Cannot find %s\n", file);
X	return;
X  }
X
X  if (st.st_dev == ar_dev && st.st_ino == ar_inode) {
X	string_print(NIL_PTR, "Cannot tar current archive file (%s)\n", file);
X	return;
X  }				/* marks@mgse Mon Sep 25 12:06:28 CDT 1989 */
X
X  if ((fd = add_open(file,&st)) < 0) {
X	string_print(NIL_PTR, "Cannot open %s\n", file);
X	return;
X  }
X
X  make_header(path_name(file), &st);
X  switch(st.st_mode & S_IFMT)
X  { case S_IFREG:
X	header.dbuf.typeflag = '0';
X	string_print(header.member.m_checksum, "%I ", checksum());
X	mwrite(tar_fd, (char *) &header, sizeof(header));
X	copy(path_name(file), fd, tar_fd, (long)st.st_size);
X	break;
X  case S_IFDIR:
X	header.dbuf.typeflag = '5';
X	string_print(header.member.m_checksum, "%I ", checksum());
X	mwrite(tar_fd, (char *) &header, sizeof(header));
X	if (NULL == getcwd( cwd, 129 ))
X		string_print(NIL_PTR, "Error: cannot getcwd()\n" );
X	else if (chdir(file) < 0)
X		string_print(NIL_PTR, "Cannot chdir to %s\n", file);
X	else {
X		is_added( &st, file );
X		verbose_print("read directory", file );
X		add_path(file);
X#ifdef	DIRECT_3
X		{	DIR	*dirp;
X			struct direct *dp;
X
X			dirp = opendir( "." );
X			while( NULL != (dp = readdir(dirp)) )
X				if ((strcmp(dp->d_name, ".") == 0) || 
X				    (strcmp(dp->d_name, "..") == 0))
X					continue;
X				else
X				{	strcpy(namebuf, dp->d_name);
X					add_file( namebuf );
X				}
X			closedir( dirp );
X		}
X#else
X		mread(fd, &dir, sizeof(dir));		/* "." */
X		mread(fd, &dir, sizeof(dir));		/* ".." */
X		while (read(fd, &dir, sizeof(dir)) == sizeof(dir))
X			if (dir.d_ino) {
X				strncpy(namebuf, dir.d_name, 14);
X				namebuf[14] = '\0';
X				add_file(namebuf);
X			}
X#endif
X		chdir(cwd);
X		add_path(NIL_PTR);
X		*file = 0;
X	}
X	break;
X#ifdef HAVE_FIFO
X  case S_IFIFO:
X	header.dbuf.typeflag = '6';
X	verbose_print("read fifo", file );
X	string_print(header.member.m_checksum, "%I ", checksum());
X	mwrite(tar_fd, (char *) &header, sizeof(header));
X	break;
X#endif
X  case S_IFBLK:
X	header.dbuf.typeflag = '4';
X	if (verbose_flag)
X		string_print(NIL_PTR, 
X			"read block device %s major %s minor %s\n",
X			file, header.dbuf.devmajor, header.dbuf.devminor );
X	string_print(header.member.m_checksum, "%I ", checksum());
X	mwrite(tar_fd, (char *) &header, sizeof(header));
X	break;
X  case S_IFCHR:
X	header.dbuf.typeflag = '3';
X	if (verbose_flag)
X		string_print(NIL_PTR, 
X			"read character device %s major %s minor %s\n",
X			file, header.dbuf.devmajor, header.dbuf.devminor );
X	string_print(header.member.m_checksum, "%I ", checksum());
X	mwrite(tar_fd, (char *) &header, sizeof(header));
X	break;
X  case -1 & S_IFMT:
X	header.dbuf.typeflag = '1';
X	if (verbose_flag)
X		string_print(NIL_PTR, "linked %s to %s\n", 
X			header.dbuf.linkname, file );
X	string_print(header.member.m_checksum, "%I ", checksum());
X	mwrite(tar_fd, (char *) &header, sizeof(header));
X	break;
X  default:
X	string_print(NIL_PTR, "Tar: %s unknown file type. Not added.\n", file);
X	*file = 0;
X  }
X
X  flush();
X  is_added( &st, file );
X  add_close(fd);
X}
X
Xverbose_print( s1, s2 )
Xchar	*s1, *s2;
X{
X	if (verbose_flag)
X		string_print(NIL_PTR, "%s: %s\n", s1, s2 );
X}
X
Xadd_close( fd )
Xint	fd;
X{
X	if (fd != 0)
X		close( fd );
X}
X
X/*
X *	open file 'file' to be added to archive, return file descriptor
X*/
Xadd_open( file, st )
Xchar	*file;
Xstruct stat	*st;
X{
X	int	fd;
X	if (((st->st_mode & S_IFMT) != S_IFREG) && 
X		((st->st_mode & S_IFMT) != S_IFDIR))
X		return 0;
X	fd = open(file, 0);
X	return fd;
X}
X	
Xmake_header(file, st)
Xchar *file;
Xregister struct stat *st;
X{
X  register char *ptr = header.member.m_name;
X  char 	*is_linked();
X  struct passwd	*pwd, *getpwuid();
X  struct group	*grp, *getgrgid();
X
X  clear_header();
X
X  while (*ptr++ = *file++)
X	;
X
X  if ((st->st_mode & S_IFMT) == S_IFDIR) {	/* fixed test  -Dal */
X	*(ptr - 1) = '/';
X  }
X  
X  string_print(header.member.m_mode, "%I ", st->st_mode & 07777);
X  string_print(header.member.m_uid, "%I ", st->st_uid);
X  string_print(header.member.m_gid, "%I ", st->st_gid);
X  if ((st->st_mode & S_IFMT) == S_IFREG)
X  	string_print(header.member.m_size, "%L ", st->st_size);
X  else
X	strncpy(header.dbuf.size, "0", TSIZLEN );
X  string_print(header.member.m_time, "%L ", st->st_mtime);
X  /*  header.member.m_linked = ''; */
X  if ((ptr = is_linked(st)) != NULL)
X  {	strncpy( header.dbuf.linkname, ptr, NAMSIZ );
X	st->st_mode = -1;	/* invalid value */
X  }
X  strncpy(header.dbuf.magic, TMAGIC, TMAGLEN );
X  header.dbuf.version[0] = 0;
X  header.dbuf.version[1] = 0;
X  pwd = getpwuid( st->st_uid );
X  strncpy(header.dbuf.uname, (pwd!=NULL?pwd->pw_name:"nobody"), TUNMLEN );
X  grp = getgrgid( st->st_gid );
X  strncpy(header.dbuf.gname, (grp!=NULL?grp->gr_name:"nobody"), TGNMLEN );
X  if (st->st_mode & (S_IFBLK | S_IFCHR))
X  {	string_print(header.dbuf.devmajor, "%I ", (st->st_rdev >> 8));
X  	string_print(header.dbuf.devminor, "%I ", (st->st_rdev & 0xFF));
X  }
X  header.dbuf.prefix[0] = 0;
X}
X
Xis_added( st, file )
Xstruct stat	*st;
Xchar	*file;
X{
X	struct link	*new;
X	char	*malloc();
X
X	if (*file == 0)
X		return;	
X	new = (struct link *) malloc(sizeof(struct link));
X	if (new == NULL)
X        {	print("Out of memory\n");
X		return;
X	}
X	new->next = link_top;
X	new->dev = st->st_dev;
X	new->ino = st->st_ino;
X	strncpy( new->name, path_name(file), NAMSIZ );
X	link_top = new;
X}
X
Xchar * is_linked( st )
Xstruct stat	*st;
X{
X	struct link *cur = link_top;
X
X	while( cur != NULL )
X		if ((cur->dev == st->st_dev) && (cur->ino == st->st_ino))
X			return cur->name;
X		else
X			cur = cur->next;
X	return NULL;
X}
X
Xclear_header()
X{
X  register char *ptr = header.hdr_block;
X
X  while (ptr < &header.hdr_block[BLOCK_SIZE])
X	*ptr++ = '\0';
X}
X
Xadjust_boundary()
X{
X  clear_header();
X  mwrite(tar_fd, (char *) &header, sizeof(header));
X#ifndef POSIX_COMP
X  while (total_blocks++ < BLOCK_BOUNDARY)
X	mwrite(tar_fd, (char *) &header, sizeof(header));
X#else
X  mwrite(tar_fd, (char *) &header, sizeof(header));
X#endif
X  (void) close(tar_fd);
X}
X
Xmread(fd, address, bytes)
Xint fd, bytes;
Xchar *address;
X{
X  if (read(fd, address, bytes) != bytes)
X	error("Tar: read error.", NIL_PTR);
X}
X
Xmwrite(fd, address, bytes)
Xint fd, bytes;
Xchar *address;
X{
X  if (write(fd, address, bytes) != bytes)
X	error("Tar: write error.", NIL_PTR);
X
X  total_blocks++;
X}
X
Xchar output[BLOCK_SIZE];
Xprint(str)		/* changed to use stderr rather than stdout  -Dal */
Xregister char *str;
X{
X  static int index = 0;
X
X  if (str == NIL_PTR) {
X	write(2, output, index);
X	index = 0;
X	return;
X  }
X
X  while (*str) {
X	output[index++] = *str++;
X	if (index == BLOCK_SIZE) {
X		write(2, output, BLOCK_SIZE);
X		index = 0;
X	}
X  }
X}
X
Xchar *num_out(number)
Xregister long number;
X{
X  static char num_buf[12];
X  register int i;
X
X  for (i = 11; i--; ) {
X	num_buf[i] = (number & 07) + '0';
X	number >>= 3;
X  }
X
X  return num_buf;
X}
X
X/*VARARGS2*/
Xstring_print(buffer, fmt, args)
Xchar *buffer;
Xregister char *fmt;
Xint args;
X{
X  register char *buf_ptr;
X  char *scan_ptr;
X  char buf[NAME_SIZE];
X  char *argptr = (char *)&args;
X  BOOL pr_fl, i;
X
X  if (pr_fl = (buffer == NIL_PTR))
X	buffer = buf;
X
X  buf_ptr = buffer;
X  while (*fmt) {
X	if (*fmt == '%') {
X		fmt++;
X		switch (*fmt++) {
X			case 's': 
X				scan_ptr = *((char **)argptr);
X				argptr += sizeof(char *);
X				break;
X			case 'I': 
X				scan_ptr = num_out((long) *((int *)argptr));
X				argptr += sizeof(int);
X				for (i = 0; i < 5; i++)
X					scan_ptr++;
X				break;
X			case 'L': 
X				scan_ptr = num_out(*((long *) argptr));
X				argptr += sizeof(long);
X				break;
X			case 'd' :
X				scan_ptr = num_out((long) *((int *)argptr));
X				argptr += sizeof(int);
X				while (*scan_ptr == '0')
X					scan_ptr++;
X				scan_ptr--;
X				break;
X			default: 
X				scan_ptr = "";
X		}
X		while (*buf_ptr++ = *scan_ptr++)
X			;
X		buf_ptr--;
X	}
X	else
X		*buf_ptr++ = *fmt++;
X  }
X  *buf_ptr = '\0';
X
X  if (pr_fl)
X	print(buffer);
X}
X
SHAR_EOF
if test 21445 -ne "`wc -c < 'tar.c'`"
then
	echo shar: error transmitting "'tar.c'" '(should have been 21445 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'tar.h'" '(1390 characters)'
if test -f 'tar.h'
then
	echo shar: will not over-write existing file "'tar.h'"
else
sed 's/^X//' << \SHAR_EOF > 'tar.h'
X/* 
X * tar.h -- Standard Archive Format
X * USTAR - Uniform Standard Tape Archive
X *
X * As published in POSIX standard IEEE Std 1003.1 (draft 1986)
X *
X * Klamer Schutte 3/'89
X */
X
X#define TBLOCK 		512
X#define NAMSIZ		100
X#define PFXSIZ		155
X
X#define TMODLEN 	8
X#define TUIDLEN		8
X#define TGIDLEN		8
X#define TSIZLEN		12
X#define TMTMLEN		12
X#define TCKSLEN		8
X
X#define TMAGIC		"ustar"
X#define TMAGLEN		6
X#define TVERSION	"00"
X#define TVERSLEN	2
X#define TUNMLEN		32
X#define TGNMLEN		32
X#define TDEVLEN		8
X
X#define REGTYPE		'0'
X#define AREGTYPE	'\0'
X#define LNKTYPE		'1'
X#define SYMTYPE		'2'
X#define CHRTYPE		'3'
X#define BLKTYPE		'4'
X#define DIRTYPE		'5'
X#define FIFOTYPE	'6'
X#define CONTTYPE	'7'
X
X#define TSUID		04000
X#define TSGID		02000
X#define TSVTX		01000
X
X#define TUREAD		00400
X#define TUWRITE		00200
X#define TUEXEC		00100
X#define TGREAD		00040
X#define TGWRITE		00020
X#define TGEXEC		00010
X#define TOREAD		00004
X#define TOWRITE		00002
X#define TOEXEC		00001
X
Xunion hblock {
X	char	dummy[TBLOCK];
X	struct header {
X		char	name[NAMSIZ];
X		char	mode[TMODLEN];
X		char	uid[TUIDLEN];
X		char	gid[TGIDLEN];
X		char	size[TSIZLEN];
X		char	mtime[TMTMLEN];
X		char	chksum[TCKSLEN];
X		char	typeflag;
X		char	linkname[NAMSIZ];
X		char	magic[TMAGLEN];
X		char	version[TVERSLEN];
X		char	uname[TUNMLEN];
X		char	gname[TGNMLEN];
X		char	devmajor[TDEVLEN];
X		char	devminor[TDEVLEN];
X		char	prefix[PFXSIZ];
X	} dbuf;
X};
SHAR_EOF
if test 1390 -ne "`wc -c < 'tar.h'`"
then
	echo shar: error transmitting "'tar.h'" '(should have been 1390 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0
-- 
_____________________Yes, mail address changed again :-(________________________
Klamer Schutte        mcvax!nikhefh!{n62,Schutte}        {Schutte,n62}@nikhef.nl