1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  28 /*        All Rights Reserved   */
  29 
  30 /*
  31  * University Copyright- Copyright (c) 1982, 1986, 1988
  32  * The Regents of the University of California
  33  * All Rights Reserved
  34  *
  35  * University Acknowledgment- Portions of this document are derived from
  36  * software developed by the University of California, Berkeley, and its
  37  * contributors.
  38  */
  39 
  40 #pragma ident   "%Z%%M% %I%     %E% SMI"
  41 
  42 #include "libcmdutils.h"
  43 
  44 
  45 int
  46 writefile(int fi, int fo, char *infile, char *outfile, char *asfile,
  47     char *atfile, struct stat *s1p, struct stat *s2p)
  48 {
  49         int mapsize, munmapsize;
  50         caddr_t cp;
  51         off_t filesize = s1p->st_size;
  52         off_t offset;
  53         int nbytes;
  54         int remains;
  55         int n;
  56         size_t src_size;
  57         size_t targ_size;
  58         char *srcbuf;
  59         char *targbuf;
  60 
  61         if (asfile != NULL) {
  62                 src_size = strlen(infile) + strlen(asfile) +
  63                     strlen(dgettext(TEXT_DOMAIN, " attribute ")) + 1;
  64         } else {
  65                 src_size = strlen(infile) + 1;
  66         }
  67         srcbuf = malloc(src_size);
  68         if (srcbuf == NULL) {
  69                 (void) fprintf(stderr,
  70                     dgettext(TEXT_DOMAIN, "could not allocate memory"
  71                     " for path buffer: "));
  72                 return (1);
  73         }
  74         if (asfile != NULL) {
  75                 (void) snprintf(srcbuf, src_size, "%s%s%s",
  76                     infile, dgettext(TEXT_DOMAIN, " attribute "), asfile);
  77         } else {
  78                 (void) snprintf(srcbuf, src_size, "%s", infile);
  79         }
  80 
  81         if (atfile != NULL) {
  82                 targ_size = strlen(outfile) + strlen(atfile) +
  83                     strlen(dgettext(TEXT_DOMAIN, " attribute ")) + 1;
  84         } else {
  85                 targ_size = strlen(outfile) + 1;
  86         }
  87         targbuf = malloc(targ_size);
  88         if (targbuf == NULL) {
  89                 (void) fprintf(stderr,
  90                     dgettext(TEXT_DOMAIN, "could not allocate memory"
  91                     " for path buffer: "));
  92                 return (1);
  93         }
  94         if (atfile != NULL) {
  95                 (void) snprintf(targbuf, targ_size, "%s%s%s",
  96                     outfile, dgettext(TEXT_DOMAIN, " attribute "), atfile);
  97         } else {
  98                 (void) snprintf(targbuf, targ_size, "%s", outfile);
  99         }
 100 
 101         if (ISREG(*s1p) && s1p->st_size > SMALLFILESIZE) {
 102                 /*
 103                  * Determine size of initial mapping.  This will determine the
 104                  * size of the address space chunk we work with.  This initial
 105                  * mapping size will be used to perform munmap() in the future.
 106                  */
 107                 mapsize = MAXMAPSIZE;
 108                 if (s1p->st_size < mapsize) mapsize = s1p->st_size;
 109                 munmapsize = mapsize;
 110 
 111                 /*
 112                  * Mmap time!
 113                  */
 114                 if ((cp = mmap((caddr_t)NULL, mapsize, PROT_READ,
 115                     MAP_SHARED, fi, (off_t)0)) == MAP_FAILED)
 116                         mapsize = 0;   /* can't mmap today */
 117         } else
 118                 mapsize = 0;
 119 
 120         if (mapsize != 0) {
 121                 offset = 0;
 122 
 123                 for (;;) {
 124                         nbytes = write(fo, cp, mapsize);
 125                         /*
 126                          * if we write less than the mmaped size it's due to a
 127                          * media error on the input file or out of space on
 128                          * the output file.  So, try again, and look for errno.
 129                          */
 130                         if ((nbytes >= 0) && (nbytes != (int)mapsize)) {
 131                                 remains = mapsize - nbytes;
 132                                 while (remains > 0) {
 133                                         nbytes = write(fo,
 134                                             cp + mapsize - remains, remains);
 135                                         if (nbytes < 0) {
 136                                                 if (errno == ENOSPC)
 137                                                         perror(targbuf);
 138                                                 else
 139                                                         perror(srcbuf);
 140                                                 (void) close(fi);
 141                                                 (void) close(fo);
 142                                                 (void) munmap(cp, munmapsize);
 143                                                 if (ISREG(*s2p))
 144                                                         (void) unlink(targbuf);
 145                                                 return (1);
 146                                         }
 147                                         remains -= nbytes;
 148                                         if (remains == 0)
 149                                                 nbytes = mapsize;
 150                                 }
 151                         }
 152                         /*
 153                          * although the write manual page doesn't specify this
 154                          * as a possible errno, it is set when the nfs read
 155                          * via the mmap'ed file is accessed, so report the
 156                          * problem as a source access problem, not a target file
 157                          * problem
 158                          */
 159                         if (nbytes < 0) {
 160                                 if (errno == EACCES)
 161                                         perror(srcbuf);
 162                                 else
 163                                         perror(targbuf);
 164                                 (void) close(fi);
 165                                 (void) close(fo);
 166                                 (void) munmap(cp, munmapsize);
 167                                 if (ISREG(*s2p))
 168                                         (void) unlink(targbuf);
 169                                 if (srcbuf != NULL)
 170                                         free(srcbuf);
 171                                 if (targbuf != NULL)
 172                                         free(targbuf);
 173                                 return (1);
 174                         }
 175                         filesize -= nbytes;
 176                         if (filesize == 0)
 177                                 break;
 178                         offset += nbytes;
 179                         if (filesize < mapsize)
 180                                 mapsize = filesize;
 181                         if (mmap(cp, mapsize, PROT_READ, MAP_SHARED |
 182                             MAP_FIXED, fi, offset) == MAP_FAILED) {
 183                                 perror(srcbuf);
 184                                 (void) close(fi);
 185                                 (void) close(fo);
 186                                 (void) munmap(cp, munmapsize);
 187                                 if (ISREG(*s2p))
 188                                         (void) unlink(targbuf);
 189                                 if (srcbuf != NULL)
 190                                         free(srcbuf);
 191                                 if (targbuf != NULL)
 192                                         free(targbuf);
 193                                 return (1);
 194                         }
 195                 }
 196                 (void) munmap(cp, munmapsize);
 197         } else {
 198                 char buf[SMALLFILESIZE];
 199                 for (;;) {
 200                         n = read(fi, buf, sizeof (buf));
 201                         if (n == 0) {
 202                                 return (0);
 203                         } else if (n < 0) {
 204                                 (void) close(fi);
 205                                 (void) close(fo);
 206                                 if (ISREG(*s2p))
 207                                         (void) unlink(targbuf);
 208                                 if (srcbuf != NULL)
 209                                         free(srcbuf);
 210                                 if (targbuf != NULL)
 211                                         free(targbuf);
 212                                 return (1);
 213                         } else if (write(fo, buf, n) != n) {
 214                                 (void) close(fi);
 215                                 (void) close(fo);
 216                                 if (ISREG(*s2p))
 217                                         (void) unlink(targbuf);
 218                                 if (srcbuf != NULL)
 219                                         free(srcbuf);
 220                                 if (targbuf != NULL)
 221                                         free(targbuf);
 222                                 return (1);
 223                         }
 224                 }
 225         }
 226         if (srcbuf != NULL)
 227                 free(srcbuf);
 228         if (targbuf != NULL)
 229                 free(targbuf);
 230         return (0);
 231 }