util.c

来自「这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易」· C语言 代码 · 共 1,080 行 · 第 1/2 页

C
1,080
字号
/* utility functions for `patch' *//* $Id: util.c,v 1.24 1997/07/10 08:16:12 eggert Exp $ *//*Copyright 1986 Larry WallCopyright 1992, 1993, 1997 Free Software Foundation, Inc.This program 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 2, or (at your option)any later version.This program 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 this program; see the file COPYING.If not, write to the Free Software Foundation,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/#define XTERN extern#include <common.h>#include <backupfile.h>#include <quotearg.h>#include <version.h>#undef XTERN#define XTERN#include <util.h>#include <maketime.h>#include <partime.h>#include <signal.h>#if !defined SIGCHLD && defined SIGCLD#define SIGCHLD SIGCLD#endif#if ! HAVE_RAISE# define raise(sig) kill (getpid (), sig)#endif#ifdef __STDC__# include <stdarg.h># define vararg_start va_start#else# define vararg_start(ap,p) va_start (ap)# if HAVE_VARARGS_H#  include <varargs.h># else   typedef char *va_list;#  define va_dcl int va_alist;#  define va_start(ap) ((ap) = (va_list) &va_alist)#  define va_arg(ap, t) (((t *) ((ap) += sizeof (t)))  [-1])#  define va_end(ap)# endif#endifstatic void makedirs PARAMS ((char *));/* Move a file FROM to TO, renaming it if possible and copying it if necessary.   If we must create TO, use MODE to create it.   If FROM is null, remove TO (ignoring FROMSTAT).   Back up TO if BACKUP is nonzero.  */#ifdef __STDC__/* If mode_t doesn't promote to itself, we can't use old-style definition.  */voidmove_file (char const *from, char *to, mode_t mode, int backup)#elsevoidmove_file (from, to, mode, backup)     char const *from;     char *to;     mode_t mode;     int backup;#endif{  struct stat to_st;  int to_errno = ! backup ? -1 : stat (to, &to_st) == 0 ? 0 : errno;  if (backup)    {      int try_makedirs_errno = 0;      char *bakname;      if (origprae || origbase)	{	  char const *p = origprae ? origprae : "";	  char const *b = origbase ? origbase : "";	  char const *o = base_name (to);	  size_t plen = strlen (p);	  size_t tlen = o - to;	  size_t blen = strlen (b);	  size_t osize = strlen (o) + 1;	  bakname = xmalloc (plen + tlen + blen + osize);	  memcpy (bakname, p, plen);	  memcpy (bakname + plen, to, tlen);	  memcpy (bakname + plen + tlen, b, blen);	  memcpy (bakname + plen + tlen + blen, o, osize);	  for (p += FILESYSTEM_PREFIX_LEN (p);  *p;  p++)	    if (ISSLASH (*p))	      {		try_makedirs_errno = ENOENT;		break;	      }	}      else	{	  bakname = find_backup_file_name (to);	  if (!bakname)	    memory_fatal ();	}      if (to_errno)	{	  int fd;	  if (debug & 4)	    say ("creating empty unreadable file `%s'\n", bakname);	  try_makedirs_errno = ENOENT;	  unlink (bakname);	  while ((fd = creat (bakname, 0)) < 0)	    {	      if (errno != try_makedirs_errno)		pfatal ("can't create file `%s'", bakname);	      makedirs (bakname);	      try_makedirs_errno = 0;	    }	  if (close (fd) != 0)	    pfatal ("can't close `%s'", bakname);	}      else	{	  if (debug & 4)	    say ("renaming `%s' to `%s'\n", to, bakname);	  while (rename (to, bakname) != 0)	    {	      if (errno != try_makedirs_errno)		pfatal ("can't rename `%s' to `%s'", to, bakname);	      makedirs (bakname);	      try_makedirs_errno = 0;	    }	}      free (bakname);    }  if (from)    {      if (debug & 4)	say ("renaming `%s' to `%s'\n", from, to);      if (rename (from, to) != 0)	{	  int to_dir_known_to_exist = 0;	  if (errno == ENOENT	      && (to_errno == -1 || to_errno == ENOENT))	    {	      makedirs (to);	      to_dir_known_to_exist = 1;	      if (rename (from, to) == 0)		return;	    }	  if (errno == EXDEV)	    {	      if (! backup)		{		  if (unlink (to) == 0)		    to_dir_known_to_exist = 1;		  else if (errno != ENOENT)		    pfatal ("can't remove `%s'", to);		}	      if (! to_dir_known_to_exist)		makedirs (to);	      copy_file (from, to, mode);	      return;	    }	  pfatal ("can't rename `%s' to `%s'", from, to);	}    }  else if (! backup)    {      if (debug & 4)	say ("removing `%s'\n", to);      if (unlink (to) != 0)	pfatal ("can't remove `%s'", to);    }}/* Create FILE with OPEN_FLAGS, and with MODE adjusted so that   we can read and write the file and that the file is not executable.   Return the file descriptor.  */#ifdef __STDC__/* If mode_t doesn't promote to itself, we can't use old-style definition.  */intcreate_file (char const *file, int open_flags, mode_t mode)#elseintcreate_file (file, open_flags, mode)     char const *file;     int open_flags;     mode_t mode;#endif{  int fd;  mode |= S_IRUSR | S_IWUSR;  mode &= ~ (S_IXUSR | S_IXGRP | S_IXOTH);  if (! (O_CREAT && O_TRUNC))    close (creat (file, mode));  fd = open (file, O_CREAT | O_TRUNC | open_flags, mode);  if (fd < 0)    pfatal ("can't create `%s'", file);  return fd;}/* Copy a file. */#ifdef __STDC__/* If mode_t doesn't promote to itself, we can't use old-style definition.  */voidcopy_file (char const *from, char const *to, mode_t mode)#elsevoidcopy_file (from, to, mode)     char const *from;     char const *to;     mode_t mode;#endif{  int tofd;  int fromfd;  size_t i;  if ((fromfd = open (from, O_RDONLY | O_BINARY)) < 0)    pfatal ("can't reopen `%s'", from);  tofd = create_file (to, O_WRONLY | O_BINARY, mode);  while ((i = read (fromfd, buf, bufsize)) != 0)    {      if (i == -1)	read_fatal ();      if (write (tofd, buf, i) != i)	write_fatal ();    }  if (close (fromfd) != 0)    read_fatal ();  if (close (tofd) != 0)    write_fatal ();}static char const DEV_NULL[] = NULL_DEVICE;static char const SCCSPREFIX[] = "s.";static char const GET[] = "get ";static char const GET_LOCKED[] = "get -e ";static char const SCCSDIFF1[] = "get -p ";static char const SCCSDIFF2[] = "|diff - %s";static char const RCSSUFFIX[] = ",v";static char const CHECKOUT[] = "co %s";static char const CHECKOUT_LOCKED[] = "co -l %s";static char const RCSDIFF1[] = "rcsdiff %s";/* Return "RCS" if FILENAME is controlled by RCS,   "SCCS" if it is controlled by SCCS, and 0 otherwise.   READONLY is nonzero if we desire only readonly access to FILENAME.   FILESTAT describes FILENAME's status or is 0 if FILENAME does not exist.   If successful and if GETBUF is nonzero, set *GETBUF to a command   that gets the file; similarly for DIFFBUF and a command to diff the file.   *GETBUF and *DIFFBUF must be freed by the caller.  */char const *version_controller (filename, readonly, filestat, getbuf, diffbuf)     char const *filename;     int readonly;     struct stat const *filestat;     char **getbuf;     char **diffbuf;{  struct stat cstat;  char const *filebase = base_name (filename);  char const *dotslash = *filename == '-' ? "./" : "";  size_t dir_len = filebase - filename;  size_t filenamelen = strlen (filename);  size_t maxfixlen = sizeof "SCCS/" - 1 + sizeof SCCSPREFIX - 1;  size_t maxtrysize = filenamelen + maxfixlen + 1;  size_t quotelen = quote_system_arg (0, filename);  size_t maxgetsize = sizeof GET_LOCKED + quotelen + maxfixlen;  size_t maxdiffsize =    (sizeof SCCSDIFF1 + sizeof SCCSDIFF2 + sizeof DEV_NULL - 1     + 2 * quotelen + maxfixlen);  char *trybuf = xmalloc (maxtrysize);  char const *r = 0;  strcpy (trybuf, filename);#define try1(f,a1)    (sprintf (trybuf + dir_len, f, a1),    stat (trybuf, &cstat) == 0)#define try2(f,a1,a2) (sprintf (trybuf + dir_len, f, a1,a2), stat (trybuf, &cstat) == 0)  /* Check that RCS file is not working file.     Some hosts don't report file name length errors.  */  if ((try2 ("RCS/%s%s", filebase, RCSSUFFIX)       || try1 ("RCS/%s", filebase)       || try2 ("%s%s", filebase, RCSSUFFIX))      && ! (filestat	    && filestat->st_dev == cstat.st_dev	    && filestat->st_ino == cstat.st_ino))    {      if (getbuf)	{	  char *p = *getbuf = xmalloc (maxgetsize);	  sprintf (p, readonly ? CHECKOUT : CHECKOUT_LOCKED, dotslash);	  p += strlen (p);	  p += quote_system_arg (p, filename);	  *p = '\0';	}      if (diffbuf)	{	  char *p = *diffbuf = xmalloc (maxdiffsize);	  sprintf (p, RCSDIFF1, dotslash);	  p += strlen (p);	  p += quote_system_arg (p, filename);	  *p++ = '>';	  strcpy (p, DEV_NULL);	}      r = "RCS";    }  else if (try2 ("SCCS/%s%s", SCCSPREFIX, filebase)	   || try2 ("%s%s", SCCSPREFIX, filebase))    {      if (getbuf)	{	  char *p = *getbuf = xmalloc (maxgetsize);	  sprintf (p, readonly ? GET : GET_LOCKED);	  p += strlen (p);	  p += quote_system_arg (p, trybuf);	  *p = '\0';	}      if (diffbuf)	{	  char *p = *diffbuf = xmalloc (maxdiffsize);	  strcpy (p, SCCSDIFF1);	  p += sizeof SCCSDIFF1 - 1;	  p += quote_system_arg (p, trybuf);	  sprintf (p, SCCSDIFF2, dotslash);	  p += strlen (p);	  p += quote_system_arg (p, filename);	  *p++ = '>';	  strcpy (p, DEV_NULL);	}      r = "SCCS";    }  free (trybuf);  return r;}/* Get FILENAME from version control system CS.  The file already exists if   EXISTS is nonzero.  Only readonly access is needed if READONLY is nonzero.   Use the command GETBUF to actually get the named file.   Store the resulting file status into *FILESTAT.   Return nonzero if successful.  */intversion_get (filename, cs, exists, readonly, getbuf, filestat)     char const *filename;     char const *cs;     int exists;     int readonly;     char const *getbuf;     struct stat *filestat;{  if (patch_get < 0)    {      ask ("Get file `%s' from %s%s? [y] ", filename,	   cs, readonly ? "" : " with lock");      if (*buf == 'n')	return 0;    }  if (dry_run)    {      if (! exists)	fatal ("can't do dry run on nonexistent version-controlled file `%s'; invoke `%s' and try again",	       filename, getbuf);    }  else    {      if (verbosity == VERBOSE)	say ("Getting file `%s' from %s%s...\n", filename,	     cs, readonly ? "" : " with lock");      if (systemic (getbuf) != 0)	fatal ("can't get file `%s' from %s", filename, cs);      if (stat (filename, filestat) != 0)	pfatal ("%s", filename);    }    return 1;}/* Allocate a unique area for a string. */char *savebuf (s, size)     register char const *s;     register size_t size;{  register char *rv;  assert (s && size);  rv = malloc (size);  if (! rv)    {      if (! using_plan_a)	memory_fatal ();    }  else    memcpy (rv, s, size);  return rv;}char *savestr(s)     char const *s;{  return savebuf (s, strlen (s) + 1);}voidremove_prefix (p, prefixlen)     char *p;     size_t prefixlen;{  char const *s = p + prefixlen;  while ((*p++ = *s++))    continue;}#if !HAVE_VPRINTF#define vfprintf my_vfprintfstatic int vfprintf PARAMS ((FILE *, char const *, va_list));static intvfprintf (stream, format, args)     FILE *stream;     char const *format;     va_list args;{#if !HAVE_DOPRNT && HAVE__DOPRINTF# define _doprnt _doprintf#endif#if HAVE_DOPRNT || HAVE__DOPRINTF  _doprnt (format, args, stream);  return ferror (stream) ? -1 : 0;#else  int *a = (int *) args;  return fprintf (stream, format,		  a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]);#endif}#endif /* !HAVE_VPRINTF *//* Terminal output, pun intended. */#ifdef __STDC__voidfatal (char const *format, ...)#else/*VARARGS1*/ voidfatal (format, va_alist)     char const *format;     va_dcl#endif{  va_list args;  fprintf (stderr, "%s: **** ", program_name);  vararg_start (args, format);  vfprintf (stderr, format, args);  va_end (args);  putc ('\n', stderr);  fflush (stderr);  fatal_exit (0);}voidmemory_fatal (){  fatal ("out of memory");}voidread_fatal (){  pfatal ("read error");}voidwrite_fatal (){  pfatal ("write error");}/* Say something from patch, something from the system, then silence . . . */#ifdef __STDC__voidpfatal (char const *format, ...)#else/*VARARGS1*/ voidpfatal (format, va_alist)     char const *format;     va_dcl#endif{  int errnum = errno;  va_list args;  fprintf (stderr, "%s: **** ", program_name);  vararg_start (args, format);  vfprintf (stderr, format, args);  va_end (args);  fflush (stderr); /* perror bypasses stdio on some hosts.  */  errno = errnum;  perror (" ");  fflush (stderr);  fatal_exit (0);}/* Tell the user something.  */#ifdef __STDC__voidsay (char const *format, ...)

⌨️ 快捷键说明

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