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