📄 port.c
字号:
/* Supporting routines which may sometimes be missing. Copyright (C) 1988 Free Software FoundationThis file is part of GNU Tar.GNU Tar is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU Tar; see the file COPYING. If not, write tothe 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>#ifdef MSDOS#include <fcntl.h>#else#include <sys/file.h>#endif#include "tar.h"#include "port.h"#ifdef USG#include <string.h>#elseextern size_t strlen();#endifextern 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_GETDATE/* WANT_DUMB_GETDATE --> getdate() */#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 MINIX#define WANT_BZERO#endif#ifdef MSDOSchar 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#define WANT_STRSTR#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_GETDATE/* JF a getdate() 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 getdate 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 getdate() supplied in getdate.y */#define OFF_FROM GMT 18000 /* Change for your time zone! */time_tgetdate(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_MKDIRintmkdir(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;}intrmdir(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>#include <memory.h>char *index (s, c) char *s; int c;{ return (strchr (s, c));}char *rindex(s,c)char *s;int c;{ return strrchr(s,c);}voidbcopy (s1, s2, n) char *s1, *s2; int n;{ (void) memcpy (s2, s1, n);}voidbzero (s1, n) char *s1; int n;{ (void) memset(s1, 0, n);}intbcmp(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. */voidbzero (s1, n) register char *s1; register int n;{ while (n--) *s1++ = '\0';}/* It also has no bcmp() */intbcmp (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. */intexeclp(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 openintopen3(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));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -