Increase size of space for ACL in "up" command.
[openafs.git] / src / venus / up.c
index f612431..9334f0f 100644 (file)
@@ -1,70 +1,44 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
  */
 
-/* missing type from C language */
-#define Boolean short
-#define true 1
-#define false 0
+#include <afsconfig.h>
+#include <afs/param.h>
 
-/* ************************************************************* */
+#include <roken.h>
 
-#include <afs/param.h>
-#include <errno.h>
-#ifdef AFS_AIX32_ENV
-#include <signal.h>
-#undef _NONSTD_TYPES
-#endif
-#include <stdio.h>
 #include <afs/afs_args.h>
-#include <sys/param.h>
-#ifdef AFS_SUN5_ENV
-#include <fcntl.h>
-#endif
-#include <sys/file.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#include <sys/time.h>
 #define VIRTUE
 #define VICE
-#include <sys/ioctl.h>
 #include <afs/vice.h>
 #undef VIRTUE
 #undef VICE
-#include <sys/ioctl.h>
-#include <netdb.h>      
 #include <afs/venus.h>
+#include <afs/sys_prototypes.h>
+#include <afs/afsutil.h>
+#include <afs/afs_consts.h>
 
 /* ************************************************************* */
 
-#define MAXACL 400
-
-extern char *index ();
-extern char *rindex ();
-#if !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
-extern sys_nerr;
-extern char *sys_errlist[];
-#endif
+#define MAXACL AFS_PIOCTL_MAXSIZE
 
-Boolean   verbose = false;
-Boolean   renameTargets = false;
-Boolean   oneLevel = false;
-Boolean   preserveDate = true; 
-Boolean   preserveMountPoints = false;
-Boolean   forceOverwrite = false;
+short verbose = 0;
+short renameTargets = 0;
+short oneLevel = 0;
+short preserveDate = 1;
+short preserveMountPoints = 0;
+short forceOverwrite = 0;
 
-int   pageSize;
-Boolean setacl = true;
-Boolean oldAcl = false;
+short setacl = 1;
+short oldAcl = 0;
 char file1[MAXPATHLEN], file2[MAXPATHLEN];
 
