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

📄 port.c

📁 unix 下tar 执行程序的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Supporting routines which may sometimes be missing.
   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.  */

/*
 * @(#)port.c 1.15	87/11/05	by John Gilmore, 1986
 *
 * These are routines not available in all environments.
 *
 * I know this introduces an extra level of subroutine calls and is
 * slightly slower.  Frankly, my dear, I don't give a damn.  Let the
 * Missed-Em Vee losers suffer a little.  This software is proud to
 * have been written on a BSD system.
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <errno.h>

#if	defined(__MSDOS__) || defined(USG)
#include <fcntl.h>
#else
#include <sys/file.h>
#endif

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

#ifdef USG
#include <string.h>
#else
extern size_t strlen();
#endif

extern long baserec;
/*
 * Some people (e.g. V7) don't have a #define for these.
 */
#ifndef	O_BINARY
#define	O_BINARY	0
#endif
#ifndef	O_RDONLY
#define	O_RDONLY	0
#endif
#ifndef NULL
#define NULL 0
#endif

/* JF: modified so all configuration information can appear here, instead of
   being scattered through the file.  Add all the machine-dependent #ifdefs
   here */
#undef WANT_DUMB_GET_DATE/* WANT_DUMB_GET_DATE --> get_date() */
#undef WANT_VALLOC	/* WANT_VALLOC --> valloc() */
#undef WANT_MKDIR	/* WANT_MKDIR --> mkdir() rmdir() */
#undef WANT_STRING	/* WANT_STRING --> index() bcopy() bzero() bcmp() */
#undef WANT_BZERO	/* WANT_BZERO --> bzero() bcmp() execlp() */
			/* EMUL_OPEN3 --> open3() */
#undef WANT_MKNOD	/* WANT_MKNOD --> mknod() link() chown() geteuid() */
#undef WANT_UTILS	/* WANT_UTILS --> panic() ck_*() *_buffer()
			   merge_sort() quote_copy_string() un_quote_string() */
#undef WANT_CK_PIPE	/* WANT_CK_PIPE --> ck_pipe() */
#undef WANT_GETWD	/* WANT_GETWD --> getwd() */
#undef WANT_STRSTR	/* WANT_STRSTR --> strstr() */
#undef WANT_FTRUNCATE	/* WANT_FTRUNCATE --> frtruncate() */

/* Define only ONE of these four . . . */
/* #undef DOPRNT_MSG	/* Define this one if you have _doprnt() and
			   no varargs support */
/* #undef VARARGS_MSG	/* Define this one if you have varargs.h and
			   vfprintf() */
/* #undef STDC_MSG 	/* Define this one if you are using ANSI C and
			   and have vfprintf() */
/* #undef LOSING_MSG	/* Define this one if you don't have any of the
			   above */
#ifdef USG
#define WANT_STRING
#define WANT_VALLOC

#if defined(sgi) && defined(mips)
#define WANT_GETWD
#endif

#if defined(i386)
#define WANT_FTRUNCATE
#endif

#endif

#ifdef hpux
#define WANT_VALLOC
#endif

#ifdef MINIX
#define WANT_BZERO
#endif

#ifdef __MSDOS__
char TTY_NAME[] = "con";

#define WANT_STRING
#define WANT_MKNOD
#define WANT_UTILS
#define WANT_VALLOC

#if (!defined(STDC_MSG) && !defined(DOPRNT_MSG) && !defined(VARARGS_MSG) && !defined(LOSING_MSG))
#ifdef __STDC__
#define STDC_MSG
#else
#define LOSING_MSG
#endif
#endif

#else /* not MSDOS */
char TTY_NAME[] ="/dev/tty";

#define WANT_UTILS
#define WANT_CK_PIPE
#ifndef HAVE_STRSTR
#define WANT_STRSTR
#endif

#if (!defined(STDC_MSG) && !defined(DOPRNT_MSG) && !defined(VARARGS_MSG) && !defined(LOSING_MSG))
#ifdef BSD42
/* BSD systems should do this even if __STDC__, because
   we might be using an ANSI compiler without an ANSI library. (sigh) */
#ifdef sparc
#define LOSING_MSG
#else
#define DOPRNT_MSG
#endif
#else /* not BSD */
#ifdef __STDC__
#define STDC_MSG
#else /* not ANSI C */
#define LOSING_MSG
#endif /* not ANSI C */
#endif /* not BSD */
#endif /* Need to define some form of _MSG */
#endif /* not MSDOS */

/* End of system-dependent #ifdefs */

#ifdef WANT_DUMB_GET_DATE
/* JF a get_date() routine takes a date/time/etc and turns it into a time_t */
/* This one is a quick hack I wrote in about five minutes to see if the N
   option works.  Someone should replace it with one that works */

