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 } 230