1/* 2 * Copyright (c) 2012 Apple, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <stdio.h> 25#include <stdlib.h> 26#include <unistd.h> 27#include <stdbool.h> 28#include <errno.h> 29#include <err.h> 30#include <sysexits.h> 31 32#include <sys/stat.h> 33#include <sys/fcntl.h> 34#include <sys/param.h> 35#include <sys/time.h> 36 37#include <copyfile.h> 38 39void usage(void); 40 41int main(int argc, char * argv[]) 42{ 43 struct stat sb; 44 void *mset; 45 mode_t mode; 46 bool gotmode = false; 47 int ch; 48 int ret; 49 int srcfd, dstfd; 50 const char *src = NULL; 51 const char *dst = NULL; 52 char dsttmpname[MAXPATHLEN]; 53 54 while ((ch = getopt(argc, argv, "cSm:")) != -1) { 55 switch(ch) { 56 case 'c': 57 case 'S': 58 /* ignored for compatibility */ 59 break; 60 case 'm': 61 gotmode = true; 62 mset = setmode(optarg); 63 if (!mset) 64 errx(EX_USAGE, "Unrecognized mode %s", optarg); 65 66 mode = getmode(mset, 0); 67 free(mset); 68 break; 69 case '?': 70 default: 71 usage(); 72 } 73 } 74 75 argc -= optind; 76 argv += optind; 77 78 if (argc < 2) { 79 usage(); 80 } 81 82 src = argv[0]; 83 dst = argv[1]; 84 85 srcfd = open(src, O_RDONLY | O_SYMLINK, 0); 86 if (srcfd < 0) 87 err(EX_NOINPUT, "open(%s)", src); 88 89 ret = fstat(srcfd, &sb); 90 if (ret < 0) 91 err(EX_NOINPUT, "fstat(%s)", src); 92 93 if (!S_ISREG(sb.st_mode)) 94 err(EX_USAGE, "%s is not a regular file", src); 95 96 snprintf(dsttmpname, sizeof(dsttmpname), "%s.XXXXXX", dst); 97 98 dstfd = mkstemp(dsttmpname); 99 if (dstfd < 0) 100 err(EX_UNAVAILABLE, "mkstemp(%s)", dsttmpname); 101 102 ret = fcopyfile(srcfd, dstfd, NULL, 103 COPYFILE_DATA); 104 if (ret < 0) 105 err(EX_UNAVAILABLE, "fcopyfile(%s, %s)", src, dsttmpname); 106 107 ret = futimes(dstfd, NULL); 108 if (ret < 0) 109 err(EX_UNAVAILABLE, "futimes(%s)", dsttmpname); 110 111 if (gotmode) { 112 ret = fchmod(dstfd, mode); 113 if (ret < 0) 114 err(EX_NOINPUT, "fchmod(%s, %ho)", dsttmpname, mode); 115 } 116 117 ret = rename(dsttmpname, dst); 118 if (ret < 0) 119 err(EX_NOINPUT, "rename(%s, %s)", dsttmpname, dst); 120 121 ret = close(dstfd); 122 if (ret < 0) 123 err(EX_NOINPUT, "close(dst)"); 124 125 ret = close(srcfd); 126 if (ret < 0) 127 err(EX_NOINPUT, "close(src)"); 128 129 return 0; 130} 131 132void usage(void) 133{ 134 fprintf(stderr, "Usage: %s [-c] [-S] [-m <mode>] <src> <dst>\n", 135 getprogname()); 136 exit(EX_USAGE); 137} 138