/* This get_date takes an arg of the form mm/dd/yyyy hh:mm:ss and turns it
   into a time_t .  Its not well tested or anything. . .  */
/* In general, you should use the get_date() supplied in getdate.y */

#define OFF_FROM GMT 18000		/* Change for your time zone! */

time_t
get_date(str)
char *str;
{
	int month,day,year,hour,minute,second;
	time_t ret;
	int	n;

#define SECS_PER_YEAR (365L*SECS_PER_DAY)
#define SECS_PER_LEAP_YEAR (366L*SECS_PER_DAY)

#define SECS_PER_DAY (24L*60*60)
	static int days_per_month[2][12] = {
		31,28,31,30,31,30,31,31,30,31,30,31,
		31,29,31,30,31,30,31,31,30,31,30,31
	};

	static int days_per_year[2]={365,366};

	month=day=year=hour=minute=second=0;
	n=sscanf(str,"%d/%d/%d %d:%d:%d",&month,&day,&year,&hour,&minute,&second);
	if(n<3)
		return 0;
	if(year<100)
		year+=1900;
	if(year<1970)
		return 0;
	ret=0;

	ret+=OFF_FROM_GMT;

	for(n=1970;n<year;n++)
		if(n%4==0 && n%400!=0)
			ret+=SECS_PER_LEAP_YEAR;
		else
			ret+=SECS_PER_YEAR;

	month--;
	for(n=0;n<month;n++) {
		if(year%4==0 && year%400!=0)
			ret+=SECS_PER_DAY*days_per_month[1][n];
		else
			ret+=SECS_PER_DAY*days_per_month[0][n];
	}
	ret+=SECS_PER_DAY*(day-1);
	ret+=second+minute*60+hour*60*60;
	return ret;
}
#endif

#ifdef WANT_VALLOC
/*
 * valloc() does a malloc() on a page boundary.  On some systems,
 * this can make large block I/O more efficient.
 */
char *
valloc (size)
	unsigned size;
{
	extern char *malloc ();
	return (malloc (size));
}
#endif
/*
 *				NMKDIR.C
 *
 * Written by Robert Rother, Mariah Corporation, August 1985. 
 *
 * I wrote this out of shear disgust with myself because I couldn't
 * figure out how to do this in /bin/sh.
 *
 * If you want it, it's yours.  All I ask in return is that if you
 * figure out how to do this in a Bourne Shell script you send me
 * a copy.
 *					sdcsvax!rmr or rmr@uscd
*
* Severely hacked over by John Gilmore to make a 4.2BSD compatible
* subroutine.	11Mar86; hoptoad!gnu
*
* Modified by rmtodd@uokmax 6-28-87 -- when making an already existing dir,
* subroutine didn't return EEXIST.  It does now.
*/

/*
 * Make a directory.  Compatible with the mkdir() system call on 4.2BSD.
 */
#ifdef WANT_MKDIR
int
mkdir(dpath, dmode)
	char *dpath;
	int dmode;
{
	int cpid, status;
	struct stat statbuf;
	extern int errno;

	if (stat(dpath,&statbuf) == 0) {
		errno = EEXIST;		/* Stat worked, so it already exists */
		return -1;
	}

	/* If stat fails for a reason other than non-existence, return error */
	if (errno != ENOENT) return -1; 

	switch (cpid = fork()) {

	case -1:			/* Error in fork() */
		return(-1);		/* Errno is set already */

	case 0:				/* Child process */
		/*
		 * Cheap hack to set mode of new directory.  Since this
		 * child process is going away anyway, we zap its umask.
		 * FIXME, this won't suffice to set SUID, SGID, etc. on this
		 * directory.  Does anybody care?
		 */
		status = umask(0);	/* Get current umask */
		status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
		execl("/bin/mkdir", "mkdir", dpath, (char *)0);
		_exit(-1);		/* Can't exec /bin/mkdir */
	
	default:			/* Parent process */
		while (cpid != wait(&status)) ;	/* Wait for kid to finish */
	}

	if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
		errno = EIO;		/* We don't know why, but */
		return -1;		/* /bin/mkdir failed */
	}

	return 0;
}
int
rmdir(dpath)
	char *dpath;
{
	int cpid, status;
	struct stat statbuf;
	extern int errno;

	if (stat(dpath,&statbuf) != 0) {
		/* Stat just set errno.  We don't have to */
		return -1;
	}

	switch (cpid = fork()) {

	case -1:			/* Error in fork() */
		return(-1);		/* Errno is set already */

	case 0:				/* Child process */
		execl("/bin/rmdir", "rmdir", dpath, (char *)0);
		_exit(-1);		/* Can't exec /bin/mkdir */
	
	default:			/* Parent process */
		while (cpid != wait(&status)) ;	/* Wait for kid to finish */
	}

	if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
		errno = EIO;		/* We don't know why, but */
		return -1;		/* /bin/mkdir failed */
	}

	return 0;
}
#endif

