1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2012 Jilin Xpd <jilinxpd@gmail.com> 14 * Copyright 2018 Nexenta Systems, Inc. 15 */ 16 17 /* 18 * use mmap to copy data from src file to des file, 19 * with given flags and modes. 20 * the src & des file should exist and have the same size. 21 */ 22 23 #include <sys/mman.h> 24 #include <sys/types.h> 25 #include <sys/stat.h> 26 #include <fcntl.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <string.h> 31 #include <errno.h> 32 33 void 34 usage(void) 35 { 36 fprintf(stderr, 37 "usage: " 38 "prot_mmap -o <r|w> <r|w>" 39 " -m <r|w|s|p> <r|w|s|p>" 40 " -f <srcfile> <desfile>\n"); 41 exit(1); 42 } 43 44 int 45 main(int argc, char **argv) 46 { 47 struct stat sb; 48 char *src_addr, *des_addr; 49 char *src_file = NULL, *des_file = NULL; 50 off_t offset; 51 size_t filesize; 52 size_t blksize; 53 size_t numblks; 54 size_t i, j; 55 int src_fid, des_fid; 56 int mret = 0; 57 int flags0 = 0, mflags0 = 0, prot0 = 0; /* flags for src file */ 58 int flags1 = 0, mflags1 = 0, prot1 = 0; /* flags for des file */ 59 60 /* 61 * parse arguments 62 * Not getopt because -o -m -f all have 2 optargs each. 63 */ 64 if (argc != 10) { 65 usage(); 66 } 67 for (i = 1; i < argc; ) { 68 switch (argv[i][1]) { 69 case 'o': /* options for open() */ 70 i++; 71 for (j = 0; argv[i][j]; j++) { 72 if (argv[i][j] == 'r') 73 flags0 |= O_RDONLY; 74 else if (argv[i][j] == 'w') 75 flags0 |= O_WRONLY; 76 } 77 if ((flags0 & (O_RDONLY | O_WRONLY)) == 78 (O_RDONLY | O_WRONLY)) 79 flags0 = O_RDWR; 80 i++; 81 for (j = 0; argv[i][j]; j++) { 82 if (argv[i][j] == 'r') 83 flags1 |= O_RDONLY; 84 else if (argv[i][j] == 'w') 85 flags1 |= O_WRONLY; 86 } 87 if ((flags1 & (O_RDONLY | O_WRONLY)) == 88 (O_RDONLY | O_WRONLY)) 89 flags1 = O_RDWR; 90 i++; 91 break; 92 case 'm': /* options for mmap() */ 93 i++; 94 for (j = 0; argv[i][j]; j++) { 95 if (argv[i][j] == 'r') 96 prot0 |= PROT_READ; 97 else if (argv[i][j] == 'w') 98 prot0 |= PROT_WRITE; 99 else if (argv[i][j] == 's') 100 mflags0 |= MAP_SHARED; 101 else if (argv[i][j] == 'p') 102 mflags0 |= MAP_PRIVATE; 103 } 104 i++; 105 for (j = 0; argv[i][j]; j++) { 106 if (argv[i][j] == 'r') 107 prot1 |= PROT_READ; 108 else if (argv[i][j] == 'w') 109 prot1 |= PROT_WRITE; 110 else if (argv[i][j] == 's') 111 mflags1 |= MAP_SHARED; 112 else if (argv[i][j] == 'p') 113 mflags1 |= MAP_PRIVATE; 114 } 115 i++; 116 break; 117 case 'f': /* src file and des file */ 118 i++; 119 src_file = argv[i]; 120 i++; 121 des_file = argv[i]; 122 i++; 123 } 124 } 125 126 /* source file */ 127 src_fid = open(src_file, flags0); 128 if (src_fid == -1) { 129 fprintf(stderr, "open %s error=%d\n", src_file, errno); 130 return (1); 131 } 132 /* destination file */ 133 des_fid = open(des_file, flags1); 134 if (des_fid == -1) { 135 fprintf(stderr, "open %s error=%d\n", des_file, errno); 136 mret = 1; 137 goto exit3; 138 } 139 140 /* get file size */ 141 if (fstat(src_fid, &sb) == -1) { 142 fprintf(stderr, "fstat %s error=%d\n", src_file, errno); 143 mret = 1; 144 goto exit2; 145 } 146 filesize = sb.st_size; 147 if (filesize < 4096) { 148 fprintf(stderr, "file too small\n"); 149 mret = 1; 150 goto exit2; 151 } 152 153 if (fstat(des_fid, &sb) == -1) { 154 fprintf(stderr, "fstat %s error=%d\n", des_file, errno); 155 mret = 1; 156 goto exit2; 157 } 158 if (filesize != sb.st_size) { 159 fprintf(stderr, "file sizes differ\n"); 160 mret = 1; 161 goto exit2; 162 } 163 164 /* copy data */ 165 blksize = 64 * 1024 * 1024; 166 numblks = (filesize + blksize - 1) / blksize; 167 for (i = 0; i < numblks && mret == 0; i++) { 168 169 offset = (i % numblks) * blksize; 170 if (offset + blksize > filesize) 171 blksize = filesize - offset; 172 173 /* map file */ 174 src_addr = mmap(NULL, blksize, prot0, mflags0, src_fid, offset); 175 if (src_addr == MAP_FAILED) { 176 fprintf(stderr, "mmap %s error=%d\n", src_file, errno); 177 mret = 1; 178 break; 179 } 180 des_addr = mmap(NULL, blksize, prot1, mflags1, des_fid, offset); 181 if (des_addr == MAP_FAILED) { 182 fprintf(stderr, "mmap %s error=%d\n", des_file, errno); 183 mret = 1; 184 goto exit1; 185 } 186 187 /* cp data from src addr to des addr */ 188 memcpy(des_addr, src_addr, blksize); 189 /* sync mapped pages to file */ 190 if (msync(des_addr, blksize, MS_SYNC) == -1) { 191 fprintf(stderr, "msync %s error=%d\n", des_file, errno); 192 mret = 1; 193 } 194 195 /* unmap file */ 196 if (munmap(des_addr, blksize) == -1) { 197 fprintf(stderr, "munmap %s error=%d\n", 198 des_file, errno); 199 mret = 1; 200 } 201 exit1: 202 if (munmap(src_addr, blksize) == -1) { 203 fprintf(stderr, "munmap %s error=%d\n", 204 src_file, errno); 205 mret = 1; 206 } 207 } 208 209 /* close file */ 210 exit2: 211 close(des_fid); 212 exit3: 213 close(src_fid); 214 215 return (mret); 216 } 217