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 #include "libcmdutils.h"
  41 
  42 
  43 int
  44 writefile(int fi, int fo, char *infile, char *outfile, char *asfile,
  45     char *atfile, struct stat *s1p, struct stat *s2p)
  46 {
  47         int mapsize, munmapsize;
  48         caddr_t cp;
  49         off_t filesize = s1p->st_size;
  50         off_t offset;
  51         int nbytes;
  52         int remains;
  53         int n;
  54         size_t src_size;
  55         size_t targ_size;
  56         char *srcbuf;
  57         char *targbuf;
  58 
  59         if (asfile != NULL) {
  60                 src_size = strlen(infile) + strlen(asfile) +
  61                     strlen(dgettext(TEXT_DOMAIN, " attribute ")) + 1;
  62         } else {
  63                 src_size = strlen(infile) + 1;
  64         }
  65         srcbuf = malloc(src_size);
  66         if (srcbuf == NULL) {
  67                 (void) fprintf(stderr,
  68                     dgettext(TEXT_DOMAIN, "could not allocate memory"
  69                     " for path buffer: "));
  70                 return (1);
  71         }
  72         if (asfile != NULL) {
  73                 (void) snprintf(srcbuf, src_size, "%s%s%s",
  74                     infile, dgettext(TEXT_DOMAIN, " attribute "), asfile);
  75         } else {
  76                 (void) snprintf(srcbuf, src_size, "%s", infile);
  77         }
  78 
  79         if (atfile != NULL) {
  80                 targ_size = strlen(outfile) + strlen(atfile) +
  81                     strlen(dgettext(TEXT_DOMAIN, " attribute ")) + 1;
  82         } else {
  83                 targ_size = strlen(outfile) + 1;
  84         }
  85         targbuf = malloc(targ_size);
  86         if (targbuf == NULL) {
  87                 (void) fprintf(stderr,
  88                     dgettext(TEXT_DOMAIN, "could not allocate memory"
  89                     " for path buffer: "));
  90                 return (1);
  91         }
  92         if (atfile != NULL) {
  93                 (void) snprintf(targbuf, targ_size, "%s%s%s",
  94                     outfile, dgettext(TEXT_DOMAIN, " attribute "), atfile);
  95         } else {
  96                 (void) snprintf(targbuf, targ_size, "%s", outfile);
  97         }
  98 
  99         if (S_ISREG(s1p->st_mode) && s1p->st_size > SMALLFILESIZE) {
 100                 /*
 101                  * Determine size of initial mapping.  This will determine the
 102                  * size of the address space chunk we work with.  This initial
 103                  * mapping size will be used to perform munmap() in the future.
 104                  */
 105                 mapsize = MAXMAPSIZE;
 106                 if (s1p->st_size < mapsize) mapsize = s1p->st_size;
 107                 munmapsize = mapsize;
 108 
 109                 /*
 110                  * Mmap time!
 111                  */
 112                 if ((cp = mmap((caddr_t)NULL, mapsize, PROT_READ,
 113                     MAP_SHARED, fi, (off_t)0)) == MAP_FAILED)
 114                         mapsize = 0;   /* can't mmap today */
 115         } else
 116                 mapsize = 0;
 117 
 118         if (mapsize != 0) {
 119                 offset = 0;
 120 
 121                 for (;;) {
 122                         nbytes = write(fo, cp, mapsize);
 123                         /*
 124                          * if we write less than the mmaped size it's due to a
 125                          * media error on the input file or out of space on
 126                          * the output file.  So, try again, and look for errno.
 127                          */
 128                         if ((nbytes >= 0) && (nbytes != (int)mapsize)) {
 129                                 remains = mapsize - nbytes;
 130                                 while (remains > 0) {
 131                                         nbytes = write(fo,
 132                                             cp + mapsize - remains, remains);
 133                                         if (nbytes < 0) {
 134                                                 if (errno == ENOSPC)
 135                                                         perror(targbuf);
 136                                                 else
 137                                                         perror(srcbuf);
 138                                                 (void) close(fi);
 139                                                 (void) close(fo);
 140                                                 (void) munmap(cp, munmapsize);
 141                                                 if (S_ISREG(s2p->st_mode))
 142                                                         (void) unlink(targbuf);
 143                                                 return (1);
 144                                         }
 145                                         remains -= nbytes;
 146                                         if (remains == 0)
 147                                                 nbytes = mapsize;
 148                                 }
 149                         }
 150                         /*
 151                          * although the write manual page doesn't specify this
 152                          * as a possible errno, it is set when the nfs read
 153                          * via the mmap'ed file is accessed, so report the
 154                          * problem as a source access problem, not a target file
 155                          * problem
 156                          */
 157                         if (nbytes < 0) {
 158                                 if (errno == EACCES)
 159                                         perror(srcbuf);
 160                                 else
 161                                         perror(targbuf);
 162                                 (void) close(fi);
 163                                 (void) close(fo);
 164                                 (void) munmap(cp, munmapsize);
 165                                 if (S_ISREG(s2p->st_mode))
 166                                         (void) unlink(targbuf);
 167                                 if (srcbuf != NULL)
 168                                         free(srcbuf);
 169                                 if (targbuf != NULL)
 170                                         free(targbuf);
 171                                 return (1);
 172                         }
 173                         filesize -= nbytes;
 174                         if (filesize == 0)
 175                                 break;
 176                         offset += nbytes;
 177                         if (filesize < mapsize)
 178                                 mapsize = filesize;
 179                         if (mmap(cp, mapsize, PROT_READ, MAP_SHARED |
 180                             MAP_FIXED, fi, offset) == MAP_FAILED) {
 181                                 perror(srcbuf);
 182                                 (void) close(fi);
 183                                 (void) close(fo);
 184                                 (void) munmap(cp, munmapsize);
 185                                 if (S_ISREG(s2p->st_mode))
 186                                         (void) unlink(targbuf);
 187                                 if (srcbuf != NULL)
 188                                         free(srcbuf);
 189                                 if (targbuf != NULL)
 190                                         free(targbuf);
 191                                 return (1);
 192                         }
 193                 }
 194                 (void) munmap(cp, munmapsize);
 195         } else {
 196                 char buf[SMALLFILESIZE];
 197                 for (;;) {
 198                         n = read(fi, buf, sizeof (buf));
 199                         if (n == 0) {
 200                                 return (0);
 201                         } else if (n < 0) {
 202                                 (void) close(fi);
 203                                 (void) close(fo);
 204                                 if (S_ISREG(s2p->st_mode))
 205                                         (void) unlink(targbuf);
 206                                 if (srcbuf != NULL)
 207                                         free(srcbuf);
 208                                 if (targbuf != NULL)
 209                                         free(targbuf);
 210                                 return (1);
 211                         } else if (write(fo, buf, n) != n) {
 212                                 (void) close(fi);
 213                                 (void) close(fo);
 214                                 if (S_ISREG(s2p->st_mode))
 215                                         (void) unlink(targbuf);
 216                                 if (srcbuf != NULL)
 217                                         free(srcbuf);
 218                                 if (targbuf != NULL)
 219                                         free(targbuf);
 220                                 return (1);
 221                         }
 222                 }
 223         }
 224         if (srcbuf != NULL)
 225                 free(srcbuf);
 226         if (targbuf != NULL)
 227                 free(targbuf);
 228         return (0);
 229 }