#ifdef WANT_STRING
/*
 * Translate V7 style into Sys V style.
 */
#include <string.h>
#ifndef __MSDOS__
#include <memory.h>
#endif

char *
index (s, c)
	char *s;
	int c;
{
	return (strchr (s, c));
}

char *
rindex(s,c)
char *s;
int c;
{
	return strrchr(s,c);
}

void
bcopy (s1, s2, n)
	char *s1, *s2;
	int n;
{
	(void) memcpy (s2, s1, n);
}

void
bzero (s1, n)
	char *s1;
	int n;
{
	(void) memset(s1, 0, n);
}

int
bcmp(s1, s2, n)
	char	*s1, *s2;
	int	n;
{
	return memcmp(s1, s2, n);
}
#endif

#ifdef WANT_BZERO
/* Minix has bcopy but not bzero, and no memset.  Thanks, Andy. */
void
bzero (s1, n)
	register char *s1;
	register int n;
{
	while (n--) *s1++ = '\0';
}

/* It also has no bcmp() */
int
bcmp (s1, s2, n) 
	register char *s1,*s2;
	register int n;
{
	for ( ; n-- ; ++s1, ++s2) {
		if (*s1 != *s2) return *s1 - *s2;
	}
	return 0;
}

/*
 * Groan, Minix doesn't have execlp either!
 *
 * execlp(file,arg0,arg1...argn,(char *)NULL)
 * exec a program, automatically searching for the program through
 * all the directories on the PATH.
 *
 * This version is naive about variable argument lists, it assumes
 * a straightforward C calling sequence.  If your system has odd stacks
 * *and* doesn't have execlp, YOU get to fix it.
 */
int
execlp(filename, arg0)
	char *filename, *arg0;
{
	register char *p, *path;    
	register char *fnbuffer;
	char **argstart = &arg0;
	struct stat statbuf;
	extern char **environ;
	extern int errno;
	extern char *malloc(), *getenv(), *index();

	if ((p = getenv("PATH")) == NULL) {
		/* couldn't find path variable -- try to exec given filename */
		return execve(filename, argstart, environ);
	}

	/*
	 * make a place to build the filename.  We malloc larger than we
	 * need, but we know it will fit in this.
	 */
	fnbuffer = malloc( strlen(p) + 1 + strlen(filename) );
	if (fnbuffer == NULL) {
		errno = ENOMEM;
		return -1;
	}

	/*
	 * try each component of the path to see if the file's there
	 * and executable.
	 */
	for (path = p ; path ; path = p) {
		/* construct full path name to try */
		if ((p = index(path,':')) == NULL) {
			strcpy(fnbuffer, path);
		} else {
			strncpy(fnbuffer, path, p-path);
			fnbuffer[p-path] = '\0';
			p++;		/* Skip : for next time */
		}
		if (strlen(fnbuffer) != 0)
			strcat(fnbuffer,"/");
		strcat(fnbuffer,filename);

		/* check to see if file is there and is a normal file */
		if (stat(fnbuffer, &statbuf) < 0) {
			if (errno == ENOENT)
				continue; /* file not there,keep on looking */
			else
				goto fail; /* failed for some reason, return */
		}
		if ( (statbuf.st_mode & S_IFMT) != S_IFREG) continue;

		if (execve(fnbuffer, argstart, environ) < 0
		    && errno != ENOENT
		    && errno != ENOEXEC) {
			/* failed, for some other reason besides "file
			 * not found" or "not a.out format"
			 */
			goto fail;
		}

		/*
		 * If we got error ENOEXEC, the file is executable but is
		 * not an object file.  Try to execute it as a shell script,
		 * returning error if we can't execute /bin/sh.
		 *
		 * FIXME, this code is broken in several ways.  Shell
		 * scripts should not in general be executed by the user's
		 * SHELL variable program.  On more mature systems, the
		 * script can specify with #!/bin/whatever.  Also, this
		 * code clobbers argstart[-1] if the exec of the shell
		 * fails.
		 */
		if (errno == ENOEXEC) {
			char *shell;

			/* Try to execute command "sh arg0 arg1 ..." */
			if ((shell = getenv("SHELL")) == NULL)
				shell = "/bin/sh";
			argstart[-1] = shell;
			argstart[0] = fnbuffer;
			execve(shell, &argstart[-1], environ);
			goto fail;	/* Exec didn't work */
		}

		/* 
		 * If we succeeded, the execve() doesn't return, so we
		 * can only be here is if the file hasn't been found yet.
		 * Try the next place on the path.
		 */
	}

	/* all attempts failed to locate the file.  Give up. */
	errno = ENOENT;

fail:
	free(fnbuffer);
	return -1;
}
#endif


