home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / bin / mv / mv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-08  |  6.4 KB  |  260 lines

  1. /*
  2.  * Copyright (c) 1989 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Ken Smith of The State University of New York at Buffalo.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. char copyright[] =
  39. "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
  40.  All rights reserved.\n";
  41. #endif /* not lint */
  42.  
  43. #ifndef lint
  44. static char sccsid[] = "@(#)mv.c    5.11 (Berkeley) 4/3/91";
  45. #endif /* not lint */
  46.  
  47. #include <sys/param.h>
  48. #include <sys/time.h>
  49. #include <sys/wait.h>
  50. #include <sys/stat.h>
  51. #include <fcntl.h>
  52. #include <errno.h>
  53. #include <unistd.h>
  54. #include <stdio.h>
  55. #include <stdlib.h>
  56. #include <string.h>
  57. #include "pathnames.h"
  58.  
  59. int fflg, iflg;
  60.  
  61. main(argc, argv)
  62.     int argc;
  63.     char **argv;
  64. {
  65.     extern char *optarg;
  66.     extern int optind;
  67.     register int baselen, exitval, len;
  68.     register char *p, *endp;
  69.     struct stat sb;
  70.     int ch;
  71.     char path[MAXPATHLEN + 1];
  72.  
  73.     while (((ch = getopt(argc, argv, "-if")) != EOF))
  74.         switch((char)ch) {
  75.         case 'i':
  76.             iflg = 1;
  77.             break;
  78.         case 'f':
  79.             fflg = 1;
  80.             break;
  81.         case '-':        /* undocumented; for compatibility */
  82.             goto endarg;
  83.         case '?':
  84.         default:
  85.             usage();
  86.         }
  87. endarg:    argc -= optind;
  88.     argv += optind;
  89.  
  90.     if (argc < 2)
  91.         usage();
  92.  
  93.     /*
  94.      * If the stat on the target fails or the target isn't a directory,
  95.      * try the move.  More than 2 arguments is an error in this case.
  96.      */
  97.     if (stat(argv[argc - 1], &sb) || !S_ISDIR(sb.st_mode)) {
  98.         if (argc > 2)
  99.             usage();
  100.         exit(do_move(argv[0], argv[1]));
  101.     }
  102.  
  103.     /* It's a directory, move each file into it. */
  104.     (void)strcpy(path, argv[argc - 1]);
  105.     baselen = strlen(path);
  106.     endp = &path[baselen];
  107.     *endp++ = '/';
  108.     ++baselen;
  109.     for (exitval = 0; --argc; ++argv) {
  110.         if ((p = rindex(*argv, '/')) == NULL)
  111.             p = *argv;
  112.         else
  113.             ++p;
  114.         if ((baselen + (len = strlen(p))) >= MAXPATHLEN)
  115.             (void)fprintf(stderr,
  116.                 "mv: %s: destination pathname too long\n", *argv);
  117.         else {
  118.             bcopy(p, endp, len + 1);
  119.             exitval |= do_move(*argv, path);
  120.         }
  121.     }
  122.     exit(exitval);
  123. }
  124.  
  125. do_move(from, to)
  126.     char *from, *to;
  127. {
  128.     struct stat sb;
  129.     int ask, ch;
  130.  
  131.     /*
  132.      * Check access.  If interactive and file exists, ask user if it
  133.      * should be replaced.  Otherwise if file exists but isn't writable
  134.      * make sure the user wants to clobber it.
  135.      */
  136.     if (!fflg && !access(to, F_OK)) {
  137.         ask = 0;
  138.         if (iflg) {
  139.             (void)fprintf(stderr, "overwrite %s? ", to);
  140.             ask = 1;
  141.         }
  142.         else if (access(to, W_OK) && !stat(to, &sb)) {
  143.             (void)fprintf(stderr, "override mode %o on %s? ",
  144.                 sb.st_mode & 07777, to);
  145.             ask = 1;
  146.         }
  147.         if (ask) {
  148.             if ((ch = getchar()) != EOF && ch != '\n')
  149.                 while (getchar() != '\n');
  150.             if (ch != 'y')
  151.                 return(0);
  152.         }
  153.     }
  154.     if (!rename(from, to))
  155.         return(0);
  156.  
  157.     if (errno != EXDEV) {
  158.         (void)fprintf(stderr,
  159.             "mv: rename %s to %s: %s\n", from, to, strerror(errno));
  160.         return(1);
  161.     }
  162.  
  163.     /*
  164.      * If rename fails, and it's a regular file, do the copy internally;
  165.      * otherwise, use cp and rm.
  166.      */
  167.     if (stat(from, &sb)) {
  168.         (void)fprintf(stderr, "mv: %s: %s\n", from, strerror(errno));
  169.         return(1);
  170.     }
  171.     return(S_ISREG(sb.st_mode) ?
  172.         fastcopy(from, to, &sb) : copy(from, to));
  173. }
  174.  
  175. fastcopy(from, to, sbp)
  176.     char *from, *to;
  177.     struct stat *sbp;
  178. {
  179.     struct timeval tval[2];
  180.     static u_int blen;
  181.     static char *bp;
  182.     register int nread, from_fd, to_fd;
  183.  
  184.     if ((from_fd = open(from, O_RDONLY, 0)) < 0) {
  185.         error(from);
  186.         return(1);
  187.     }
  188.     if ((to_fd = open(to, O_CREAT|O_TRUNC|O_WRONLY, sbp->st_mode)) < 0) {
  189.         error(to);
  190.         (void)close(from_fd);
  191.         return(1);
  192.     }
  193.     if (!blen && !(bp = malloc(blen = sbp->st_blksize))) {
  194.         error(NULL);
  195.         return(1);
  196.     }
  197.     while ((nread = read(from_fd, bp, blen)) > 0)
  198.         if (write(to_fd, bp, nread) != nread) {
  199.             error(to);
  200.             goto err;
  201.         }
  202.     if (nread < 0) {
  203.         error(from);
  204. err:        (void)unlink(to);
  205.         (void)close(from_fd);
  206.         (void)close(to_fd);
  207.         return(1);
  208.     }
  209.     (void)fchown(to_fd, sbp->st_uid, sbp->st_gid);
  210.     (void)fchmod(to_fd, sbp->st_mode);
  211.  
  212.     (void)close(from_fd);
  213.     (void)close(to_fd);
  214.  
  215.     tval[0].tv_sec = sbp->st_atime;
  216.     tval[1].tv_sec = sbp->st_mtime;
  217.     tval[0].tv_usec = tval[1].tv_usec = 0;
  218.     (void)utimes(to, tval);
  219.     (void)unlink(from);
  220.     return(0);
  221. }
  222.  
  223. copy(from, to)
  224.     char *from, *to;
  225. {
  226.     int pid, status;
  227.  
  228.     if (!(pid = vfork())) {
  229.         execl(_PATH_CP, "mv", "-pr", from, to, NULL);
  230.         error(_PATH_CP);
  231.         _exit(1);
  232.     }
  233.     (void)waitpid(pid, &status, 0);
  234.     if (!WIFEXITED(status) || WEXITSTATUS(status))
  235.         return(1);
  236.     if (!(pid = vfork())) {
  237.         execl(_PATH_RM, "mv", "-rf", from, NULL);
  238.         error(_PATH_RM);
  239.         _exit(1);
  240.     }
  241.     (void)waitpid(pid, &status, 0);
  242.     return(!WIFEXITED(status) || WEXITSTATUS(status));
  243. }
  244.  
  245. error(s)
  246.     char *s;
  247. {
  248.     if (s)
  249.         (void)fprintf(stderr, "mv: %s: %s\n", s, strerror(errno));
  250.     else
  251.         (void)fprintf(stderr, "mv: %s\n", strerror(errno));
  252. }
  253.  
  254. usage()
  255. {
  256.     (void)fprintf(stderr,
  257. "usage: mv [-if] src target;\n   or: mv [-if] src1 ... srcN directory\n");
  258.     exit(1);
  259. }
  260.