-#define        MAXSIZE 2048
-static char space[MAXSIZE];
+static char space[AFS_PIOCTL_MAXSIZE];
 
 struct OldAcl {
     int nplus;
@@ -73,6 +47,12 @@ struct OldAcl {
     char data[1];
 };
 
+static void ScanArgs(int argc, char *argv[]);
+static short MakeParent(char *file, afs_int32 owner);
+static int Copy(char *file1, char *file2, short recursive, int level);
+static int isMountPoint(char *name, struct ViceIoctl *blob);
+
+
 /* ************************************************************ */
 /*                                                              */
 /* main program                                                         */
@@ -81,125 +61,123 @@ struct OldAcl {
 
 #include "AFS_component_version_number.c"
 
-main(argc, argv)
-    int argc;
-    char *argv[];
-
+int
+main(int argc, char *argv[])
 {
 #ifdef AFS_AIX32_ENV
     /*
-     * The following signal action for AIX is necessary so that in case of a 
-     * crash (i.e. core is generated) we can include the user's data section 
+     * The following signal action for AIX is necessary so that in case of a
+     * crash (i.e. core is generated) we can include the user's data section
      * in the core dump. Unfortunately, by default, only a partial core is
      * generated which, in many cases, isn't too useful.
      */
     struct sigaction nsa;
-    
+
     sigemptyset(&nsa.sa_mask);
     nsa.sa_handler = SIG_DFL;
     nsa.sa_flags = SA_FULLDUMP;
     sigaction(SIGSEGV, &nsa, NULL);
 #endif
-#if !defined (AFS_AIX_ENV) && !defined (AFS_HPUX_ENV)
-    pageSize = getpagesize();
-#endif
     ScanArgs(argc, argv);
-    
+
     /* now read each line of the CopyList */
     if (Copy(file1, file2, !oneLevel, 0))
-       exit(1);        /* some type of failure */
+       return(1);              /* some type of failure */
 
-    exit(0);
+    return(0);
 }
 
 
-ScanArgs(argc, argv)
-    int argc;
-    char *argv[];
-
+#define USAGE "usage: up [-v1frxm] from to\n"
+static void
+ScanArgs(int argc, char *argv[])
 {
     /* skip program name */
     argc--, argv++;
-    
+
     /* check for -flag options */
     while (argc > 0 && *argv[0] == '-') {
-        char *cp = *argv;
+       char *cp = *argv;
+
+       if (strlen(cp) > 2) {
+           goto badoption;
+       }
 
-        switch (*++cp) {
-         case 'v':
-           verbose = true;
+       switch (*++cp) {
+       case 'v':
+           verbose = 1;
            break;
-           
-         case '1':
-           oneLevel = true;
+
+       case '1':
+           oneLevel = 1;
            break;
-           
-         case 'r':
-           renameTargets = true;
+
+       case 'r':
+           renameTargets = 1;
            break;
-           
-         case 'f':
-           forceOverwrite = true;
+
+       case 'f':
+           forceOverwrite = 1;
            break;
-           
-         case 'x':
-           preserveDate = false;
+
+       case 'x':
+           preserveDate = 0;
            break;
-           
-         case 'm':
-           preserveMountPoints = true;
+
+       case 'm':
+           preserveMountPoints = 1;
            break;
-           
-         default: 
-           fprintf(stderr, "Unknown option: '%c'\n", *cp);
-           fprintf(stderr, "usage: up [-v1frxm] from to\n");
+
+       default:
+           cp--;
+
+ badoption:
+           fprintf(stderr, "Unknown option: '%s'\n", cp);
+           fprintf(stderr, USAGE);
            exit(1);
        }
        argc--, argv++;
     }
 
     if (argc != 2) {
-        fprintf(stderr, "usage: up [-v1frx] from to\n");
-        exit(1);
+       fprintf(stderr, USAGE);
+       exit(1);
     }
 
     strncpy(file1, argv[0], MAXPATHLEN);
     strncpy(file2, argv[1], MAXPATHLEN);
 
-} /*ScanArgs*/
+}                              /*ScanArgs */
 
 
 
 /*
  * MakeParent
  *     Make sure the parent directory of this file exists.  Returns
- *     true if it exists, false otherwise.  Note: the owner argument
+ *     1 if it exists, 0 otherwise.  Note: the owner argument
  *     is a hack.  All directories made will have this owner.
  */
-Boolean MakeParent(file, owner)
-    char *file;
-    afs_int32 owner;
+static short
+MakeParent(char *file, afs_int32 owner)
 {
-    char  parent[MAXPATHLEN];
+    char parent[MAXPATHLEN];
     char *p;
     struct stat s;
-    
-    strcpy(parent, file);
-    
-    p = rindex(parent, '/');
+
+    strlcpy(parent, file, sizeof parent);
+
+    p = strrchr(parent, '/');
     if (!p) {
-       strcpy(parent, ".");
-    }
-    else if (p > parent) {
-        *p = '\0';
-    }
-    else {
+       strlcpy(parent, ".", sizeof parent);
+    } else if (p > parent) {
+       *p = '\0';
+    } else {
        p[1] = '\0';
     }
-    
+
     if (stat(parent, &s) < 0) {
        if (!MakeParent(parent, owner))
-            return(false);
+           return (0);
 
        if (verbose) {
            printf("Creating directory %s\n", parent);
@@ -209,8 +187,8 @@ Boolean MakeParent(file, owner)
        mkdir(parent, 0777);
        chown(parent, owner, -1);
     }
-    return(true);
-} /*MakeParent*/
+    return (1);
+}                              /*MakeParent */
 
 
 /*
@@ -218,518 +196,564 @@ Boolean MakeParent(file, owner)
  *     This does the bulk of the work of the program.  Handle one file,
  *     possibly copying subfiles if this is a directory
  */
-Copy(file1, file2, recursive, level)
-    char *file1;       /* input file name */
-    char *file2;       /* output file name */
-    Boolean recursive; /* true if directory should be copied */
-    int level;         /* level of recursion: 0, 1, ... */
-
+static int
+Copy(char *file1, char *file2, short recursive, int level)
 {
-    struct stat s1, s2;        /*Stat blocks*/
+    struct stat s1, s2;                /*Stat blocks */
     struct ViceIoctl blob;
     char aclspace[MAXACL];
     afs_int32 rcode = 0, code;
-    int   goods2 = 1;
+    int goods2 = 1;
 
     code = lstat(file1, &s1);
     if (code < 0) {
-       fprintf(stderr,"Can't find %s\n",file1);
-       return 1;
+       fprintf(stderr, "Can't find %s\n", file1);
+       return 1;
     }
 
     code = lstat(file2, &s2);
     if (code < 0) {
-       if (!MakeParent(file2,s1.st_uid))
-         return 0;
-       goods2 = 0;
+       if (!MakeParent(file2, s1.st_uid))
+           return 0;
+       goods2 = 0;
     }
 
     if ((s1.st_mode & S_IFMT) == S_IFREG) {
-       /*
-       * -------------------- Copy regular file --------------------
-       */
-       int    f1, f2, n;
-       char   buf[4096];                       /* Must be bigger than sizeof (*head) */
-       struct timeval tv[2];
-       char   tmpfile[MAXPATHLEN], newName[MAXPATHLEN];
-       
-       if (verbose) {
-         printf("Level %d: File %s to %s\n", level, file1, file2);
-         fflush(stdout);
-       }
-
-       /* Wonder if there is a security hole */
-       if ( ((s1.st_mode & 04002) == 04002) ||
-           ((s1.st_mode & 04020) == 04020) ||
-           ((s1.st_mode & 02002) == 02002) ) {
-         fprintf(stderr, "WARNING: Mode-bits security hole in files %s and %s\n",
-                 file1, file2);
-       }
-
-       if (!goods2 || (s1.st_mtime != s2.st_mtime) || (s1.st_size != s2.st_size)) { /*c*/
-         /* Don't ovewrite a write protected file (unless force: -f) */
-         if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
-            fprintf(stderr,
-                    "File %s is write protected against its owner; not changed\n",
-                    file2);
-            return 1;
-         }
-
-         if (verbose) {
-            printf("  Copy file %s to %s (%u Bytes)\n", file1, file2, s1.st_size);
-            fflush(stdout);
-         }
-
-         strcpy(tmpfile, file2);        /* Name of temporary file */
-         strcat(tmpfile,".UPD");
-
-         /* open file1 for input */
-         f1 = open(file1, O_RDONLY);
-         if (f1 < 0) {
-            fprintf(stderr, "Unable to open input file %s, ", file1);
-            if (errno >= sys_nerr)
-               fprintf(stderr, "error code = %d\n", errno);
-            else
-               fprintf(stderr, "%s\n", sys_errlist[errno]);
-            return 1;
-         }
-
-         /* open temporary output file */
-         f2 = open(tmpfile, (O_WRONLY | O_CREAT | O_TRUNC), s1.st_mode);
-         if (f2 < 0) {
-            fprintf(stderr, "Unable to open output file %s, ", tmpfile);
-            if (errno >= sys_nerr)
-               fprintf(stderr, "error code = %d\n", errno);
-            else
-               fprintf(stderr, "%s\n", sys_errlist[errno]);
-            fflush(stdout);
-            close(f1);
-            return 1;
-          }
-       
-         /* Copy file1 to temporary file */
-         while ((n = read(f1, buf, sizeof(buf))) > 0) {
-            if (write(f2, buf, n) != n) {
-               fprintf(stderr,"Write failed, file %s must be copied again.\n", file2);
-            }
-         }
-
-         /* preserve access and modification times: ("-x" disables)*/
-         if (preserveDate) {
-            tv[0].tv_sec = s1.st_atime;
-            tv[0].tv_usec = 0;
-            tv[1].tv_sec = s1.st_mtime;
-            tv[1].tv_usec = 0;
-            utimes(tmpfile, tv);
-         }
-
-         /* Close the files */
-         code = close(f1);
-         code = close(f2);
-         if (code < 0) {
-            perror("close ");
-            rcode = 1;
-         }
-
-         /* Rename file2 to file2.old. [-r] */
-         if (renameTargets && goods2) {
-            strcpy(newName, file2);
-            strcat(newName, ".old");
-            if (verbose) {
-               printf("  Renaming %s to %s\n", file2, newName);
+       /*
+        * -------------------- Copy regular file --------------------
+        */
+       int f1, f2, n;
+       char buf[4096];         /* Must be bigger than sizeof (*head) */
+       struct timeval tv[2];
+       char tmpfile[MAXPATHLEN], newName[MAXPATHLEN];
+
+       if (verbose) {
+           printf("Level %d: File %s to %s\n", level, file1, file2);
+           fflush(stdout);
+       }
+
+       /* Wonder if there is a security hole */
+       if (((s1.st_mode & 04002) == 04002) || ((s1.st_mode & 04020) == 04020)
+           || ((s1.st_mode & 02002) == 02002)) {
+           fprintf(stderr,
+                   "WARNING: Mode-bits security hole in files %s and %s\n",
+                   file1, file2);
+       }
+
+       if (!goods2 || (s1.st_mtime != s2.st_mtime) || (s1.st_size != s2.st_size)) {    /*c */
+           /* Don't ovewrite a write protected file (unless force: -f) */
+           if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
+               fprintf(stderr,
+                       "File %s is write protected against its owner; not changed\n",
+                       file2);
+               return 1;
+           }
+
+           if (verbose) {
+               printf("  Copy file %s to %s (%u Bytes)\n", file1, file2,
+                      (unsigned int) s1.st_size);
                fflush(stdout);
-            }
-            if (rename(file2, newName) < 0) {
-               fprintf(stderr, "Rename of %s to %s failed.\n", file2, newName);
-            }
-         }
-
-         /* Rename temporary file to file2 */
-         code = rename(tmpfile, file2);
-         if (code < 0) {
-            fprintf(stderr, "Rename of %s to %s failed.\n", tmpfile, file2);
-            return 1;
-         }
-
-         /* Re-stat file2 and compare file sizes */
-         code = lstat(file2, &s2);
-         if (code < 0) {
-            fprintf(stderr, "WARNING: Unable to stat new file %s\n", file2);
-            return 1;
-         }
-         if (s1.st_size != s2.st_size) {
-            fprintf(stderr, "WARNING: New file %s is %u bytes long; should be %u\n",
-                   file2, s2.st_size, s1.st_size);
-         }
-       } /*c*/
-
-       /* Set the user-id */
-       if (s2.st_uid != s1.st_uid) {
-         if (verbose) {
-            printf("  Set owner-id for %s to %d\n", file2, s1.st_uid);
-            fflush(stdout);
-         }
-         code = chown(file2, s1.st_uid, -1);
-         if (code) {
-            fprintf(stderr, "Unable to set owner-id for %s to %d\n", file2, s1.st_uid);
-            fflush(stdout);
-            rcode = 1;
-            s1.st_mode &= ~04000;       /* Don't set suid bit */
-         }
-       }
-
-       /* Set the group-id */
-       if (s2.st_gid != s1.st_gid) {
-         if (verbose) {
-            printf("  Set group-id for %s to %d\n", file2, s1.st_gid);
-            fflush(stdout);
-         }
-         code = chown(file2, -1, s1.st_gid);
-         if (code) {
-            fprintf(stderr, "Unable to set group-id for %s to %d\n", file2, s1.st_gid);
-            fflush(stdout);
-            rcode = 1;
-            s1.st_mode &= ~02000;       /* Don't set sgid bit */
-         }
-       }
-
-       /* Set the mode bits */
-       if (s1.st_mode != s2.st_mode) {
-         if (verbose) {
-            printf("  Set mode-bit for %s to %o\n", file2, (s1.st_mode & 07777));
-            fflush(stdout);
-         }
-         code = chmod(file2, s1.st_mode);
-         if (code) {
-            fprintf(stderr, "Unable to set mode-bits for %s to %d\n", file2, s1.st_mode);
-            rcode = 1;
-         }
-       }
-    } /* regular file */
+           }
 
-    else if ((s1.st_mode & S_IFMT) == S_IFLNK) {
-       /*
-       * --------------------- Copy symlink  --------------------
-       */
-       char linkvalue[MAXPATHLEN+1];
-       int  n;
-
-       if (verbose) {
-         printf("Level %d: Symbolic link %s to %s\n", level, file1, file2);
-         fflush(stdout);
-       }
-       
-       /* Don't ovewrite a write protected directory (unless force: -f) */
-       if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
-         fprintf(stderr,
-                 "Link %s is write protected against its owner; not changed\n",
-                 file2);
-         return 1;
-       }
-       
-       if (verbose) {
-         printf("  Copy symbolic link %s->%s to %s\n", file1, linkvalue, file2);
-         fflush(stdout);
-       }
-       
-       n = readlink(file1, linkvalue, sizeof(linkvalue));
-       if (n == -1) {
-         fprintf(stderr, "Could not read symbolic link %s\n", file1);
-         perror("read link ");
-         return 1;
-       }
-       linkvalue[n] = 0;
-
-       unlink(file2);  /* Always make the new link (it was easier) */
-
-       code = symlink(linkvalue, file2);
-       if (code == -1) {
-         fprintf(stderr, "Could not create symbolic link %s\n", file2);
-         perror("create link ");
-         return 1;
-       }
-    } /*Dealing with symlink*/
-    
-    else if ( preserveMountPoints && (code=isMountPoint( file1, &blob )) ) {
-       /*
-       * --------------------- Copy mount point  --------------------
-       */
-
-       if ( code > 1 ) {
-          perror("checking for mount point ");
-          return 1;
-       }
-       if (verbose) {
-         printf("Level %d: Mount point %s to %s\n", level, file1, file2);
-         fflush(stdout);
-       }
-       
-       /* Don't ovewrite a write protected directory (unless force: -f) */
-       if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
-         fprintf(stderr,
-                 "Target %s is write protected against its owner; not changed\n",
-                 file2);
-         return 1;
-       }
-       
-       if (verbose) {
-         printf("  Copy mount point %s for vol %s to %s\n", file1, blob.out, file2);
-         fflush(stdout);
-       }
-       
-       unlink(file2);  /* Always make the new link (it was easier) */
-
-       strcat(blob.out, ".");          /* stupid convention; these end with a period */
-       code = symlink(blob.out, file2);
-       if (code == -1) {
-         fprintf(stderr, "Could not create mount point %s for vol %s\n", file2, blob.out);
-         perror("create mount point ");
-         return 1;
-       }
-       
-    } /*Dealing with mount point*/
-
-    else if (((s1.st_mode & S_IFMT) == S_IFDIR) && (recursive || (level == 0))) {
-       /*
-       * ----------------------- Copy directory -----------------------
-       */
-       DIR           *dir;
-       int           tfd, code, i;
-       struct OldAcl *oacl;
-       char          tacl[MAXACL];
-       char          f1[MAXPATHLEN], f2[MAXPATHLEN];
-       char          *p1, *p2;
-       struct dirent *d;
-
-       if (verbose) {
-         printf("Level %d: Directory %s to %s\n", level, file1, file2);
-         fflush(stdout);
-       }
-
-       /* Don't ovewrite a write protected directory (unless force: -f) */
-       if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
-         fprintf(stderr,
-                 "Directory %s is write protected against its owner; not changed\n",
-                 file2);
-         return 1;
-       }
-
-       strcpy(f1, file1);
-       strcpy(f2, file2);
-       p1 = f1 + strlen(f1);
-       p2 = f2 + strlen(f2);
-       if (p1 == f1 || p1[-1] != '/')
-         *p1++ = '/';
-       if (p2 == f2 || p2[-1] != '/')
-         *p2++ = '/';
-
-       dir = opendir(file1);
-       if (dir == NULL) {
-         fprintf(stderr, "Couldn't open %s\n", file1);
-         return 1;
-       }
-
-       while ((d = readdir(dir)) != NULL) {
-         if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
-            continue;
-         strcpy(p1, d->d_name);
-         strcpy(p2, d->d_name);
-         code = Copy(f1, f2, recursive, level + 1);
-         if (code && !rcode) rcode = 1;                 /* remember errors */
-       }
-
-       closedir(dir);
-
-       if (verbose) {
-         printf("Level %d: Copied directory %s to %s\n", level, file1, file2);
-         fflush(stdout);
-       }
-
-       mkdir(file2, 0777);     /* Handle case where MakeParent not invoked. */
-
-       if (verbose) {
-         printf("  Set owner-id for %s to %d\n", file2, s1.st_uid);
-         fflush(stdout);
-       }
-       code = chown(file2, s1.st_uid, -1);
-       if (code) {
-         fprintf(stderr, "Unable to set owner-id for %s to %d\n", file2, s1.st_uid);
-         fflush(stdout);
-         s1.st_mode &= ~04000;       /* Don't set suid bit */
-       }
-
-       if (verbose) {
-         printf("  Set group-id for %s to %d\n", file2, s1.st_gid);
-         fflush(stdout);
-       }
-       code = chown(file2, -1, s1.st_gid);
-       if (code) {
-         fprintf(stderr, "Unable to set group-id for %s to %d\n", file2, s1.st_gid);
-         fflush(stdout);
-         s1.st_mode &= ~02000;       /* Don't set sgid bit */
-       }
-
-       if (verbose) {
-         printf("  Set mode-bit for %s to %o\n", file2, (s1.st_mode & 07777));
-         fflush(stdout);
-       }
-       code = chmod(file2, s1.st_mode);
-       if (code) {
-         fprintf(stderr, "Unable to set mode-bits for %s to %d\n", file2, s1.st_mode);
-         fflush(stdout);
-         rcode = 1;
-       }
-
-       if (setacl == true) {
-         if (verbose) {
-            printf("  Set acls for %s\n", file2);
-            fflush(stdout);
-         }
-
-         blob.in       = aclspace;
-         blob.out      = aclspace;
-         blob.in_size  = 0;
-         blob.out_size = MAXACL;
-
-         if (oldAcl) {
-            /* Get an old-style ACL and convert it */
-            for (i=1; i<strlen(file1); i++)
-               if (file1[i] == '/') break;
-            strcpy(aclspace, &file1[i]);
-
-            blob.in_size = 1+strlen(aclspace);
-            tfd = open(file1, O_RDONLY, 0);
-            if (tfd < 0) {
-               perror("old-acl open ");
+           strlcpy(tmpfile, file2, sizeof tmpfile);    /* Name of temporary file */
+           strlcat(tmpfile, ".UPD", sizeof tmpfile);
+
+           /* open file1 for input */
+           f1 = open(file1, O_RDONLY);
+           if (f1 < 0) {
+               fprintf(stderr, "Unable to open input file %s: %s\n",
+                       file1, strerror(errno));
+               return 1;
+           }
+
+           /* open temporary output file */
+           f2 = open(tmpfile, (O_WRONLY | O_CREAT | O_TRUNC), s1.st_mode);
+           if (f2 < 0) {
+               fprintf(stderr, "Unable to open output file %s: %s\n",
+                       tmpfile, strerror(errno));
+               fflush(stdout);
+               close(f1);
                return 1;
-            }
-            code = ioctl(tfd, _VICEIOCTL(4), &blob);
-            close(tfd);
-            if (code < 0) {
-               if (errno == EINVAL) {
-                  setacl = false;
+           }
+
+           /* Copy file1 to temporary file */
+           while ((n = read(f1, buf, sizeof(buf))) > 0) {
+               if (write(f2, buf, n) != n) {
+                   fprintf(stderr,
+                           "Write failed, file %s must be copied again.\n",
+                           file2);
                }
-               else {
-                  return 1;
+           }
+
+           /* preserve access and modification times: ("-x" disables) */
+           if (preserveDate) {
+               tv[0].tv_sec = s1.st_atime;
+               tv[0].tv_usec = 0;
+               tv[1].tv_sec = s1.st_mtime;
+               tv[1].tv_usec = 0;
+               utimes(tmpfile, tv);
+           }
+
+           /* Close the files */
+           code = close(f1);
+           if (code < 0) {
+               perror("close ");
+               rcode = 1;
+           }
+           code = close(f2);
+           if (code < 0) {
+               perror("close ");
+               rcode = 1;
+           }
+
+           /* Rename file2 to file2.old. [-r] */
+           if (renameTargets && goods2) {
+               strlcpy(newName, file2, sizeof newName);
+               strlcat(newName, ".old", sizeof newName);
+               if (verbose) {
+                   printf("  Renaming %s to %s\n", file2, newName);
+                   fflush(stdout);
                }
-            }
-            /* Now convert the thing. */
-            oacl = (struct OldAcl *) (aclspace+4);
-            sprintf(tacl, "%d\n%d\n", oacl->nplus, oacl->nminus);
-            strcat(tacl, oacl->data);
-            strcpy(aclspace, tacl);
-         } /*Grab and convert old-style ACL*/
-         else {
-            /* Get a new-style ACL */
-            code = pioctl(file1, _VICEIOCTL(2), &blob, 1);
-            if (code < 0) {
-               if (errno == EINVAL) {
-                  setacl = false;
+               if (rename(file2, newName) < 0) {
+                   fprintf(stderr, "Rename of %s to %s failed.\n", file2,
+                           newName);
+               }
+           }
+
+           /* Rename temporary file to file2 */
+           code = rename(tmpfile, file2);
+           if (code < 0) {
+               fprintf(stderr, "Rename of %s to %s failed.\n", tmpfile,
+                       file2);
+               return 1;
+           }
+
+           /* Re-stat file2 and compare file sizes */
+           code = lstat(file2, &s2);
+           if (code < 0) {
+               fprintf(stderr, "WARNING: Unable to stat new file %s\n",
+                       file2);
+               return 1;
+           }
+           if (s1.st_size != s2.st_size) {
+               fprintf(stderr,
+                       "WARNING: New file %s is %u bytes long; should be %u\n",
+                       file2, (unsigned int) s2.st_size,
+                       (unsigned int) s1.st_size);
+           }
+       }
+
+       /*c */
+       /* Set the user-id */
+       if (s2.st_uid != s1.st_uid) {
+           if (verbose) {
+               printf("  Set owner-id for %s to %d\n", file2, s1.st_uid);
+               fflush(stdout);
+           }
+           code = chown(file2, s1.st_uid, -1);
+           if (code) {
+               fprintf(stderr, "Unable to set owner-id for %s to %d\n",
+                       file2, s1.st_uid);
+               fflush(stdout);
+               rcode = 1;
+               s1.st_mode &= ~04000;   /* Don't set suid bit */
+           }
+       }
+
+       /* Set the group-id */
+       if (s2.st_gid != s1.st_gid) {
+           if (verbose) {
+               printf("  Set group-id for %s to %d\n", file2, s1.st_gid);
+               fflush(stdout);
+           }
+           code = chown(file2, -1, s1.st_gid);
+           if (code) {
+               fprintf(stderr, "Unable to set group-id for %s to %d\n",
+                       file2, s1.st_gid);
+               fflush(stdout);
+               rcode = 1;
+               s1.st_mode &= ~02000;   /* Don't set sgid bit */
+           }
+       }
+
+       /* Set the mode bits */
+       if (s1.st_mode != s2.st_mode) {
+           if (verbose) {
+               printf("  Set mode-bit for %s to %o\n", file2,
+                      (s1.st_mode & 07777));
+               fflush(stdout);
+           }
+           code = chmod(file2, s1.st_mode);
+           if (code) {
+               fprintf(stderr, "Unable to set mode-bits for %s to %d\n",
+                       file2, s1.st_mode);
+               rcode = 1;
+           }
+       }
+    }
+    /* regular file */
+    else if ((s1.st_mode & S_IFMT) == S_IFLNK) {
+       /*
+        * --------------------- Copy symlink  --------------------
+        */
+       char linkvalue[MAXPATHLEN + 1];
+       int n;
+
+       if (verbose) {
+           printf("Level %d: Symbolic link %s to %s\n", level, file1, file2);
+           fflush(stdout);
+       }
+
+       /* Don't ovewrite a write protected directory (unless force: -f) */
+       if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
+           fprintf(stderr,
+                   "Link %s is write protected against its owner; not changed\n",
+                   file2);
+           return 1;
+       }
+
+       if (verbose) {
+           printf("  Copy symbolic link %s->%s to %s\n", file1, linkvalue,
+                  file2);
+           fflush(stdout);
+       }
+
+       n = readlink(file1, linkvalue, sizeof(linkvalue)-1);
+       if (n == -1) {
+           fprintf(stderr, "Could not read symbolic link %s\n", file1);
+           perror("read link ");
+           return 1;
+       }
+       linkvalue[n] = 0;
+
+       unlink(file2);          /* Always make the new link (it was easier) */
+
+       code = symlink(linkvalue, file2);
+       if (code == -1) {
+           fprintf(stderr, "Could not create symbolic link %s\n", file2);
+           perror("create link ");
+           return 1;
+       }
+    }
+    /*Dealing with symlink */
+    else if (preserveMountPoints && (code = isMountPoint(file1, &blob))) {
+       /*
+        * --------------------- Copy mount point  --------------------
+        */
+
+       if (code > 1) {
+           perror("checking for mount point ");
+           return 1;
+       }
+       if (verbose) {
+           printf("Level %d: Mount point %s to %s\n", level, file1, file2);
+           fflush(stdout);
+       }
+
+       /* Don't ovewrite a write protected directory (unless force: -f) */
+       if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
+           fprintf(stderr,
+                   "Target %s is write protected against its owner; not changed\n",
+                   file2);
+           return 1;
+       }
+
+       if (verbose) {
+           printf("  Copy mount point %s for vol %s to %s\n", file1,
+                  blob.out, file2);
+           fflush(stdout);
+       }
+
+       unlink(file2);          /* Always make the new link (it was easier) */
+
+       strcat(blob.out, ".");  /* stupid convention; these end with a period */
+       code = symlink(blob.out, file2);
+       if (code == -1) {
+           fprintf(stderr, "Could not create mount point %s for vol %s\n",
+                   file2, blob.out);
+           perror("create mount point ");
+           return 1;
+       }
+
+    }
+    /*Dealing with mount point */
+    else if (((s1.st_mode & S_IFMT) == S_IFDIR)
+            && (recursive || (level == 0))) {
+       /*
+        * ----------------------- Copy directory -----------------------
+        */
+       DIR *dir;
+       int tfd, code, i;
+       struct OldAcl *oacl;
+       char tacl[MAXACL];
+       char f1[MAXPATHLEN], f2[MAXPATHLEN];
+       char *p1, *p2;
+       struct dirent *d;
+       struct timeval tv[2];
+
+       if (verbose) {
+           printf("Level %d: Directory %s to %s\n", level, file1, file2);
+           fflush(stdout);
+       }
+
+       /* Don't ovewrite a write protected directory (unless force: -f) */
+       if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
+           fprintf(stderr,
+                   "Directory %s is write protected against its owner; not changed\n",
+                   file2);
+           return 1;
+       }
+
+       strlcpy(f1, file1, sizeof f1);
+       strlcpy(f2, file2, sizeof f2);
+       p1 = f1 + strlen(f1);
+       p2 = f2 + strlen(f2);
+       if (p1 == f1 || p1[-1] != '/')
+           *p1++ = '/';
+       if (p2 == f2 || p2[-1] != '/')
+           *p2++ = '/';
+
+       dir = opendir(file1);
+       if (dir == NULL) {
+           fprintf(stderr, "Couldn't open %s\n", file1);
+           return 1;
+       }
+
+       while ((d = readdir(dir)) != NULL) {
+           if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
+               continue;
+           strlcpy(p1, d->d_name, sizeof f1 - (p1 - f1));
+           strlcpy(p2, d->d_name, sizeof f2 - (p2 - f2));
+           code = Copy(f1, f2, recursive, level + 1);
+           if (code && !rcode)
+               rcode = 1;      /* remember errors */
+       }
+
+       closedir(dir);
+
+       if (verbose) {
+           printf("Level %d: Copied directory %s to %s\n", level, file1,
+                  file2);
+           fflush(stdout);
+       }
+
+       mkdir(file2, 0777);     /* Handle case where MakeParent not invoked. */
+
+       if (verbose) {
+           printf("  Set owner-id for %s to %d\n", file2, s1.st_uid);
+           fflush(stdout);
+       }
+       code = chown(file2, s1.st_uid, -1);
+       if (code) {
+           fprintf(stderr, "Unable to set owner-id for %s to %d\n", file2,
+                   s1.st_uid);
+           fflush(stdout);
+           s1.st_mode &= ~04000;       /* Don't set suid bit */
+       }
+
+       if (verbose) {
+           printf("  Set group-id for %s to %d\n", file2, s1.st_gid);
+           fflush(stdout);
+       }
+       code = chown(file2, -1, s1.st_gid);
+       if (code) {
+           fprintf(stderr, "Unable to set group-id for %s to %d\n", file2,
+                   s1.st_gid);
+           fflush(stdout);
+           s1.st_mode &= ~02000;       /* Don't set sgid bit */
+       }
+
+       if (verbose) {
+           printf("  Set mode-bit for %s to %o\n", file2,
+                  (s1.st_mode & 07777));
+           fflush(stdout);
+       }
+       code = chmod(file2, s1.st_mode);
+       if (code) {
+           fprintf(stderr, "Unable to set mode-bits for %s to %d\n", file2,
+                   s1.st_mode);
+           fflush(stdout);
+           rcode = 1;
+       }
+
+       if (setacl == 1) {
+           if (verbose) {
+               printf("  Set acls for %s\n", file2);
+               fflush(stdout);
+           }
+
+           blob.in = aclspace;
+           blob.out = aclspace;
+           blob.in_size = 0;
+           blob.out_size = MAXACL;
+
+           if (oldAcl) {
+               /* Get an old-style ACL and convert it */
+                if (verbose) {
+                    printf("  Getting old style acl\n");
+                    fflush(stdout);
+                }
+
+               for (i = 1; i < strlen(file1); i++)
+                   if (file1[i] == '/')
+                       break;
+               strlcpy(aclspace, &file1[i], sizeof aclspace);
+
+               blob.in_size = 1 + strlen(aclspace);
+               tfd = open(file1, O_RDONLY, 0);
+               if (tfd < 0) {
+                   perror("old-acl open ");
+                   return 1;
                }
-               else {
-                  perror("getacl ");
-                  return 1;
+               code = ioctl(tfd, _VICEIOCTL(4), &blob);
+               close(tfd);
+               if (code < 0) {
+                   if (errno == EINVAL) {
+                       setacl = 0;
+                        if (verbose) {
+                            printf("  _VICEIOCTL(4) returns EINVAL\n");
+                            fflush(stdout);
+                        }
+                   } else {
+                       return 1;
+                   }
                }
-            }
-         } /*Grab new-style ACL*/
-
-         /*
-          * Now, set the new-style ACL.
-          */
-         if (setacl == true) {
-            blob.out      = aclspace;
-            blob.in       = aclspace;
-            blob.out_size = 0;
-            blob.in_size  = 1+strlen(aclspace);
-            code = pioctl(file2, _VICEIOCTL(1), &blob, 1);
-            if (code) {
-               if (errno == EINVAL) {
-                  setacl = false;
+               /* Now convert the thing. */
+               oacl = (struct OldAcl *)(aclspace + 4);
+               sprintf(tacl, "%d\n%d\n", oacl->nplus, oacl->nminus);
+               strlcat(tacl, oacl->data, sizeof tacl);
+               strlcpy(aclspace, tacl, sizeof aclspace);
+           } /*Grab and convert old-style ACL */
+           else {
+               /* Get a new-style ACL */
+                if (verbose) {
+                    printf("  Getting new style acl\n");
+                    fflush(stdout);
+                }
+
+               code = pioctl(file1, _VICEIOCTL(2), &blob, 1);
+               if (code < 0) {
+                   if (errno == EINVAL) {
+                       setacl = 0;
+                        if (verbose) {
+                            printf("  _VICEIOCTL(2) returns EINVAL\n");
+                            fflush(stdout);
+                        }
+                   } else {
+                       perror("getacl ");
+                       return 1;
+                   }
                }
-               else {
-                  fprintf(stderr, "Couldn't set acls for %s\n", file2);
-                  return 1;
+           }                   /*Grab new-style ACL */
+
+           /*
+            * Now, set the new-style ACL.
+            */
+           if (setacl == 1) {
+                if (verbose) {
+                    printf("  Setting new style acl\n");
+                    fflush(stdout);
+                }
+               blob.out = aclspace;
+               blob.in = aclspace;
+               blob.out_size = 0;
+               blob.in_size = 1 + strlen(aclspace);
+               code = pioctl(file2, _VICEIOCTL(1), &blob, 1);
+               if (code) {
+                   if (errno == EINVAL) {
+                       setacl = 0;
+                        if (verbose) {
+                            printf("  _VICEIOCTL(1) returns EINVAL\n");
+                            fflush(stdout);
+                        }
+                   } else {
+                       fprintf(stderr, "Couldn't set acls for %s\n", file2);
+                       return 1;
+                   }
                }
-            }
-         }
+           }
 
-         if (setacl == false) {
-            printf("Not setting acls\n");
-         }
-       }
+           if (setacl == 0) {
+               printf("Not setting acls\n");
+           }
+       }
+
+        /* preserve access and modification times: ("-x" disables) */
+        if (preserveDate) {
+            tv[0].tv_sec = s1.st_atime;
+            tv[0].tv_usec = 0;
+            tv[1].tv_sec = s1.st_mtime;
+            tv[1].tv_usec = 0;
+            utimes(file2, tv);
+        }
     }
 
     return rcode;
-} /*Copy*/
+}                              /*Copy */
 
 
-int isMountPoint( name, blob )
-    char *name;
-    struct ViceIoctl *blob;
+static int
+isMountPoint(char *name, struct ViceIoctl *blob)
 {
-    afs_int32  code;
-    char true_name[1024];              /*dirname*/
-    char parent_dir[1024];             /*Parent directory of true name*/
-    char *last_component;              /*Last component of true name*/
+    afs_int32 code;
+    char true_name[1024];      /*dirname */
+    char parent_dir[1024];     /*Parent directory of true name */
+    char *last_component;      /*Last component of true name */
 
-    sprintf(true_name, "%s%s",
-            (name[0] == '/') ? "" : "./",
-            name);
+    sprintf(true_name, "%s%s", (name[0] == '/') ? "" : "./", name);
 
     /*
      * Find rightmost slash, if any.
      */
-    last_component = (char *) rindex(true_name, '/');
+    last_component = (char *)strrchr(true_name, '/');
     if (last_component) {
-        /*
-         * Found it.  Designate everything before it as the parent directory,
-         * everything after it as the final component.
-         */
-        strncpy(parent_dir, true_name, last_component - true_name);
-        parent_dir[last_component - true_name] = 0;
-        last_component++;   /*Skip the slash*/
-    }
-    else {
-        /*
-         * No slash appears in the given file name.  Set parent_dir to the current
-         * directory, and the last component as the given name.
-         */
-        strcpy(parent_dir, ".");
-        last_component = true_name;
+       /*
+        * Found it.  Designate everything before it as the parent directory,
+        * everything after it as the final component.
+        */
+       strncpy(parent_dir, true_name, last_component - true_name);
+       parent_dir[last_component - true_name] = 0;
+       last_component++;       /*Skip the slash */
+    } else {
+       /*
+        * No slash appears in the given file name.  Set parent_dir to the current
+        * directory, and the last component as the given name.
+        */
+       strlcpy(parent_dir, ".", sizeof parent_dir);
+       last_component = true_name;
     }
 
     if (strcmp(last_component, ".") == 0 || strcmp(last_component, "..") == 0) {
-        fprintf(stderr, "up: you may not use '.' or '..' as the last component\n");
-        fprintf(stderr, "up: of a name in the 'up' command.\n");
-        return 3;
+       fprintf(stderr,
+               "up: you may not use '.' or '..' as the last component\n");
+       fprintf(stderr, "up: of a name in the 'up' command.\n");
+       return 3;
     }
 
     blob->in = last_component;
-    blob->in_size = strlen(last_component)+1;
-    blob->out_size = MAXSIZE;
+    blob->in_size = strlen(last_component) + 1;
+    blob->out_size = AFS_PIOCTL_MAXSIZE;
     blob->out = space;
-    bzero(space, MAXSIZE);
+    memset(space, 0, AFS_PIOCTL_MAXSIZE);
 
     code = pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, blob, 0);
 
     if (code == 0) {
-        printf("'%s' is a mount point for volume '%s'\n", name, space);
-        fflush(stdout);
-        return 1;
-    }
-    else {
-        if (errno == EINVAL) {
-            /* printf( "'%s' is not a mount point.\n", name);
+       printf("'%s' is a mount point for volume '%s'\n", name, space);
+       fflush(stdout);
+       return 1;
+    } else {
+       if (errno == EINVAL) {
+           /* printf( "'%s' is not a mount point.\n", name);
             * fflush(stdout);
             */
-            return 0;
-        }
-        else {
-            fprintf( stderr, "problem examining '%s' in '%s'.\n", last_component, parent_dir );
-            return 2;
-            /* Die(errno, (ti->data ? ti->data : parent_dir));
-             */
-        }
+           return 0;
+       } else {
+           fprintf(stderr, "problem examining '%s' in '%s'.\n",
+                   last_component, parent_dir);
+           return 2;
+           /* Die(errno, (ti->data ? ti->data : parent_dir));
+            */
+       }
     }
-    return 4;
 }