#ifdef EMUL_OPEN3
#include "open3.h"
/*
 * open3 -- routine to emulate the 3-argument open system
 * call that is present in most modern Unix systems.
 * This version attempts to support all the flag bits except for O_NDELAY
 * and O_APPEND, which are silently ignored.  The emulation is not as efficient
 * as the real thing (at worst, 4 system calls instead of one), but there's
 * not much I can do about that.
 *
 * Written 6/10/87 by rmtodd@uokmax
 *
 * open3(path, flag, mode)
 * Attempts to open the file specified by
 * the given pathname.  The following flag bits (#defined in tar.h)
 * specify options to the routine:
 *	O_RDONLY	file open for read only
 *	O_WRONLY	file open for write only
 *	O_RDWR		file open for both read & write
 * (Needless to say, you should only specify one of the above).
 * 	O_CREAT		file is created with specified mode if it needs to be.
 *	O_TRUNC		if file exists, it is truncated to 0 bytes
 *	O_EXCL		used with O_CREAT--routine returns error if file exists
 * Function returns file descriptor if successful, -1 and errno if not.
 */

/*
 * array to give arguments to access for various modes
 * FIXME, this table depends on the specific integer values of O_XXX,
 * and also contains integers (args to 'access') that should be #define's.
 */
static int modes[] =
	{
		04, /* O_RDONLY */
		02, /* O_WRONLY */
		06, /* O_RDWR */
		06, /* invalid but we'd better cope -- O_WRONLY+O_RDWR */
	};

/* Shut off the automatic emulation of open(), we'll need it. */
#undef open

int
open3(path, flags, mode)
char *path;
int flags, mode;
{
	extern int errno;
	int exists = 1;
	int call_creat = 0;
	int fd;
	/*
	 * We actually do the work by calling the open() or creat() system
	 * call, depending on the flags.  Call_creat is true if we will use 
	 * creat(), false if we will use open().
	 */

	/*
	 * See if the file exists and is accessible in the requested mode. 
	 *
	 * Strictly speaking we shouldn't be using access, since access checks
	 * against real uid, and the open call should check against euid.
	 * Most cases real uid == euid, so it won't matter.   FIXME.
	 * FIXME, the construction "flags & 3" and the modes table depends
	 * on the specific integer values of the O_XXX #define's.  Foo!
	 */
	if (access(path,modes[flags & 3]) < 0) {
		if (errno == ENOENT) {
			/* the file does not exist */
			exists = 0;
		} else {
			/* probably permission violation */
			if (flags & O_EXCL) {
				/* Oops, the file exists, we didn't want it. */
				/* No matter what the error, claim EEXIST. */
				errno = EEXIST;
			}
			return -1;
		}
	}

	/* if we have the O_CREAT bit set, check for O_EXCL */
	if (flags & O_CREAT) {
		if ((flags & O_EXCL) && exists) {
			/* Oops, the file exists and we didn't want it to. */
			errno = EEXIST;
			return -1;
		}
		/*
		 * If the file doesn't exist, be sure to call creat() so that
		 * it will be created with the proper mode.
		 */
		if (!exists) call_creat = 1;
	} else {
		/* If O_CREAT isn't set and the file doesn't exist, error. */
		if (!exists) {
			errno = ENOENT;
			return -1;
		}
	}

	/*
	 * If the O_TRUNC flag is set and the file exists, we want to call
	 * creat() anyway, since creat() guarantees that the file will be
	 * truncated and open()-for-writing doesn't.
	 * (If the file doesn't exist, we're calling creat() anyway and the
	 * file will be created with zero length.)
	 */
	if ((flags & O_TRUNC) && exists) call_creat = 1;
	/* actually do the call */
	if (call_creat) {
		/*
		 * call creat.  May have to close and reopen the file if we
		 * want O_RDONLY or O_RDWR access -- creat() only gives
		 * O_WRONLY.
		 */
		fd = creat(path,mode);
		if (fd < 0 || (flags & O_WRONLY)) return fd;
		if (close(fd) < 0) return -1;
		/* Fall out to reopen the file we've created */
	}

	/*
	 * calling old open, we strip most of the new flags just in case.
	 */
	return open(path, flags & (O_RDONLY|O_WRONLY|O_RDWR|O_BINARY));
}
#endif

#ifdef	WANT_MKNOD
#ifdef __MSDOS__
/* typedef int dev_t;  /* we don't need this with MSC 5.1 or later */
#endif
/* Fake mknod by complaining */
int
mknod(path, mode, dev)
	char		*path;
	unsigned short	mode;
	dev_t		dev;
{
	extern int	errno;

⌨️ 快捷键说明

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