changeset 5:41c9d08b09d7

Initial revision
author Jim Meyering <jim@meyering.net>
date Sat, 31 Oct 1992 20:42:48 +0000
parents 9087e62f9efd
children 4949c6c98e20 2d78b0003b93
files lib/Makefile.in lib/argmatch.c lib/backupfile.c lib/backupfile.h lib/dirname.c lib/fileblocks.c lib/filemode.c lib/fnmatch.c lib/fnmatch.h lib/fsusage.c lib/fsusage.h lib/ftruncate.c lib/getversion.c lib/idcache.c lib/isdir.c lib/makepath.c lib/mkdir.c lib/modechange.c lib/modechange.h lib/mountlist.c lib/mountlist.h lib/rename.c lib/savedir.c lib/stpcpy.c lib/strdup.c lib/stripslash.c lib/strstr.c lib/userspec.c lib/xstrdup.c lib/yesno.c
diffstat 30 files changed, 3443 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/Makefile.in	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,98 @@
+# Makefile for library files used by GNU fileutils.
+# Do not use this makefile directly, but only from `../Makefile'.
+# Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+# This program 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 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 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 this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+SOURCES = argmatch.c backupfile.c basename.c dirname.c eaccess.c \
+error.c filemode.c fsusage.c getopt.c getopt1.c \
+getversion.c idcache.c isdir.c makepath.c \
+modechange.c mountlist.c savedir.c \
+stripslash.c xgetcwd.c xmalloc.c xstrdup.c userspec.c yesno.c \
+getdate.y posixtm.y \
+fileblocks.c fnmatch.c ftruncate.c mkdir.c mktime.c rename.c stpcpy.c \
+strdup.c strstr.c alloca.c
+
+OBJECTS = argmatch.o backupfile.o basename.o dirname.o eaccess.o \
+error.o filemode.o getopt.o getopt1.o \
+getversion.o idcache.o isdir.o makepath.o \
+modechange.o savedir.o \
+stripslash.o xgetcwd.o xmalloc.o xstrdup.o userspec.o yesno.o \
+getdate.o posixtm.o @LIBOBJS@ @ALLOCA@
+
+DISTFILES = Makefile.in backupfile.h getopt.h modechange.h \
+fnmatch.h fsusage.h mountlist.h pathmax.h system.h $(SOURCES)
+
+all: libfu.a
+
+.c.o:
+	$(CC) -c $(CFLAGS) $(CPPFLAGS) $(DEFS) -I$(srcdir) $<
+
+install: all
+
+uninstall:
+
+TAGS: $(SOURCES)
+	etags $(SOURCES)
+
+clean:
+	rm -f *.a *.o
+
+mostlyclean: clean
+
+distclean: clean
+	rm -f Makefile *.tab.c getdate.c *posixtm.c
+
+realclean: distclean
+	rm -f TAGS
+
+dist:
+	ln $(DISTFILES) ../`cat ../.fname`/lib
+
+libfu.a: $(OBJECTS)
+	rm -f $@
+	$(AR) cr $@ $(OBJECTS)
+	-$(RANLIB) $@
+
+# Since this directory contains two parsers, using bison without -y
+# is the only way to reliably do a parallel make.
+getdate.c: getdate.y
+	@echo expect 9 shift/reduce conflicts
+	-bison -o getdate.c $(srcdir)/getdate.y || yacc $(srcdir)/getdate.y
+	test ! -f y.tab.c || mv y.tab.c getdate.c
+
+# Make the rename atomic, in case sed is interrupted and later rerun.
+posixtm.c: posixtm.y
+	-bison -o posixtm.tab.c $(srcdir)/posixtm.y || yacc $(srcdir)/posixtm.y
+	test ! -f y.tab.c || mv y.tab.c posixtm.tab.c
+	sed -e 's/yy/zz/g' posixtm.tab.c > tposixtm.c
+	mv tposixtm.c posixtm.c
+	rm -f posixtm.tab.c
+
+backupfile.o getversion.o: backupfile.h
+fnmatch.o: fnmatch.h
+fsusage.o: fsusage.h
+getopt1.o: getopt.h
+modechange.o: modechange.h
+mountlist.o: mountlist.h
+xgetcwd.o: pathmax.h
+
+# Prevent GNU make v3 from overflowing arg limit on SysV.
+.NOEXPORT:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/argmatch.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,83 @@
+/* argmatch.c -- find a match for a string in an array
+   Copyright (C) 1990 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Written by David MacKenzie <djm@ai.mit.edu> */
+
+#include <stdio.h>
+#ifdef STDC_HEADERS
+#include <string.h>
+#endif
+
+extern char *program_name;
+
+/* If ARG is an unambiguous match for an element of the
+   null-terminated array OPTLIST, return the index in OPTLIST
+   of the matched element, else -1 if it does not match any element
+   or -2 if it is ambiguous (is a prefix of more than one element).  */
+
+int
+argmatch (arg, optlist)
+     char *arg;
+     char **optlist;
+{
+  int i;			/* Temporary index in OPTLIST.  */
+  int arglen;			/* Length of ARG.  */
+  int matchind = -1;		/* Index of first nonexact match.  */
+  int ambiguous = 0;		/* If nonzero, multiple nonexact match(es).  */
+  
+  arglen = strlen (arg);
+  
+  /* Test all elements for either exact match or abbreviated matches.  */
+  for (i = 0; optlist[i]; i++)
+    {
+      if (!strncmp (optlist[i], arg, arglen))
+	{
+	  if (strlen (optlist[i]) == arglen)
+	    /* Exact match found.  */
+	    return i;
+	  else if (matchind == -1)
+	    /* First nonexact match found.  */
+	    matchind = i;
+	  else
+	    /* Second nonexact match found.  */
+	    ambiguous = 1;
+	}
+    }
+  if (ambiguous)
+    return -2;
+  else
+    return matchind;
+}
+
+/* Error reporting for argmatch.
+   KIND is a description of the type of entity that was being matched.
+   VALUE is the invalid value that was given.
+   PROBLEM is the return value from argmatch.  */
+
+void
+invalid_arg (kind, value, problem)
+     char *kind;
+     char *value;
+     int problem;
+{
+  fprintf (stderr, "%s: ", program_name);
+  if (problem == -1)
+    fprintf (stderr, "invalid");
+  else				/* Assume -2.  */
+    fprintf (stderr, "ambiguous");
+  fprintf (stderr, " %s `%s'\n", kind, value);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/backupfile.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,224 @@
+/* backupfile.c -- make Emacs style backup file names
+   Copyright (C) 1990 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* David MacKenzie <djm@ai.mit.edu>.
+   Some algorithms adapted from GNU Emacs. */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include "backupfile.h"
+#if defined(USG) || defined(STDC_HEADERS)
+#include <string.h>
+#define index strchr
+#define rindex strrchr
+#else
+#include <strings.h>
+#endif
+
+#ifdef DIRENT
+#include <dirent.h>
+#ifdef direct
+#undef direct
+#endif
+#define direct dirent
+#define NLENGTH(direct) (strlen((direct)->d_name))
+#else /* !DIRENT */
+#define NLENGTH(direct) ((direct)->d_namlen)
+#ifdef USG
+#ifdef SYSNDIR
+#include <sys/ndir.h>
+#else /* !SYSNDIR */
+#include <ndir.h>
+#endif /* !SYSNDIR */
+#else /* !USG */
+#include <sys/dir.h>
+#endif /* !USG */
+#endif /* !DIRENT */
+
+#ifdef VOID_CLOSEDIR
+/* Fake a return value. */
+#define CLOSEDIR(d) (closedir (d), 0)
+#else
+#define CLOSEDIR(d) closedir (d)
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *malloc ();
+#endif
+
+#ifndef isascii
+#define ISDIGIT(c) (isdigit ((unsigned char) (c)))
+#else
+#define ISDIGIT(c) (isascii (c) && isdigit (c))
+#endif
+
+#if defined (HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#if defined (_POSIX_VERSION)
+/* POSIX does not require that the d_ino field be present, and some
+   systems do not provide it. */
+#define REAL_DIR_ENTRY(dp) 1
+#else
+#define REAL_DIR_ENTRY(dp) ((dp)->d_ino != 0)
+#endif
+
+/* Which type of backup file names are generated. */
+enum backup_type backup_type = none;
+
+/* The extension added to file names to produce a simple (as opposed
+   to numbered) backup file name. */
+char *simple_backup_suffix = "~";
+
+char *basename ();
+char *dirname ();
+static char *concat ();
+char *find_backup_file_name ();
+static char *make_version_name ();
+static int max_backup_version ();
+static int version_number ();
+
+/* Return the name of the new backup file for file FILE,
+   allocated with malloc.  Return 0 if out of memory.
+   FILE must not end with a '/' unless it is the root directory.
+   Do not call this function if backup_type == none. */
+
+char *
+find_backup_file_name (file)
+     char *file;
+{
+  char *dir;
+  char *base_versions;
+  int highest_backup;
+
+  if (backup_type == simple)
+    return concat (file, simple_backup_suffix);
+  base_versions = concat (basename (file), ".~");
+  if (base_versions == 0)
+    return 0;
+  dir = dirname (file);
+  if (dir == 0)
+    {
+      free (base_versions);
+      return 0;
+    }
+  highest_backup = max_backup_version (base_versions, dir);
+  free (base_versions);
+  free (dir);
+  if (backup_type == numbered_existing && highest_backup == 0)
+    return concat (file, simple_backup_suffix);
+  return make_version_name (file, highest_backup + 1);
+}
+
+/* Return the number of the highest-numbered backup file for file
+   FILE in directory DIR.  If there are no numbered backups
+   of FILE in DIR, or an error occurs reading DIR, return 0.
+   FILE should already have ".~" appended to it. */
+
+static int
+max_backup_version (file, dir)
+     char *file, *dir;
+{
+  DIR *dirp;
+  struct direct *dp;
+  int highest_version;
+  int this_version;
+  int file_name_length;
+  
+  dirp = opendir (dir);
+  if (!dirp)
+    return 0;
+  
+  highest_version = 0;
+  file_name_length = strlen (file);
+
+  while ((dp = readdir (dirp)) != 0)
+    {
+      if (!REAL_DIR_ENTRY (dp) || NLENGTH (dp) <= file_name_length)
+	continue;
+      
+      this_version = version_number (file, dp->d_name, file_name_length);
+      if (this_version > highest_version)
+	highest_version = this_version;
+    }
+  if (CLOSEDIR (dirp))
+    return 0;
+  return highest_version;
+}
+
+/* Return a string, allocated with malloc, containing
+   "FILE.~VERSION~".  Return 0 if out of memory. */
+
+static char *
+make_version_name (file, version)
+     char *file;
+     int version;
+{
+  char *backup_name;
+
+  backup_name = malloc (strlen (file) + 16);
+  if (backup_name == 0)
+    return 0;
+  sprintf (backup_name, "%s.~%d~", file, version);
+  return backup_name;
+}
+
+/* If BACKUP is a numbered backup of BASE, return its version number;
+   otherwise return 0.  BASE_LENGTH is the length of BASE.
+   BASE should already have ".~" appended to it. */
+
+static int
+version_number (base, backup, base_length)
+     char *base;
+     char *backup;
+     int base_length;
+{
+  int version;
+  char *p;
+  
+  version = 0;
+  if (!strncmp (base, backup, base_length) && ISDIGIT (backup[base_length]))
+    {
+      for (p = &backup[base_length]; ISDIGIT (*p); ++p)
+	version = version * 10 + *p - '0';
+      if (p[0] != '~' || p[1])
+	version = 0;
+    }
+  return version;
+}
+
+/* Return the newly-allocated concatenation of STR1 and STR2.
+   If out of memory, return 0. */
+
+static char *
+concat (str1, str2)
+     char *str1, *str2;
+{
+  char *newstr;
+  char str1_length = strlen (str1);
+
+  newstr = malloc (str1_length + strlen (str2) + 1);
+  if (newstr == 0)
+    return 0;
+  strcpy (newstr, str1);
+  strcpy (newstr + str1_length, str2);
+  return newstr;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/backupfile.h	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,42 @@
+/* backupfile.h -- declarations for making Emacs style backup file names
+   Copyright (C) 1990 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* When to make backup files. */
+enum backup_type
+{
+  /* Never make backups. */
+  none,
+
+  /* Make simple backups of every file. */
+  simple,
+
+  /* Make numbered backups of files that already have numbered backups,
+     and simple backups of the others. */
+  numbered_existing,
+
+  /* Make numbered backups of every file. */
+  numbered
+};
+
+extern enum backup_type backup_type;
+extern char *simple_backup_suffix;
+
+#ifdef __STDC__
+char *find_backup_file_name (char *file);
+#else
+char *find_backup_file_name ();
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/dirname.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,64 @@
+/* dirname.c -- return all but the last element in a path
+   Copyright (C) 1990 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *malloc ();
+#endif
+#if defined(USG) || defined(STDC_HEADERS)
+#include <string.h>
+#define rindex strrchr
+#else
+#include <strings.h>
+#endif
+
+/* Return the leading directories part of PATH,
+   allocated with malloc.  If out of memory, return 0.
+   Assumes that trailing slashes have already been
+   removed.  */
+
+char *
+dirname (path)
+     char *path;
+{
+  char *newpath;
+  char *slash;
+  int length;			/* Length of result, not including NUL.  */
+
+  slash = rindex (path, '/');
+  if (slash == 0)
+    {
+      /* File is in the current directory.  */
+      path = ".";
+      length = 1;
+    }
+  else
+    {
+      /* Remove any trailing slashes from the result.  */
+      while (slash > path && *slash == '/')
+	--slash;
+
+      length = slash - path + 1;
+    }
+  newpath = malloc (length + 1);
+  if (newpath == 0)
+    return 0;
+  strncpy (newpath, path, length);
+  newpath[length] = 0;
+  return newpath;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/fileblocks.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,60 @@
+/* Convert file size to number of blocks on System V-like machines.
+   Copyright (C) 1990 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Written by Brian L. Matthews, blm@6sceng.UUCP. */
+
+#if !defined (HAVE_ST_BLOCKS) && !defined(_POSIX_SOURCE)
+#include <sys/types.h>
+#include <sys/param.h>
+
+#ifndef NINDIR
+/* Some SysV's, like Irix, seem to lack these.  Hope they're correct. */
+/* Size of a indirect block, in bytes. */
+#define BSIZE 1024
+
+/* Number of inode pointers per indirect block. */
+#define NINDIR (BSIZE/sizeof(daddr_t))
+#endif /* !NINDIR */
+
+/* Number of direct block addresses in an inode. */
+#define NDIR	10
+
+/* Return the number of 512-byte blocks in a file of SIZE bytes. */
+
+long
+st_blocks (size)
+     long size;
+{
+  long datablks = (size + 512 - 1) / 512;
+  long indrblks = 0;
+
+  if (datablks > NDIR)
+    {
+      indrblks = (datablks - NDIR - 1) / NINDIR + 1;
+
+      if (datablks > NDIR + NINDIR)
+	{
+	  indrblks += (datablks - NDIR - NINDIR - 1) / (NINDIR * NINDIR) + 1;
+
+	  if (datablks > NDIR + NINDIR + NINDIR * NINDIR)
+	    indrblks++;
+	}
+    }
+
+  return datablks + indrblks;
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/filemode.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,221 @@
+/* filemode.c -- make a string describing file modes
+   Copyright (C) 1985, 1990 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef S_IREAD
+#define S_IREAD S_IRUSR
+#define S_IWRITE S_IWUSR
+#define S_IEXEC S_IXUSR
+#endif
+#ifndef S_ISREG			/* Doesn't have POSIX.1 stat stuff.  */
+#define mode_t unsigned short
+#endif
+#if !defined(S_ISBLK) && defined(S_IFBLK)
+#define	S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+#endif
+#if !defined(S_ISCHR) && defined(S_IFCHR)
+#define	S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define	S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG) && defined(S_IFREG)
+#define	S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISFIFO) && defined(S_IFIFO)
+#define	S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+#define	S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK) && defined(S_IFSOCK)
+#define	S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
+#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
+#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
+#endif
+#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
+#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
+#endif
+
+void mode_string ();
+static char ftypelet ();
+static void rwx ();
+static void setst ();
+
+/* filemodestring - fill in string STR with an ls-style ASCII
+   representation of the st_mode field of file stats block STATP.
+   10 characters are stored in STR; no terminating null is added.
+   The characters stored in STR are:
+
+   0	File type.  'd' for directory, 'c' for character
+	special, 'b' for block special, 'm' for multiplex,
+	'l' for symbolic link, 's' for socket, 'p' for fifo,
+	'-' for regular, '?' for any other file type
+
+   1	'r' if the owner may read, '-' otherwise.
+
+   2	'w' if the owner may write, '-' otherwise.
+
+   3	'x' if the owner may execute, 's' if the file is
+	set-user-id, '-' otherwise.
+	'S' if the file is set-user-id, but the execute
+	bit isn't set.
+
+   4	'r' if group members may read, '-' otherwise.
+
+   5	'w' if group members may write, '-' otherwise.
+
+   6	'x' if group members may execute, 's' if the file is
+	set-group-id, '-' otherwise.
+	'S' if it is set-group-id but not executable.
+
+   7	'r' if any user may read, '-' otherwise.
+
+   8	'w' if any user may write, '-' otherwise.
+
+   9	'x' if any user may execute, 't' if the file is "sticky"
+	(will be retained in swap space after execution), '-'
+	otherwise.
+	'T' if the file is sticky but not executable.  */
+
+void
+filemodestring (statp, str)
+     struct stat *statp;
+     char *str;
+{
+  mode_string (statp->st_mode, str);
+}
+
+/* Like filemodestring, but only the relevant part of the `struct stat'
+   is given as an argument.  */
+
+void
+mode_string (mode, str)
+     unsigned short mode;
+     char *str;
+{
+  str[0] = ftypelet (mode);
+  rwx ((mode & 0700) << 0, &str[1]);
+  rwx ((mode & 0070) << 3, &str[4]);
+  rwx ((mode & 0007) << 6, &str[7]);
+  setst (mode, str);
+}
+
+/* Return a character indicating the type of file described by
+   file mode BITS:
+   'd' for directories
+   'b' for block special files
+   'c' for character special files
+   'm' for multiplexor files
+   'l' for symbolic links
+   's' for sockets
+   'p' for fifos
+   '-' for regular files
+   '?' for any other file type.  */
+
+static char
+ftypelet (bits)
+     mode_t bits;
+{
+#ifdef S_ISBLK
+  if (S_ISBLK (bits))
+    return 'b';
+#endif
+  if (S_ISCHR (bits))
+    return 'c';
+  if (S_ISDIR (bits))
+    return 'd';
+  if (S_ISREG (bits))
+    return '-';
+#ifdef S_ISFIFO
+  if (S_ISFIFO (bits))
+    return 'p';
+#endif
+#ifdef S_ISLNK
+  if (S_ISLNK (bits))
+    return 'l';
+#endif
+#ifdef S_ISSOCK
+  if (S_ISSOCK (bits))
+    return 's';
+#endif
+#ifdef S_ISMPC
+  if (S_ISMPC (bits))
+    return 'm';
+#endif
+#ifdef S_ISNWK
+  if (S_ISNWK (bits))
+    return 'n';
+#endif
+  return '?';
+}
+
+/* Look at read, write, and execute bits in BITS and set
+   flags in CHARS accordingly.  */
+
+static void
+rwx (bits, chars)
+     unsigned short bits;
+     char *chars;
+{
+  chars[0] = (bits & S_IREAD) ? 'r' : '-';
+  chars[1] = (bits & S_IWRITE) ? 'w' : '-';
+  chars[2] = (bits & S_IEXEC) ? 'x' : '-';
+}
+
+/* Set the 's' and 't' flags in file attributes string CHARS,
+   according to the file mode BITS.  */
+
+static void
+setst (bits, chars)
+     unsigned short bits;
+     char *chars;
+{
+#ifdef S_ISUID
+  if (bits & S_ISUID)
+    {
+      if (chars[3] != 'x')
+	/* Set-uid, but not executable by owner.  */
+	chars[3] = 'S';
+      else
+	chars[3] = 's';
+    }
+#endif
+#ifdef S_ISGID
+  if (bits & S_ISGID)
+    {
+      if (chars[6] != 'x')
+	/* Set-gid, but not executable by group.  */
+	chars[6] = 'S';
+      else
+	chars[6] = 's';
+    }
+#endif
+#ifdef S_ISVTX
+  if (bits & S_ISVTX)
+    {
+      if (chars[9] != 'x')
+	/* Sticky, but not executable by others.  */
+	chars[9] = 'T';
+      else
+	chars[9] = 't';
+    }
+#endif
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/fnmatch.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,173 @@
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <errno.h>
+#include "fnmatch.h"
+
+#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
+extern int errno;
+#endif
+
+#if !__STDC__
+#define const
+#endif
+
+/* Match STRING against the filename pattern PATTERN, returning zero if
+   it matches, nonzero if not.  */
+int
+fnmatch (pattern, string, flags)
+     const char *pattern;
+     const char *string;
+     int flags;
+{
+  register const char *p = pattern, *n = string;
+  register char c;
+
+  if ((flags & ~__FNM_FLAGS) != 0)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  while ((c = *p++) != '\0')
+    {
+      switch (c)
+	{
+	case '?':
+	  if (*n == '\0')
+	    return FNM_NOMATCH;
+	  else if ((flags & FNM_PATHNAME) && *n == '/')
+	    return FNM_NOMATCH;
+	  else if ((flags & FNM_PERIOD) && *n == '.' &&
+		   (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
+	    return FNM_NOMATCH;
+	  break;
+
+	case '\\':
+	  if (!(flags & FNM_NOESCAPE))
+	    c = *p++;
+	  if (*n != c)
+	    return FNM_NOMATCH;
+	  break;
+
+	case '*':
+	  if ((flags & FNM_PERIOD) && *n == '.' &&
+	      (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
+	    return FNM_NOMATCH;
+
+	  for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
+	    if (((flags & FNM_PATHNAME) && *n == '/') ||
+		(c == '?' && *n == '\0'))
+	      return FNM_NOMATCH;
+
+	  if (c == '\0')
+	    return 0;
+
+	  {
+	    char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
+	    for (--p; *n != '\0'; ++n)
+	      if ((c == '[' || *n == c1) &&
+		  fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
+		return 0;
+	    return FNM_NOMATCH;
+	  }
+
+	case '[':
+	  {
+	    /* Nonzero if the sense of the character class is inverted.  */
+	    register int not;
+
+	    if (*n == '\0')
+	      return FNM_NOMATCH;
+
+	    if ((flags & FNM_PERIOD) && *n == '.' &&
+		(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
+	      return FNM_NOMATCH;
+
+	    not = (*p == '!' || *p == '^');
+	    if (not)
+	      ++p;
+
+	    c = *p++;
+	    for (;;)
+	      {
+		register char cstart = c, cend = c;
+
+		if (!(flags & FNM_NOESCAPE) && c == '\\')
+		  cstart = cend = *p++;
+
+		if (c == '\0')
+		  /* [ (unterminated) loses.  */
+		  return FNM_NOMATCH;
+
+		c = *p++;
+
+		if ((flags & FNM_PATHNAME) && c == '/')
+		  /* [/] can never match.  */
+		  return FNM_NOMATCH;
+
+		if (c == '-' && *p != ']')
+		  {
+		    cend = *p++;
+		    if (!(flags & FNM_NOESCAPE) && cend == '\\')
+		      cend = *p++;
+		    if (cend == '\0')
+		      return FNM_NOMATCH;
+		    c = *p++;
+		  }
+
+		if (*n >= cstart && *n <= cend)
+		  goto matched;
+
+		if (c == ']')
+		  break;
+	      }
+	    if (!not)
+	      return FNM_NOMATCH;
+	    break;
+
+	  matched:;
+	    /* Skip the rest of the [...] that already matched.  */
+	    while (c != ']')
+	      {
+		if (c == '\0')
+		  /* [... (unterminated) loses.  */
+		  return FNM_NOMATCH;
+
+		c = *p++;
+		if (!(flags & FNM_NOESCAPE) && c == '\\')
+		  /* 1003.2d11 is unclear if this is right.  %%% */
+		  ++p;
+	      }
+	    if (not)
+	      return FNM_NOMATCH;
+	  }
+	  break;
+
+	default:
+	  if (c != *n)
+	    return FNM_NOMATCH;
+	}
+
+      ++n;
+    }
+
+  if (*n == '\0' || ((flags & FNM_TARPATH) && *n == '/'))
+    return 0;
+
+  return FNM_NOMATCH;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/fnmatch.h	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,61 @@
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef	_FNMATCH_H
+
+#define	_FNMATCH_H	1
+
+#ifdef	__cplusplus
+extern "C"
+{
+#endif
+
+#if defined (__cplusplus) || (defined (__STDC__) && __STDC__)
+#undef	__P
+#define	__P(args)	args
+#else /* Not C++ or ANSI C.  */
+#undef	__P
+#define	__P(args)	()
+#undef	const
+#define	const
+#endif /* C++ or ANSI C.  */
+
+/* Bits set in the FLAGS argument to `fnmatch'.  */
+#define	FNM_PATHNAME	(1 << 0)/* No wildcard can ever match `/'.  */
+#define	FNM_NOESCAPE	(1 << 1)/* Backslashes don't quote special chars.  */
+#define	FNM_PERIOD	(1 << 2)/* Leading `.' is matched only explicitly.  */
+#define	FNM_TARPATH	(1 << 4)/* Ignore `/...' after a match.  */
+#define	__FNM_FLAGS	(FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD|FNM_TARPATH)
+
+#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_BSD_SOURCE)
+#define	FNM_FILE_NAME	FNM_PATHNAME
+#endif
+
+/* Value returned by `fnmatch' if STRING does not match PATTERN.  */
+#define	FNM_NOMATCH	1
+
+/* Match STRING against the filename pattern PATTERN,
+   returning zero if it matches, FNM_NOMATCH if not.  */
+  extern int fnmatch __P ((const char *__pattern, const char *__string,
+			   int __flags));
+
+#ifdef	__cplusplus
+}
+
+#endif
+
+#endif /* fnmatch.h */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/fsusage.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,198 @@
+/* fsusage.c -- return space usage of mounted filesystems
+   Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <sys/types.h>
+#include "fsusage.h"
+
+int statfs ();
+
+#if defined(STAT_STATFS2_BSIZE) && !defined(_IBMR2) /* 4.3BSD, SunOS 4, HP-UX, AIX PS/2.  */
+#include <sys/vfs.h>
+#endif
+
+#ifdef STAT_STATFS2_FSIZE	/* 4.4BSD.  */
+#include <sys/mount.h>
+#endif
+
+#ifdef STAT_STATFS2_FS_DATA	/* Ultrix.  */
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif
+
+#ifdef STAT_READ		/* SVR2.  */
+#include <sys/param.h>
+#include <sys/filsys.h>
+#include <fcntl.h>
+#endif
+
+#if defined(STAT_STATFS4) || (defined(_AIX) && defined(_IBMR2)) /* SVR3, Dynix, Irix, AIX RS6000.  */
+#include <sys/statfs.h>
+#endif
+
+#if defined(_AIX) && defined(_I386) /* AIX PS/2.  */
+#include <sys/stat.h>
+#include <sys/dustat.h>
+#endif
+
+#ifdef STAT_STATVFS		/* SVR4.  */
+#include <sys/statvfs.h>
+int statvfs ();
+#endif
+
+/* Return the number of TOSIZE-byte blocks used by
+   BLOCKS FROMSIZE-byte blocks, rounding up.  */
+
+static long
+adjust_blocks (blocks, fromsize, tosize)
+     long blocks;
+     int fromsize, tosize;
+{
+  if (fromsize == tosize)	/* E.g., from 512 to 512.  */
+    return blocks;
+  else if (fromsize > tosize)	/* E.g., from 2048 to 512.  */
+    return blocks * (fromsize / tosize);
+  else				/* E.g., from 256 to 512.  */
+    return (blocks + 1) / (tosize / fromsize);
+}
+
+/* Fill in the fields of FSP with information about space usage for
+   the filesystem on which PATH resides.
+   DISK is the device on which PATH is mounted, for space-getting
+   methods that need to know it.
+   Return 0 if successful, -1 if not. */
+
+int
+get_fs_usage (path, disk, fsp)
+     char *path, *disk;
+     struct fs_usage *fsp;
+{
+#ifdef STAT_STATFS2_FS_DATA	/* Ultrix.  */
+  struct fs_data fsd;
+
+  if (statfs (path, &fsd) != 1)
+    return -1;
+#define convert_blocks(b) adjust_blocks ((b), 1024, 512)
+  fsp->fsu_blocks = convert_blocks (fsd.fd_req.btot);
+  fsp->fsu_bfree = convert_blocks (fsd.fd_req.bfree);
+  fsp->fsu_bavail = convert_blocks (fsd.fd_req.bfreen);
+  fsp->fsu_files = fsd.fd_req.gtot;
+  fsp->fsu_ffree = fsd.fd_req.gfree;
+#endif
+
+#ifdef STAT_READ		/* SVR2.  */
+#ifndef SUPERBOFF
+#define SUPERBOFF (SUPERB * 512)
+#endif
+  struct filsys fsd;
+  int fd;
+
+  fd = open (disk, O_RDONLY);
+  if (fd < 0)
+    return -1;
+  lseek (fd, (long) SUPERBOFF, 0);
+  if (read (fd, (char *) &fsd, sizeof fsd) != sizeof fsd)
+    {
+      close (fd);
+      return -1;
+    }
+  close (fd);
+#define convert_blocks(b) adjust_blocks ((b), (fsd.s_type == Fs2b ? 1024 : 512), 512)
+  fsp->fsu_blocks = convert_blocks (fsd.s_fsize);
+  fsp->fsu_bfree = convert_blocks (fsd.s_tfree);
+  fsp->fsu_bavail = convert_blocks (fsd.s_tfree);
+  fsp->fsu_files = (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1);
+  fsp->fsu_ffree = fsd.s_tinode;
+#endif
+
+#ifdef STAT_STATFS2_BSIZE	/* 4.3BSD, SunOS 4, HP-UX, AIX.  */
+  struct statfs fsd;
+
+  if (statfs (path, &fsd) < 0)
+    return -1;
+#define convert_blocks(b) adjust_blocks ((b), fsd.f_bsize, 512)
+#endif
+
+#ifdef STAT_STATFS2_FSIZE	/* 4.4BSD.  */
+  struct statfs fsd;
+
+  if (statfs (path, &fsd) < 0)
+    return -1;
+#define convert_blocks(b) adjust_blocks ((b), fsd.f_fsize, 512)
+#endif
+
+#ifdef STAT_STATFS4		/* SVR3, Dynix, Irix.  */
+  struct statfs fsd;
+
+  if (statfs (path, &fsd, sizeof fsd, 0) < 0)
+    return -1;
+  /* Empirically, the block counts on most SVR3 and SVR3-derived
+     systems seem to always be in terms of 512-byte blocks,
+     no matter what value f_bsize has.  */
+#define convert_blocks(b) (b)
+#ifndef _SEQUENT_		/* _SEQUENT_ is DYNIX/ptx.  */
+#define f_bavail f_bfree
+#endif
+#endif
+
+#ifdef STAT_STATVFS		/* SVR4.  */
+  struct statvfs fsd;
+
+  if (statvfs (path, &fsd) < 0)
+    return -1;
+  /* f_frsize isn't guaranteed to be supported.  */
+#define convert_blocks(b) \
+  adjust_blocks ((b), fsd.f_frsize ? fsd.f_frsize : fsd.f_bsize, 512)
+#endif
+
+#if !defined(STAT_STATFS2_FS_DATA) && !defined(STAT_READ) /* !Ultrix && !SVR2.  */
+  fsp->fsu_blocks = convert_blocks (fsd.f_blocks);
+  fsp->fsu_bfree = convert_blocks (fsd.f_bfree);
+  fsp->fsu_bavail = convert_blocks (fsd.f_bavail);
+  fsp->fsu_files = fsd.f_files;
+  fsp->fsu_ffree = fsd.f_ffree;
+#endif
+
+  return 0;
+}
+
+#if defined(_AIX) && defined(_I386)
+/* AIX PS/2 does not supply statfs.  */
+
+int
+statfs (path, fsb)
+     char *path;
+     struct statfs *fsb;
+{
+  struct stat stats;
+  struct dustat fsd;
+
+  if (stat (path, &stats))
+    return -1;
+  if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
+    return -1;
+  fsb->f_type   = 0;
+  fsb->f_bsize  = fsd.du_bsize;
+  fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
+  fsb->f_bfree  = fsd.du_tfree;
+  fsb->f_bavail = fsd.du_tfree;
+  fsb->f_files  = (fsd.du_isize - 2) * fsd.du_inopb;
+  fsb->f_ffree  = fsd.du_tinode;
+  fsb->f_fsid.val[0] = fsd.du_site;
+  fsb->f_fsid.val[1] = fsd.du_pckno;
+  return 0;
+}
+#endif /* _AIX && _I386 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/fsusage.h	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,32 @@
+/* fsusage.h -- declarations for filesystem space usage info
+   Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Space usage statistics for a filesystem.  Blocks are 512-byte. */
+struct fs_usage
+{
+  long fsu_blocks;		/* Total blocks. */
+  long fsu_bfree;		/* Free blocks available to superuser. */
+  long fsu_bavail;		/* Free blocks available to non-superuser. */
+  long fsu_files;		/* Total file nodes. */
+  long fsu_ffree;		/* Free file nodes. */
+};
+
+#if __STDC__
+int get_fs_usage (char *path, char *disk, struct fs_usage *fsp);
+#else
+int get_fs_usage ();
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/ftruncate.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,72 @@
+/* ftruncate emulations that work on some System V's.
+   This file is in the public domain. */
+
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifdef F_CHSIZE
+int
+ftruncate (fd, length)
+     int fd;
+     off_t length;
+{
+  return fcntl (fd, F_CHSIZE, length);
+}
+#else
+#ifdef F_FREESP
+/* The following function was written by
+   kucharsk@Solbourne.com (William Kucharski) */
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+
+int
+ftruncate (fd, length)
+     int fd;
+     off_t length;
+{
+  struct flock fl;
+  struct stat filebuf;
+
+  if (fstat (fd, &filebuf) < 0)
+    return -1;
+
+  if (filebuf.st_size < length)
+    {
+      /* Extend file length. */
+      if (lseek (fd, (length - 1), SEEK_SET) < 0)
+	return -1;
+
+      /* Write a "0" byte. */
+      if (write (fd, "", 1) != 1)
+	return -1;
+    }
+  else
+    {
+      /* Truncate length. */
+      fl.l_whence = 0;
+      fl.l_len = 0;
+      fl.l_start = length;
+      fl.l_type = F_WRLCK;	/* Write lock on file space. */
+
+      /* This relies on the UNDOCUMENTED F_FREESP argument to
+	 fcntl, which truncates the file so that it ends at the
+	 position indicated by fl.l_start.
+	 Will minor miracles never cease? */
+      if (fcntl (fd, F_FREESP, &fl) < 0)
+	return -1;
+    }
+
+  return 0;
+}
+#else
+int
+ftruncate (fd, length)
+     int fd;
+     off_t length;
+{
+  return chsize (fd, length);
+}
+#endif
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/getversion.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,57 @@
+/* getversion.c -- select backup filename type
+   Copyright (C) 1990 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu> */
+
+#include "backupfile.h"
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+int argmatch ();
+void invalid_arg ();
+
+extern char *program_name;
+
+static char *backup_args[] =
+{
+  "never", "simple", "nil", "existing", "t", "numbered", 0
+};
+
+static enum backup_type backup_types[] =
+{
+  simple, simple, numbered_existing, numbered_existing, numbered, numbered
+};
+
+/* Return the type of backup indicated by VERSION.
+   Unique abbreviations are accepted. */
+
+enum backup_type
+get_version (version)
+     char *version;
+{
+  int i;
+
+  if (version == 0 || *version == 0)
+    return numbered_existing;
+  i = argmatch (version, backup_args);
+  if (i >= 0)
+    return backup_types[i];
+  invalid_arg ("version control type", version, i);
+  exit (1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/idcache.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,206 @@
+/* idcache.c -- map user and group IDs, cached for speed
+   Copyright (C) 1985, 1988, 1989, 1990 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+#if defined(USG) || defined(STDC_HEADERS)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifndef _POSIX_VERSION
+struct passwd *getpwuid ();
+struct passwd *getpwnam ();
+struct group *getgrgid ();
+struct group *getgrnam ();
+#endif
+
+char *xmalloc ();
+char *xstrdup ();
+
+struct userid
+{
+  union
+    {
+      uid_t u;
+      gid_t g;
+    } id;
+  char *name;
+  struct userid *next;
+};
+
+static struct userid *user_alist;
+
+/* The members of this list have names not in the local passwd file.  */
+static struct userid *nouser_alist;
+
+/* Translate UID to a login name or a stringified number,
+   with cache.  */
+
+char *
+getuser (uid)
+     uid_t uid;
+{
+  register struct userid *tail;
+  struct passwd *pwent;
+  char usernum_string[20];
+
+  for (tail = user_alist; tail; tail = tail->next)
+    if (tail->id.u == uid)
+      return tail->name;
+
+  pwent = getpwuid (uid);
+  tail = (struct userid *) xmalloc (sizeof (struct userid));
+  tail->id.u = uid;
+  if (pwent == 0)
+    {
+      sprintf (usernum_string, "%u", (unsigned) uid);
+      tail->name = xstrdup (usernum_string);
+    }
+  else
+    tail->name = xstrdup (pwent->pw_name);
+
+  /* Add to the head of the list, so most recently used is first.  */
+  tail->next = user_alist;
+  user_alist = tail;
+  return tail->name;
+}
+
+/* Translate USER to a UID, with cache.
+   Return NULL if there is no such user.
+   (We also cache which user names have no passwd entry,
+   so we don't keep looking them up.)  */
+
+uid_t *
+getuidbyname (user)
+     char *user;
+{
+  register struct userid *tail;
+  struct passwd *pwent;
+
+  for (tail = user_alist; tail; tail = tail->next)
+    /* Avoid a function call for the most common case.  */
+    if (*tail->name == *user && !strcmp (tail->name, user))
+      return &tail->id.u;
+
+  for (tail = nouser_alist; tail; tail = tail->next)
+    /* Avoid a function call for the most common case.  */
+    if (*tail->name == *user && !strcmp (tail->name, user))
+      return 0;
+
+  pwent = getpwnam (user);
+
+  tail = (struct userid *) xmalloc (sizeof (struct userid));
+  tail->name = xstrdup (user);
+
+  /* Add to the head of the list, so most recently used is first.  */
+  if (pwent)
+    {
+      tail->id.u = pwent->pw_uid;
+      tail->next = user_alist;
+      user_alist = tail;
+      return &tail->id.u;
+    }
+
+  tail->next = nouser_alist;
+  nouser_alist = tail;
+  return 0;
+}
+
+/* Use the same struct as for userids.  */
+static struct userid *group_alist;
+static struct userid *nogroup_alist;
+
+/* Translate GID to a group name or a stringified number,
+   with cache.  */
+
+char *
+getgroup (gid)
+     gid_t gid;
+{
+  register struct userid *tail;
+  struct group *grent;
+  char groupnum_string[20];
+
+  for (tail = group_alist; tail; tail = tail->next)
+    if (tail->id.g == gid)
+      return tail->name;
+
+  grent = getgrgid (gid);
+  tail = (struct userid *) xmalloc (sizeof (struct userid));
+  tail->id.g = gid;
+  if (grent == 0)
+    {
+      sprintf (groupnum_string, "%u", (unsigned int) gid);
+      tail->name = xstrdup (groupnum_string);
+    }
+  else
+    tail->name = xstrdup (grent->gr_name);
+
+  /* Add to the head of the list, so most recently used is first.  */
+  tail->next = group_alist;
+  group_alist = tail;
+  return tail->name;
+}
+
+/* Translate GROUP to a UID, with cache.
+   Return NULL if there is no such group.
+   (We also cache which group names have no group entry,
+   so we don't keep looking them up.)  */
+
+gid_t *
+getgidbyname (group)
+     char *group;
+{
+  register struct userid *tail;
+  struct group *grent;
+
+  for (tail = group_alist; tail; tail = tail->next)
+    /* Avoid a function call for the most common case.  */
+    if (*tail->name == *group && !strcmp (tail->name, group))
+      return &tail->id.g;
+
+  for (tail = nogroup_alist; tail; tail = tail->next)
+    /* Avoid a function call for the most common case.  */
+    if (*tail->name == *group && !strcmp (tail->name, group))
+      return 0;
+
+  grent = getgrnam (group);
+
+  tail = (struct userid *) xmalloc (sizeof (struct userid));
+  tail->name = xstrdup (group);
+
+  /* Add to the head of the list, so most recently used is first.  */
+  if (grent)
+    {
+      tail->id.g = grent->gr_gid;
+      tail->next = group_alist;
+      group_alist = tail;
+      return &tail->id.g;
+    }
+  
+  tail->next = nogroup_alist;
+  nogroup_alist = tail;
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/isdir.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,35 @@
+/* isdir.c -- determine whether a directory exists
+   Copyright (C) 1990 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define	S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+/* If PATH is an existing directory or symbolic link to a directory,
+   return nonzero, else 0.  */
+
+int
+isdir (path)
+     char *path;
+{
+  struct stat stats;
+
+  return stat (path, &stats) == 0 && S_ISDIR (stats.st_mode);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/makepath.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,261 @@
+/* makepath.c -- Ensure that a directory path exists.
+   Copyright (C) 1990 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu> and
+   Jim Meyering <meyering@cs.utexas.edu>.  */
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#else
+#ifdef _AIX
+ #pragma alloca
+#else
+char *alloca ();
+#endif
+#endif
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define	S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+#ifdef STDC_HEADERS
+#include <errno.h>
+#include <stdlib.h>
+#else
+extern int errno;
+#endif
+
+#if defined(USG) || defined(STDC_HEADERS)
+#include <string.h>
+#define index strchr
+#else
+#include <strings.h>
+#endif
+
+#ifdef __MSDOS__
+typedef int uid_t;
+typedef int gid_t;
+#endif
+
+void error ();
+
+/* Ensure that the directory ARGPATH exists.
+   Remove any trailing slashes from ARGPATH before calling this function.
+
+   Make any leading directories that don't already exist, with
+   permissions PARENT_MODE.
+   If the last element of ARGPATH does not exist, create it as
+   a new directory with permissions MODE.
+   If OWNER and GROUP are non-negative, make them the UID and GID of
+   created directories.
+   If VERBOSE_FMT_STRING is nonzero, use it as a printf format
+   string for printing a message after successfully making a directory,
+   with the name of the directory that was just made as an argument.
+
+   Return 0 if ARGPATH exists as a directory with the proper
+   ownership and permissions when done, otherwise 1.  */
+
+int
+make_path (argpath, mode, parent_mode, owner, group, verbose_fmt_string)
+     char *argpath;
+     int mode;
+     int parent_mode;
+     uid_t owner;
+     gid_t group;
+     char *verbose_fmt_string;
+{
+  char *dirpath;		/* A copy we can scribble NULs on.  */
+  struct stat stats;
+  int retval = 0;
+  int oldmask = umask (0);
+
+  dirpath = alloca (strlen (argpath) + 1);
+  strcpy (dirpath, argpath);
+
+  if (stat (dirpath, &stats))
+    {
+      char *slash;
+      int tmp_mode;		/* Initial perms for leading dirs.  */
+      int re_protect;		/* Should leading dirs be unwritable? */
+      struct ptr_list
+      {
+	char *dirname_end;
+	struct ptr_list *next;
+      };
+      struct ptr_list *p, *leading_dirs = NULL;
+
+      /* If leading directories shouldn't be writable or executable,
+	 or should have set[ug]id or sticky bits set and we are setting
+	 their owners, we need to fix their permissions after making them.  */
+      if (((parent_mode & 0300) != 0300)
+	  || (owner != (uid_t) -1 && group != (gid_t) -1
+	      && (parent_mode & 07000) != 0))
+	{
+	  tmp_mode = 0700;
+	  re_protect = 1;
+	}
+      else
+	{
+	  tmp_mode = parent_mode;
+	  re_protect = 0;
+	}
+
+      slash = dirpath;
+      while (*slash == '/')
+	slash++;
+      while (slash = index (slash, '/'))
+	{
+	  *slash = '\0';
+	  if (stat (dirpath, &stats))
+	    {
+	      if (mkdir (dirpath, tmp_mode))
+		{
+		  error (0, errno, "cannot make directory `%s'", dirpath);
+		  umask (oldmask);
+		  return 1;
+		}
+	      else
+		{
+		  if (verbose_fmt_string != NULL)
+		    error (0, 0, verbose_fmt_string, dirpath);
+
+		  if (owner != (uid_t) -1 && group != (gid_t) -1
+		      && chown (dirpath, owner, group)
+#ifdef AFS
+		      && errno != EPERM
+#endif
+		      )
+		    {
+		      error (0, errno, "%s", dirpath);
+		      retval = 1;
+		    }
+		  if (re_protect)
+		    {
+		      struct ptr_list *new = (struct ptr_list *)
+			alloca (sizeof (struct ptr_list));
+		      new->dirname_end = slash;
+		      new->next = leading_dirs;
+		      leading_dirs = new;
+		    }
+		}
+	    }
+	  else if (!S_ISDIR (stats.st_mode))
+	    {
+	      error (0, 0, "`%s' exists but is not a directory", dirpath);
+	      umask (oldmask);
+	      return 1;
+	    }
+
+	  *slash++ = '/';
+
+	  /* Avoid unnecessary calls to `stat' when given
+	     pathnames containing multiple adjacent slashes.  */
+	  while (*slash == '/')
+	    slash++;
+	}
+
+      /* We're done making leading directories.
+	 Make the final component of the path.  */
+
+      if (mkdir (dirpath, mode))
+	{
+	  error (0, errno, "cannot make directory `%s'", dirpath);
+	  umask (oldmask);
+	  return 1;
+	}
+      if (verbose_fmt_string != NULL)
+	error (0, 0, verbose_fmt_string, dirpath);
+
+      if (owner != (uid_t) -1 && group != (gid_t) -1)
+	{
+	  if (chown (dirpath, owner, group)
+#ifdef AFS
+	      && errno != EPERM
+#endif
+	      )
+	    {
+	      error (0, errno, "%s", dirpath);
+	      retval = 1;
+	    }
+	  /* chown may have turned off some permission bits we wanted.  */
+	  if ((mode & 07000) != 0 && chmod (dirpath, mode))
+	    {
+	      error (0, errno, "%s", dirpath);
+	      retval = 1;
+	    }
+	}
+
+      /* If the mode for leading directories didn't include owner "wx"
+	 privileges, we have to reset their protections to the correct
+	 value.  */
+      for (p = leading_dirs; p != NULL; p = p->next)
+	{
+	  *(p->dirname_end) = '\0';
+	  if (chmod (dirpath, parent_mode))
+	    {
+	      error (0, errno, "%s", dirpath);
+	      retval = 1;
+	    }
+	}
+    }
+  else
+    {
+      /* We get here if the entire path already exists.  */
+
+      if (!S_ISDIR (stats.st_mode))
+	{
+	  error (0, 0, "`%s' exists but is not a directory", dirpath);
+	  umask (oldmask);
+	  return 1;
+	}
+
+      /* chown must precede chmod because on some systems,
+	 chown clears the set[ug]id bits for non-superusers,
+	 resulting in incorrect permissions.
+	 On System V, users can give away files with chown and then not
+	 be able to chmod them.  So don't give files away.  */
+
+      if (owner != (uid_t) -1 && group != (gid_t) -1
+	  && chown (dirpath, owner, group)
+#ifdef AFS
+	  && errno != EPERM
+#endif
+	  )
+	{
+	  error (0, errno, "%s", dirpath);
+	  retval = 1;
+	}
+      if (chmod (dirpath, mode))
+	{
+	  error (0, errno, "%s", dirpath);
+	  retval = 1;
+	}
+    }
+
+  umask (oldmask);
+  return retval;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/mkdir.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,125 @@
+/* mkrmdir.c -- BSD compatible directory functions for System V
+   Copyright (C) 1988, 1990 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#ifndef STDC_HEADERS
+extern int errno;
+#endif
+
+/* mkdir and rmdir adapted from GNU tar.  */
+
+/* Make directory DPATH, with permission mode DMODE.
+
+   Written by Robert Rother, Mariah Corporation, August 1985
+   (sdcsvax!rmr or rmr@uscd).  If you want it, it's yours.
+
+   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.  */
+
+int
+mkdir (dpath, dmode)
+     char *dpath;
+     int dmode;
+{
+  int cpid, status;
+  struct stat statbuf;
+
+  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;
+
+  cpid = fork ();
+  switch (cpid)
+    {
+    case -1:			/* Cannot 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.
+	 This won't suffice to set SUID, SGID, etc. on this
+	 directory, so the parent process calls chmod afterward.  */
+      status = umask (0);	/* Get current umask.  */
+      umask (status | (0777 & ~dmode));	/* Set for mkdir.  */
+      execl ("/bin/mkdir", "mkdir", dpath, (char *) 0);
+      _exit (1);
+
+    default:			/* Parent process.  */
+      while (wait (&status) != cpid) /* Wait for kid to finish.  */
+	/* Do nothing.  */ ;
+
+      if (status & 0xFFFF)
+	{
+	  errno = EIO;		/* /bin/mkdir failed.  */
+	  return -1;
+	}
+      return chmod (dpath, dmode);
+    }
+}
+
+/* Remove directory DPATH.
+   Return 0 if successful, -1 if not.  */
+
+int
+rmdir (dpath)
+     char *dpath;
+{
+  int cpid, status;
+  struct stat statbuf;
+
+  if (stat (dpath, &statbuf) != 0)
+    return -1;			/* stat set errno.  */
+
+  if ((statbuf.st_mode & S_IFMT) != S_IFDIR)
+    {
+      errno = ENOTDIR;
+      return -1;
+    }
+
+  cpid = fork ();
+  switch (cpid)
+    {
+    case -1:			/* Cannot fork.  */
+      return -1;		/* errno is set already.  */
+
+    case 0:			/* Child process.  */
+      execl ("/bin/rmdir", "rmdir", dpath, (char *) 0);
+      _exit (1);
+
+    default:			/* Parent process.  */
+      while (wait (&status) != cpid) /* Wait for kid to finish.  */
+	/* Do nothing.  */ ;
+
+      if (status & 0xFFFF)
+	{
+	  errno = EIO;		/* /bin/rmdir failed.  */
+	  return -1;
+	}
+      return 0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/modechange.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,330 @@
+/* modechange.c -- file mode manipulation
+   Copyright (C) 1989, 1990 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Written by David MacKenzie <djm@ai.mit.edu> */
+
+/* The ASCII mode string is compiled into a linked list of `struct
+   modechange', which can then be applied to each file to be changed.
+   We do this instead of re-parsing the ASCII string for each file
+   because the compiled form requires less computation to use; when
+   changing the mode of many files, this probably results in a
+   performance gain. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "modechange.h"
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *malloc ();
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef S_ISDIR
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+/* Return newly allocated memory to hold one element of type TYPE. */
+#define talloc(type) ((type *) malloc (sizeof (type)))
+
+#define isodigit(c) ((c) >= '0' && (c) <= '7')
+
+static int oatoi ();
+
+/* Return a linked list of file mode change operations created from
+   MODE_STRING, an ASCII string that contains either an octal number
+   specifying an absolute mode, or symbolic mode change operations with
+   the form:
+   [ugoa...][[+-=][rwxXstugo...]...][,...]
+   MASKED_OPS is a bitmask indicating which symbolic mode operators (=+-)
+   should not affect bits set in the umask when no users are given.
+   Operators not selected in MASKED_OPS ignore the umask.
+
+   Return MODE_INVALID if `mode_string' does not contain a valid
+   representation of file mode change operations;
+   return MODE_MEMORY_EXHAUSTED if there is insufficient memory. */
+
+struct mode_change *
+mode_compile (mode_string, masked_ops)
+     register char *mode_string;
+     unsigned masked_ops;
+{
+  struct mode_change *head;	/* First element of the linked list. */
+  struct mode_change *change;	/* An element of the linked list. */
+  int i;			/* General purpose temporary. */
+  int umask_value;		/* The umask value (surprise). */
+  unsigned short affected_bits;	/* Which bits in the mode are operated on. */
+  unsigned short affected_masked; /* `affected_bits' modified by umask. */
+  unsigned ops_to_mask;		/* Operators to actually use umask on. */
+
+  i = oatoi (mode_string);
+  if (i >= 0)
+    {
+      if (i > 07777)
+	return MODE_INVALID;
+      head = talloc (struct mode_change);
+      if (head == NULL)
+	return MODE_MEMORY_EXHAUSTED;
+      head->next = NULL;
+      head->op = '=';
+      head->flags = 0;
+      head->value = i;
+      head->affected = 07777;	/* Affect all permissions. */
+      return head;
+    }
+
+  umask_value = umask (0);
+  umask (umask_value);		/* Restore the old value. */
+
+  head = NULL;
+  --mode_string;
+
+  /* One loop iteration for each "ugoa...=+-rwxXstugo...[=+-rwxXstugo...]". */
+  do
+    {
+      affected_bits = 0;
+      ops_to_mask = 0;
+      /* Turn on all the bits in `affected_bits' for each group given. */
+      for (++mode_string;; ++mode_string)
+	switch (*mode_string)
+	  {
+	  case 'u':
+	    affected_bits |= 04700;
+	    break;
+	  case 'g':
+	    affected_bits |= 02070;
+	    break;
+	  case 'o':
+	    affected_bits |= 01007;
+	    break;
+	  case 'a':
+	    affected_bits |= 07777;
+	    break;
+	  default:
+	    goto no_more_affected;
+	  }
+
+    no_more_affected:
+      /* If none specified, affect all bits, except perhaps those
+	 set in the umask. */
+      if (affected_bits == 0)
+	{
+	  affected_bits = 07777;
+	  ops_to_mask = masked_ops;
+	}
+
+      while (*mode_string == '=' || *mode_string == '+' || *mode_string == '-')
+	{
+	  /* Add the element to the tail of the list, so the operations
+	     are performed in the correct order. */
+	  if (head == NULL)
+	    {
+	      head = talloc (struct mode_change);
+	      if (head == NULL)
+		return MODE_MEMORY_EXHAUSTED;
+	      change = head;
+	    }
+	  else
+	    {
+	      change->next = talloc (struct mode_change);
+	      if (change->next == NULL)
+		{
+		  mode_free (change);
+		  return MODE_MEMORY_EXHAUSTED;
+		}
+	      change = change->next;
+	    }
+
+	  change->next = NULL;
+	  change->op = *mode_string;	/* One of "=+-". */
+	  affected_masked = affected_bits;
+	  if (ops_to_mask & (*mode_string == '=' ? MODE_MASK_EQUALS
+			     : *mode_string == '+' ? MODE_MASK_PLUS
+			     : MODE_MASK_MINUS))
+	    affected_masked &= ~umask_value;
+	  change->affected = affected_masked;
+	  change->value = 0;
+	  change->flags = 0;
+
+	  /* Set `value' according to the bits set in `affected_masked'. */
+	  for (++mode_string;; ++mode_string)
+	    switch (*mode_string)
+	      {
+	      case 'r':
+		change->value |= 00444 & affected_masked;
+		break;
+	      case 'w':
+		change->value |= 00222 & affected_masked;
+		break;
+	      case 'X':
+		change->flags |= MODE_X_IF_ANY_X;
+		/* Fall through. */
+	      case 'x':
+		change->value |= 00111 & affected_masked;
+		break;
+	      case 's':
+		/* Set the setuid/gid bits if `u' or `g' is selected. */
+		change->value |= 06000 & affected_masked;
+		break;
+	      case 't':
+		/* Set the "save text image" bit if `o' is selected. */
+		change->value |= 01000 & affected_masked;
+		break;
+	      case 'u':
+		/* Set the affected bits to the value of the `u' bits
+		   on the same file.  */
+		if (change->value)
+		  goto invalid;
+		change->value = 00700;
+		change->flags |= MODE_COPY_EXISTING;
+		break;
+	      case 'g':
+		/* Set the affected bits to the value of the `g' bits
+		   on the same file.  */
+		if (change->value)
+		  goto invalid;
+		change->value = 00070;
+		change->flags |= MODE_COPY_EXISTING;
+		break;
+	      case 'o':
+		/* Set the affected bits to the value of the `o' bits
+		   on the same file.  */
+		if (change->value)
+		  goto invalid;
+		change->value = 00007;
+		change->flags |= MODE_COPY_EXISTING;
+		break;
+	      default:
+		goto no_more_values;
+	      }
+	no_more_values:;
+	}
+  } while (*mode_string == ',');
+  if (*mode_string == 0)
+    return head;
+invalid:
+  mode_free (head);
+  return MODE_INVALID;
+}
+
+/* Return file mode OLDMODE, adjusted as indicated by the list of change
+   operations CHANGES.  If OLDMODE is a directory, the type `X'
+   change affects it even if no execute bits were set in OLDMODE.
+   The returned value has the S_IFMT bits cleared. */
+
+unsigned short
+mode_adjust (oldmode, changes)
+     unsigned oldmode;
+     register struct mode_change *changes;
+{
+  unsigned short newmode;	/* The adjusted mode and one operand. */
+  unsigned short value;		/* The other operand. */
+
+  newmode = oldmode & 07777;
+
+  for (; changes; changes = changes->next)
+    {
+      if (changes->flags & MODE_COPY_EXISTING)
+	{
+	  /* Isolate in `value' the bits in `newmode' to copy, given in
+	     the mask `changes->value'. */
+	  value = newmode & changes->value;
+
+	  if (changes->value & 00700)
+	    /* Copy `u' permissions onto `g' and `o'. */
+	    value |= (value >> 3) | (value >> 6);
+	  else if (changes->value & 00070)
+	    /* Copy `g' permissions onto `u' and `o'. */
+	    value |= (value << 3) | (value >> 3);
+	  else
+	    /* Copy `o' permissions onto `u' and `g'. */
+	    value |= (value << 3) | (value << 6);
+
+	  /* In order to change only `u', `g', or `o' permissions,
+	     or some combination thereof, clear unselected bits.
+	     This can not be done in mode_compile because the value
+	     to which the `changes->affected' mask is applied depends
+	     on the old mode of each file. */
+	  value &= changes->affected;
+	}
+      else
+	{
+	  value = changes->value;
+	  /* If `X', do not affect the execute bits if the file is not a
+	     directory and no execute bits are already set. */
+	  if ((changes->flags & MODE_X_IF_ANY_X)
+	      && !S_ISDIR (oldmode)
+	      && (newmode & 00111) == 0)
+	    value &= ~00111;	/* Clear the execute bits. */
+	}
+
+      switch (changes->op)
+	{
+	case '=':
+	  /* Preserve the previous values in `newmode' of bits that are
+	     not affected by this change operation. */
+	  newmode = (newmode & ~changes->affected) | value;
+	  break;
+	case '+':
+	  newmode |= value;
+	  break;
+	case '-':
+	  newmode &= ~value;
+	  break;
+	}
+    }
+  return newmode;
+}
+
+/* Free the memory used by the list of file mode change operations
+   CHANGES. */
+
+void
+mode_free (changes)
+     register struct mode_change *changes;
+{
+  register struct mode_change *next;
+
+  while (changes)
+    {
+      next = changes->next;
+      free (changes);
+      changes = next;
+    }
+}
+
+/* Return a positive integer containing the value of the ASCII
+   octal number S.  If S is not an octal number, return -1.  */
+
+static int
+oatoi (s)
+     char *s;
+{
+  register int i;
+
+  if (*s == 0)
+    return -1;
+  for (i = 0; isodigit (*s); ++s)
+    i = i * 8 + *s - '0';
+  if (*s)
+    return -1;
+  return i;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/modechange.h	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,55 @@
+/* modechange.h -- definitions for file mode manipulation
+   Copyright (C) 1989, 1990 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Masks for the `flags' field in a `struct mode_change'. */
+
+/* Affect the execute bits only if at least one execute bit is set already,
+   or if the file is a directory. */
+#define MODE_X_IF_ANY_X 01
+
+/* If set, copy some existing permissions for u, g, or o onto the other two.
+   Which of u, g, or o is copied is determined by which bits are set in the
+   `value' field. */
+#define MODE_COPY_EXISTING 02
+
+struct mode_change
+{
+  char op;			/* One of "=+-". */
+  char flags;			/* Special operations. */
+  unsigned short affected;	/* Set for u/g/o/s/s/t, if to be affected. */
+  unsigned short value;		/* Bits to add/remove. */
+  struct mode_change *next;	/* Link to next change in list. */
+};
+
+/* Masks for mode_compile argument. */
+#define MODE_MASK_EQUALS 1
+#define MODE_MASK_PLUS 2
+#define MODE_MASK_MINUS 4
+
+/* Error return values for mode_compile. */
+#define MODE_INVALID (struct mode_change *) 0
+#define MODE_MEMORY_EXHAUSTED (struct mode_change *) 1
+
+#ifdef __STDC__
+struct mode_change *mode_compile (char *, unsigned);
+unsigned short mode_adjust (unsigned, struct mode_change *);
+void mode_free (struct mode_change *);
+#else
+struct mode_change *mode_compile ();
+unsigned short mode_adjust ();
+void mode_free ();
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/mountlist.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,402 @@
+/* mountlist.c -- return a list of mounted filesystems
+   Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include "mountlist.h"
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+void free ();
+#endif
+#if defined(USG) || defined(STDC_HEADERS)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+char *strstr ();
+char *xmalloc ();
+char *xrealloc ();
+char *xstrdup ();
+void error ();
+
+#ifdef MOUNTED_GETMNTENT1	/* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
+#include <mntent.h>
+#if !defined(MOUNTED)
+#  if defined(MNT_MNTTAB)	/* HP-UX.  */
+#    define MOUNTED MNT_MNTTAB
+#  endif
+#  if defined(MNTTABNAME)	/* Dynix.  */
+#    define MOUNTED MNTTABNAME
+#  endif
+#endif
+#endif
+
+#ifdef MOUNTED_GETMNTINFO	/* 4.4BSD.  */
+#include <sys/mount.h>
+#endif
+
+#ifdef MOUNTED_GETMNT		/* Ultrix.  */
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/fs_types.h>
+#endif
+
+#ifdef MOUNTED_FREAD		/* SVR2.  */
+#include <mnttab.h>
+#endif
+
+#ifdef MOUNTED_FREAD_FSTYP	/* SVR3.  */
+#include <mnttab.h>
+#include <sys/fstyp.h>
+#include <sys/statfs.h>
+#endif
+
+#ifdef MOUNTED_GETMNTENT2	/* SVR4.  */
+#include <sys/mnttab.h>
+#endif
+
+#ifdef MOUNTED_VMOUNT		/* AIX.  */
+#include <fshelp.h>
+#include <sys/vfs.h>
+#endif
+
+#ifdef MOUNTED_GETMNTENT1	/* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
+/* Return the value of the hexadecimal number represented by CP.
+   No prefix (like '0x') or suffix (like 'h') is expected to be
+   part of CP. */
+
+static int
+xatoi (cp)
+     char *cp;
+{
+  int val;
+  
+  val = 0;
+  while (*cp)
+    {
+      if (*cp >= 'a' && *cp <= 'f')
+	val = val * 16 + *cp - 'a' + 10;
+      else if (*cp >= 'A' && *cp <= 'F')
+	val = val * 16 + *cp - 'A' + 10;
+      else if (*cp >= '0' && *cp <= '9')
+	val = val * 16 + *cp - '0';
+      else
+	break;
+      cp++;
+    }
+  return val;
+}
+#endif /* MOUNTED_GETMNTENT1.  */
+
+#ifdef MOUNTED_GETMNTINFO	/* 4.4BSD.  */
+static char *
+fstype_to_string (t)
+     short t;
+{
+  switch (t)
+    {
+    case MOUNT_UFS:
+      return "ufs";
+    case MOUNT_NFS:
+      return "nfs";
+    case MOUNT_PC:
+      return "pc";
+#ifdef MOUNT_MFS
+    case MOUNT_MFS:
+      return "mfs";
+#endif
+#ifdef MOUNT_LO
+    case MOUNT_LO:
+      return "lo";
+#endif
+#ifdef MOUNT_TFS
+    case MOUNT_TFS:
+      return "tfs";
+#endif
+#ifdef MOUNT_TMP
+    case MOUNT_TMP:
+      return "tmp";
+#endif
+    default:
+      return "?";
+    }
+}
+#endif /* MOUNTED_GETMNTINFO */
+
+#ifdef MOUNTED_VMOUNT		/* AIX.  */
+static char *
+fstype_to_string (t)
+     int t;
+{
+  struct vfs_ent *e;
+
+  e = getvfsbytype (t);
+  if (!e || !e->vfsent_name)
+    return "none";
+  else
+    return e->vfsent_name;
+}
+#endif /* MOUNTED_VMOUNT */
+
+/* Return a list of the currently mounted filesystems, or NULL on error.
+   Add each entry to the tail of the list so that they stay in order.
+   If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
+   the returned list are valid.  Otherwise, they might not be.
+   If ALL_FS is zero, do not return entries for filesystems that
+   are automounter (dummy) entries.  */
+
+struct mount_entry *
+read_filesystem_list (need_fs_type, all_fs)
+     int need_fs_type, all_fs;
+{
+  struct mount_entry *mount_list;
+  struct mount_entry *me;
+  struct mount_entry *mtail;
+
+  /* Start the list off with a dummy entry. */
+  me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
+  me->me_next = NULL;
+  mount_list = mtail = me;
+
+#ifdef MOUNTED_GETMNTENT1	/* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
+  {
+    struct mntent *mnt;
+    char *table = MOUNTED;
+    FILE *fp;
+    char *devopt;
+
+    fp = setmntent (table, "r");
+    if (fp == NULL)
+      return NULL;
+
+    while ((mnt = getmntent (fp)))
+      {
+	if (!all_fs && (!strcmp (mnt->mnt_type, "ignore")
+			|| !strcmp (mnt->mnt_type, "auto")))
+	  continue;
+
+	me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
+	me->me_devname = xstrdup (mnt->mnt_fsname);
+	me->me_mountdir = xstrdup (mnt->mnt_dir);
+	me->me_type = xstrdup (mnt->mnt_type);
+	devopt = strstr (mnt->mnt_opts, "dev=");
+	if (devopt)
+	  {
+	    if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
+	      me->me_dev = xatoi (devopt + 6);
+	    else
+	      me->me_dev = xatoi (devopt + 4);
+	  }
+	else
+	  me->me_dev = -1;	/* Magic; means not known yet. */
+	me->me_next = NULL;
+
+	/* Add to the linked list. */
+	mtail->me_next = me;
+	mtail = me;
+      }
+
+    if (endmntent (fp) == 0)
+      return NULL;
+  }
+#endif /* MOUNTED_GETMNTENT1. */
+
+#ifdef MOUNTED_GETMNTINFO	/* 4.4BSD.  */
+  {
+    struct statfs *fsp;
+    int entries;
+
+    entries = getmntinfo (&fsp, MNT_NOWAIT);
+    if (entries < 0)
+      return NULL;
+    while (entries-- > 0)
+      {
+	me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
+	me->me_devname = xstrdup (fsp->f_mntfromname);
+	me->me_mountdir = xstrdup (fsp->f_mntonname);
+	me->me_type = fstype_to_string (fsp->f_type);
+	me->me_dev = -1;	/* Magic; means not known yet. */
+	me->me_next = NULL;
+
+	/* Add to the linked list. */
+	mtail->me_next = me;
+	mtail = me;
+	fsp++;
+      }
+  }
+#endif /* MOUNTED_GETMNTINFO */
+
+#ifdef MOUNTED_GETMNT		/* Ultrix.  */
+  {
+    int offset = 0;
+    int val;
+    struct fs_data fsd;
+
+    while ((val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
+			  (char *) 0)) > 0)
+      {
+	me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
+	me->me_devname = xstrdup (fsd.fd_req.devname);
+	me->me_mountdir = xstrdup (fsd.fd_req.path);
+	me->me_type = gt_names[fsd.fd_req.fstype];
+	me->me_dev = fsd.fd_req.dev;
+	me->me_next = NULL;
+
+	/* Add to the linked list. */
+	mtail->me_next = me;
+	mtail = me;
+      }
+    if (val < 0)
+      return NULL;
+  }
+#endif /* MOUNTED_GETMNT. */
+
+#if defined (MOUNTED_FREAD) || defined (MOUNTED_FREAD_FSTYP) /* SVR[23].  */
+  {
+    struct mnttab mnt;
+    char *table = "/etc/mnttab";
+    FILE *fp;
+
+    fp = fopen (table, "r");
+    if (fp == NULL)
+      return NULL;
+
+    while (fread (&mnt, sizeof mnt, 1, fp) > 0)
+      {
+	me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
+#ifdef GETFSTYP			/* SVR3.  */
+	me->me_devname = xstrdup (mnt.mt_dev);
+#else
+	me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
+	strcpy (me->me_devname, "/dev/");
+	strcpy (me->me_devname + 5, mnt.mt_dev);
+#endif
+	me->me_mountdir = xstrdup (mnt.mt_filsys);
+	me->me_dev = -1;	/* Magic; means not known yet. */
+	me->me_type = "";
+#ifdef GETFSTYP			/* SVR3.  */
+	if (need_fs_type)
+	  {
+	    struct statfs fsd;
+	    char typebuf[FSTYPSZ];
+
+	    if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
+		&& sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
+	      me->me_type = xstrdup (typebuf);
+	  }
+#endif
+	me->me_next = NULL;
+
+	/* Add to the linked list. */
+	mtail->me_next = me;
+	mtail = me;
+      }
+
+    if (fclose (fp) == EOF)
+      return NULL;
+  }
+#endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP.  */
+
+#ifdef MOUNTED_GETMNTENT2	/* SVR4.  */
+  {
+    struct mnttab mnt;
+    char *table = MNTTAB;
+    FILE *fp;
+    int ret;
+
+    fp = fopen (table, "r");
+    if (fp == NULL)
+      return NULL;
+
+    while ((ret = getmntent (fp, &mnt)) == 0)
+      {
+	me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
+	me->me_devname = xstrdup (mnt.mnt_special);
+	me->me_mountdir = xstrdup (mnt.mnt_mountp);
+	me->me_type = xstrdup (mnt.mnt_fstype);
+	me->me_dev = -1;	/* Magic; means not known yet. */
+	me->me_next = NULL;
+
+	/* Add to the linked list. */
+	mtail->me_next = me;
+	mtail = me;
+      }
+
+    if (ret > 0)
+      return NULL;
+   if (fclose (fp) == EOF)
+      return NULL;
+  }
+#endif /* MOUNTED_GETMNTENT2.  */
+
+#ifdef MOUNTED_VMOUNT		/* AIX.  */
+  {
+    int bufsize;
+    char *entries, *thisent;
+    struct vmount *vmp;
+
+    /* Ask how many bytes to allocate for the mounted filesystem info.  */
+    mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
+    entries = xmalloc (bufsize);
+
+    /* Get the list of mounted filesystems.  */
+    mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
+
+    for (thisent = entries; thisent < entries + bufsize;
+	 thisent += vmp->vmt_length)
+      {
+	vmp = (struct vmount *) thisent;
+	me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
+	if (vmp->vmt_flags & MNT_REMOTE)
+	  {
+	    char *host, *path;
+
+	    /* Prepend the remote pathname.  */
+	    host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
+	    path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
+	    me->me_devname = xmalloc (strlen (host) + strlen (path) + 2);
+	    strcpy (me->me_devname, host);
+	    strcat (me->me_devname, ":");
+	    strcat (me->me_devname, path);
+	  }
+	else
+	  {
+	    me->me_devname = xstrdup (thisent + 
+				      vmp->vmt_data[VMT_OBJECT].vmt_off);
+	  }
+	me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
+	me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
+	me->me_dev = -1;	/* vmt_fsid might be the info we want.  */
+	me->me_next = NULL;
+
+	/* Add to the linked list. */
+	mtail->me_next = me;
+	mtail = me;
+      }
+    free (entries);
+  }
+#endif /* MOUNTED_VMOUNT. */
+
+  /* Free the dummy head. */
+  me = mount_list;
+  mount_list = mount_list->me_next;
+  free (me);
+  return mount_list;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/mountlist.h	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,32 @@
+/* mountlist.h -- declarations for list of mounted filesystems
+   Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* A mount table entry. */
+struct mount_entry
+{
+  char *me_devname;		/* Device node pathname, including "/dev/". */
+  char *me_mountdir;		/* Mount point directory pathname. */
+  char *me_type;		/* "nfs", "4.2", etc. */
+  dev_t me_dev;			/* Device number of me_mountdir. */
+  struct mount_entry *me_next;
+};
+
+#if __STDC__
+struct mount_entry *read_filesystem_list (int need_fs_type, int all_fs);
+#else
+struct mount_entry *read_filesystem_list ();
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/rename.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,79 @@
+/* rename.c -- BSD compatible directory function for System V
+   Copyright (C) 1988, 1990 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#ifndef STDC_HEADERS
+extern int errno;
+#endif
+
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define	S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+/* Rename file FROM to file TO.
+   Return 0 if successful, -1 if not. */
+
+int
+rename (from, to)
+     char *from;
+     char *to;
+{
+  struct stat from_stats;
+  int pid, status;
+
+  if (stat (from, &from_stats))
+    return -1;
+
+  if (unlink (to) && errno != ENOENT)
+    return -1;
+
+  if (S_ISDIR (from_stats.st_mode))
+    {
+      /* Need a setuid root process to link and unlink directories. */
+      pid = fork ();
+      switch (pid)
+	{
+	case -1:		/* Error. */
+	  error (1, errno, "cannot fork");
+
+	case 0:			/* Child. */
+	  execl (MVDIR, "mvdir", from, to, (char *) 0);
+	  error (255, errno, "cannot run `%s'", MVDIR);
+
+	default:		/* Parent. */
+	  while (wait (&status) != pid)
+	    /* Do nothing. */ ;
+
+	  errno = 0;		/* mvdir printed the system error message. */
+	  if (status)
+	    return -1;
+	}
+    }
+  else
+    {
+      if (link (from, to))
+	return -1;
+      if (unlink (from) && errno != ENOENT)
+	{
+	  unlink (to);
+	  return -1;
+	}
+    }
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/savedir.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,125 @@
+/* savedir.c -- save the list of files in a directory in a string
+   Copyright (C) 1990 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Written by David MacKenzie <djm@ai.mit.edu>. */
+
+#include <sys/types.h>
+#ifdef DIRENT
+#include <dirent.h>
+#ifdef direct
+#undef direct
+#endif
+#define direct dirent
+#define NLENGTH(direct) (strlen((direct)->d_name))
+#else
+#define NLENGTH(direct) ((direct)->d_namlen)
+#ifdef USG
+#ifdef SYSNDIR
+#include <sys/ndir.h>
+#else
+#include <ndir.h>
+#endif
+#else
+#include <sys/dir.h>
+#endif
+#endif
+
+#ifdef VOID_CLOSEDIR
+/* Fake a return value. */
+#define CLOSEDIR(d) (closedir (d), 0)
+#else
+#define CLOSEDIR(d) closedir (d)
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#else
+char *malloc ();
+char *realloc ();
+#ifndef NULL
+#define NULL 0
+#endif
+#endif
+
+char *stpcpy ();
+
+/* Return a freshly allocated string containing the filenames
+   in directory DIR, separated by '\0' characters;
+   the end is marked by two '\0' characters in a row.
+   NAME_SIZE is the number of bytes to initially allocate
+   for the string; it will be enlarged as needed.
+   Return NULL if DIR cannot be opened or if out of memory. */
+
+char *
+savedir (dir, name_size)
+     char *dir;
+     unsigned name_size;
+{
+  DIR *dirp;
+  struct direct *dp;
+  char *name_space;
+  char *namep;
+
+  dirp = opendir (dir);
+  if (dirp == NULL)
+    return NULL;
+
+  name_space = (char *) malloc (name_size);
+  if (name_space == NULL)
+    {
+      closedir (dirp);
+      return NULL;
+    }
+  namep = name_space;
+
+  while ((dp = readdir (dirp)) != NULL)
+    {
+      /* Skip "." and ".." (some NFS filesystems' directories lack them). */
+      if (dp->d_name[0] != '.'
+	  || (dp->d_name[1] != '\0'
+	      && (dp->d_name[1] != '.' || dp->d_name[2] != '\0')))
+	{
+	  unsigned size_needed = (namep - name_space) + NLENGTH (dp) + 2;
+
+	  if (size_needed > name_size)
+	    {
+	      char *new_name_space;
+
+	      while (size_needed > name_size)
+		name_size += 1024;
+
+	      new_name_space = realloc (name_space, name_size);
+	      if (new_name_space == NULL)
+		{
+		  closedir (dirp);
+		  return NULL;
+		}
+	      namep += new_name_space - name_space;
+	      name_space = new_name_space;
+	    }
+	  namep = stpcpy (namep, dp->d_name) + 1;
+	}
+    }
+  *namep = '\0';
+  if (CLOSEDIR (dirp))
+    {
+      free (name_space);
+      return NULL;
+    }
+  return name_space;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/stpcpy.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,30 @@
+/* stpcpy.c -- copy a string and return pointer to end of new string
+    Copyright (C) 1989, 1990 Free Software Foundation.
+
+    This program 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 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 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Copy SOURCE into DEST, stopping after copying the first '\0', and
+   return a pointer to the '\0' at the end of DEST;
+   in other words, return DEST + strlen (SOURCE). */
+
+char *
+stpcpy (dest, source)
+     char *dest;
+     char *source;
+{
+  while ((*dest++ = *source++) != '\0')
+    /* Do nothing. */ ;
+  return dest - 1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/strdup.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,43 @@
+/* strdup.c -- return a newly allocated copy of a string
+   Copyright (C) 1990 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifdef STDC_HEADERS
+#include <string.h>
+#include <stdlib.h>
+#else
+char *malloc ();
+char *strcpy ();
+#endif
+
+#if !__STDC__
+#define const
+#endif
+
+/* Return a newly allocated copy of STR,
+   or 0 if out of memory. */
+
+char *
+strdup (str)
+     const char *str;
+{
+  char *newstr;
+
+  newstr = (char *) malloc (strlen (str) + 1);
+  if (newstr)
+    strcpy (newstr, str);
+  return newstr;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/stripslash.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,39 @@
+/* stripslash.c -- remove trailing slashes from a string
+   Copyright (C) 1990 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#if defined(STDC_HEADERS) || defined(USG)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/* Remove trailing slashes from PATH.
+   This is useful when using filename completion from a shell that
+   adds a "/" after directory names (such as tcsh and bash), because
+   the Unix rename and rmdir system calls return an "Invalid argument" error
+   when given a path that ends in "/" (except for the root directory).  */
+
+void
+strip_trailing_slashes (path)
+     char *path;
+{
+  int last;
+
+  last = strlen (path) - 1;
+  while (last > 0 && path[last] == '/')
+    path[last--] = '\0';
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/strstr.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,49 @@
+/* strstr.c -- return the offset of one string within another
+   Copyright (C) 1989, 1990 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Author:
+	Mike Rendell			Department of Computer Science
+	michael@garfield.mun.edu	Memorial University of Newfoundland
+	..!uunet!garfield!michael	St. John's, Nfld., Canada
+	(709) 737-4550			A1C 5S7
+*/
+
+/* Return the starting address of string S2 in S1;
+   return 0 if it is not found. */
+
+char *
+strstr (s1, s2)
+     char *s1;
+     char *s2;
+{
+  int i;
+  char *p1;
+  char *p2;
+  char *s = s1;
+
+  for (p2 = s2, i = 0; *s; p2 = s2, i++, s++)
+    {
+      for (p1 = s; *p1 && *p2 && *p1 == *p2; p1++, p2++)
+	;
+      if (!*p2)
+	break;
+    }
+  if (!*p2)
+    return s1 + i;
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/userspec.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,178 @@
+/* userspec.c -- Parse a user and group string.
+   Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>.  */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+#if defined(USG) || defined(STDC_HEADERS)
+#include <string.h>
+#define index strchr
+#else
+#include <strings.h>
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *malloc ();
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifndef _POSIX_VERSION
+struct passwd *getpwnam ();
+struct group *getgrnam ();
+struct group *getgrgid ();
+#endif
+
+#ifdef _POSIX_SOURCE
+#define endpwent()
+#define endgrent()
+#endif
+
+#define isdigit(c) ((c) >= '0' && (c) <= '9')
+
+char *strdup ();
+static int isnumber ();
+
+/* Extract from NAME, which has the form "[user][:.][group]",
+   a USERNAME, UID U, GROUPNAME, and GID G.
+   Either user or group, or both, must be present.
+   If the group is omitted but the ":" or "." separator is given,
+   use the given user's login group.
+
+   USERNAME and GROUPNAME will be in newly malloc'd memory.
+   Either one might be NULL instead, indicating that it was not
+   given and the corresponding numeric ID was left unchanged.
+   Might write NULs into NAME.
+
+   Return NULL if successful, a static error message string if not.  */
+
+char *
+parse_user_spec (name, uid, gid, username, groupname)
+     char *name;
+     uid_t *uid;
+     gid_t *gid;
+     char **username, **groupname;
+{
+  static char *tired = "virtual memory exhausted";
+  struct passwd *pwd;
+  struct group *grp;
+  char *cp;
+  int use_login_group = 0;
+
+  *username = *groupname = NULL;
+
+  /* Check whether a group is given.  */
+  cp = index (name, ':');
+  if (cp == NULL)
+    cp = index (name, '.');
+  if (cp != NULL)
+    {
+      *cp++ = '\0';
+      if (*cp == '\0')
+	{
+	  if (cp == name + 1)
+	    /* Neither user nor group given, just "." or ":".  */
+	    return "can not omit both user and group";
+	  else
+	    /* "user.".  */
+	    use_login_group = 1;
+	}
+      else
+	{
+	  /* Explicit group.  */
+	  *groupname = strdup (cp);
+	  if (*groupname == NULL)
+	    return tired;
+	  grp = getgrnam (cp);
+	  if (grp == NULL)
+	    {
+	      if (!isnumber (cp))
+		return "invalid group";
+	      *gid = atoi (cp);
+	    }
+	  else
+	    *gid = grp->gr_gid;
+	  endgrent ();		/* Save a file descriptor.  */
+	}
+    }
+
+  /* Parse the user name, now that any group has been removed.  */
+
+  if (name[0] == '\0')
+    /* No user name was given, just a group.  */
+    return NULL;
+
+  *username = strdup (name);
+  if (*username == NULL)
+    return tired;
+
+  pwd = getpwnam (name);
+  if (pwd == NULL)
+    {
+      if (!isnumber (name))
+	return "invalid user";
+      if (use_login_group)
+	return "cannot get the login group of a numeric UID";
+      *uid = atoi (name);
+    }
+  else
+    {
+      *uid = pwd->pw_uid;
+      if (use_login_group)
+	{
+	  *gid = pwd->pw_gid;
+	  grp = getgrgid (pwd->pw_gid);
+	  if (grp == NULL)
+	    {
+	      *groupname = malloc (15);
+	      if (*groupname == NULL)
+		return tired;
+	      sprintf (*groupname, "%u", pwd->pw_gid);
+	    }
+	  else
+	    {
+	      *groupname = strdup (grp->gr_name);
+	      if (*groupname == NULL)
+		return tired;
+	    }
+	  endgrent ();
+	}
+    }
+  endpwent ();
+  return NULL;
+}
+
+/* Return nonzero if STR represents an unsigned decimal integer,
+   otherwise return 0. */
+
+static int
+isnumber (str)
+     char *str;
+{
+  for (; *str; str++)
+    if (!isdigit (*str))
+      return 0;
+  return 1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/xstrdup.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,32 @@
+/* xstrdup.c -- copy a string with out of memory checking
+   Copyright (C) 1990 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#if defined(USG) || defined(STDC_HEADERS)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+char *xmalloc ();
+
+/* Return a newly allocated copy of STRING.  */
+
+char *
+xstrdup (string)
+     char *string;
+{
+  return strcpy (xmalloc (strlen (string) + 1), string);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/yesno.c	Sat Oct 31 20:42:48 1992 +0000
@@ -0,0 +1,37 @@
+/* yesno.c -- read a yes/no response from stdin
+   Copyright (C) 1990 Free Software Foundation, Inc.
+
+   This program 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 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 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <stdio.h>
+
+/* Read one line from standard input
+   and return nonzero if that line begins with y or Y,
+   otherwise return 0. */
+
+int
+yesno ()
+{
+  int c;
+  int rv;
+
+  fflush (stderr);
+  c = getchar ();
+  rv = (c == 'y') || (c == 'Y');
+  while (c != EOF && c != '\n')
+    c = getchar ();
+
+  return rv;
+}