1 /* 2 * Copyright (c) 2003 Matthew Dillon <dillon@backplane.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $DragonFly: src/sbin/newfs/fscopy.c,v 1.6 2005/01/08 19:39:40 cpressey Exp $ 27 */ 28 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 #include <stdio.h> 32 #include <stdarg.h> 33 #include <unistd.h> 34 #include <fcntl.h> 35 #include <dirent.h> 36 #include <errno.h> 37 #ifdef DIRBLKSIZ 38 #undef DIRBLKSIZ 39 #endif 40 #include "defs.h" 41 42 struct FSNode { 43 struct FSNode *fs_Next; 44 struct FSNode *fs_HNext; 45 struct FSNode *fs_Base; 46 struct FSNode *fs_Parent; 47 struct stat fs_St; 48 char *fs_Data; 49 int fs_Bytes; 50 int fs_Marker; 51 char fs_Name[4]; 52 }; 53 54 static 55 fsnode_t 56 fsmknode(const char *path) 57 { 58 int pathlen = strlen(path); 59 fsnode_t node = malloc(offsetof(struct FSNode, fs_Name[pathlen+1])); 60 61 if (node == NULL) { 62 fprintf(stderr, "ran out of memory copying filesystem\n"); 63 return(NULL); 64 } 65 bzero(node, sizeof(*node)); 66 bcopy(path, node->fs_Name, pathlen + 1); 67 if (lstat(path, &node->fs_St) < 0) { 68 fprintf(stderr, "Unable to lstat(\"%s\")\n", path); 69 free(node); 70 return(NULL); 71 } 72 return(node); 73 } 74 75 static fsnode_t 76 fsgethlink(fsnode_t hlinks, fsnode_t node) 77 { 78 fsnode_t scan; 79 80 for (scan = hlinks; scan; scan = scan->fs_HNext) { 81 if (scan->fs_St.st_dev == node->fs_St.st_dev && 82 scan->fs_St.st_ino == node->fs_St.st_ino 83 ) { 84 return(scan); 85 } 86 } 87 return(NULL); 88 } 89 90 static char * 91 fshardpath(fsnode_t hlink, fsnode_t node) 92 { 93 fsnode_t scan; 94 char *path; 95 char *tmp; 96 97 for (scan = hlink; scan; scan = scan->fs_Parent) 98 scan->fs_Marker = 1; 99 for (scan = node; scan; scan = scan->fs_Parent) { 100 if (scan->fs_Marker == 1) { 101 scan->fs_Marker = 2; 102 break; 103 } 104 } 105 if (scan == NULL) 106 return(NULL); 107 108 /* 109 * Build the path backwards 110 */ 111 asprintf(&path, "%s", hlink->fs_Name); 112 for (scan = hlink->fs_Parent; scan->fs_Marker == 1; scan = scan->fs_Parent) { 113 tmp = path; 114 asprintf(&path, "%s/%s", scan->fs_Name, tmp); 115 free(tmp); 116 } 117 for (scan = node->fs_Parent; scan; scan = scan->fs_Parent) { 118 if (scan->fs_Marker == 2) 119 break; 120 tmp = path; 121 asprintf(&path, "../%s", tmp); 122 free(tmp); 123 } 124 125 for (scan = hlink; scan; scan = scan->fs_Parent) 126 scan->fs_Marker = 0; 127 for (scan = node; scan; scan = scan->fs_Parent) 128 scan->fs_Marker = 0; 129 return(path); 130 } 131 132 fsnode_t 133 FSCopy(fsnode_t *phlinks, const char *path) 134 { 135 int n; 136 DIR *dir; 137 fsnode_t node; 138 char buf[1024]; 139 140 node = fsmknode(path); 141 if (node) { 142 switch(node->fs_St.st_mode & S_IFMT) { 143 case S_IFIFO: 144 break; 145 case S_IFCHR: 146 break; 147 case S_IFDIR: 148 if ((dir = opendir(path)) != NULL) { 149 struct dirent *den; 150 fsnode_t scan; 151 fsnode_t *pscan; 152 153 if (chdir(path) < 0) { 154 fprintf(stderr, "Unable to chdir into %s\n", path); 155 break; 156 } 157 pscan = &node->fs_Base; 158 while ((den = readdir(dir)) != NULL) { 159 if (den->d_namlen == 1 && den->d_name[0] == '.') 160 continue; 161 if (den->d_namlen == 2 && den->d_name[0] == '.' && 162 den->d_name[1] == '.' 163 ) { 164 continue; 165 } 166 scan = FSCopy(phlinks, den->d_name); 167 if (scan) { 168 *pscan = scan; 169 scan->fs_Parent = node; 170 pscan = &scan->fs_Next; 171 } 172 } 173 if (chdir("..") < 0) { 174 fprintf(stderr, "Unable to chdir .. after scanning %s\n", path); 175 exit(1); 176 } 177 closedir(dir); 178 } 179 break; 180 case S_IFBLK: 181 break; 182 case S_IFREG: 183 if (node->fs_St.st_nlink > 1 && fsgethlink(*phlinks, node)) { 184 node->fs_Bytes = -1; /* hardlink indicator */ 185 } else if (node->fs_St.st_size >= 0x80000000LL) { 186 fprintf(stderr, "File %s too large to copy\n", path); 187 free(node); 188 node = NULL; 189 } else if ((node->fs_Data = malloc(node->fs_St.st_size)) == NULL) { 190 fprintf(stderr, "Ran out of memory copying %s\n", path); 191 free(node); 192 node = NULL; 193 } else if ((n = open(path, O_RDONLY)) < 0) { 194 fprintf(stderr, "Unable to open %s for reading\n", path); 195 free(node->fs_Data); 196 free(node); 197 node = NULL; 198 } else if (read(n, node->fs_Data, node->fs_St.st_size) != node->fs_St.st_size) { 199 fprintf(stderr, "Unable to read %s\n", path); 200 free(node->fs_Data); 201 free(node); 202 node = NULL; 203 204 } else { 205 node->fs_Bytes = node->fs_St.st_size; 206 if (node->fs_St.st_nlink > 1) { 207 node->fs_HNext = *phlinks; 208 *phlinks = node; 209 } 210 } 211 break; 212 case S_IFLNK: 213 if ((n = readlink(path, buf, sizeof(buf))) > 0) { 214 if ((node->fs_Data = malloc(n + 1)) == NULL) { 215 fprintf(stderr, "Ran out of memory\n"); 216 free(node); 217 node = NULL; 218 } else { 219 node->fs_Bytes = n; 220 bcopy(buf, node->fs_Data, n); 221 node->fs_Data[n] = 0; 222 } 223 } else if (n == 0) { 224 node->fs_Data = NULL; 225 node->fs_Bytes = 0; 226 } else { 227 fprintf(stderr, "Unable to read link: %s\n", path); 228 free(node); 229 node = NULL; 230 } 231 break; 232 case S_IFSOCK: 233 break; 234 case S_IFWHT: 235 break; 236 default: 237 break; 238 } 239 } 240 return(node); 241 } 242 243 void 244 FSPaste(const char *path, fsnode_t node, fsnode_t hlinks) 245 { 246 struct timeval times[2]; 247 fsnode_t scan; 248 int fd; 249 int ok = 0; 250 251 switch(node->fs_St.st_mode & S_IFMT) { 252 case S_IFIFO: 253 break; 254 case S_IFCHR: 255 case S_IFBLK: 256 if (mknod(path, node->fs_St.st_mode, node->fs_St.st_rdev) < 0) { 257 fprintf(stderr, "Paste: mknod failed on %s\n", path); 258 break; 259 } 260 ok = 1; 261 break; 262 case S_IFDIR: 263 fd = open(".", O_RDONLY); 264 if (fd < 0) { 265 fprintf(stderr, "Paste: cannot open current directory\n"); 266 exit(1); 267 } 268 if (mkdir(path, 0700) < 0 && errno != EEXIST) { 269 printf("Paste: unable to create directory %s\n", path); 270 close(fd); 271 break; 272 } 273 if (chdir(path) < 0) { 274 printf("Paste: unable to chdir into %s\n", path); 275 exit(1); 276 } 277 for (scan = node->fs_Base; scan; scan = scan->fs_Next) { 278 FSPaste(scan->fs_Name, scan, hlinks); 279 } 280 if (fchdir(fd) < 0) { 281 fprintf(stderr, "Paste: cannot fchdir current dir\n"); 282 close(fd); 283 exit(1); 284 } 285 close(fd); 286 ok = 1; 287 break; 288 case S_IFREG: 289 if (node->fs_St.st_nlink > 1 && node->fs_Bytes < 0) { 290 if ((scan = fsgethlink(hlinks, node)) == NULL) { 291 fprintf(stderr, "Cannot find hardlink for %s\n", path); 292 } else { 293 char *hpath = fshardpath(scan, node); 294 if (hpath == NULL || link(hpath, path) < 0) { 295 fprintf(stderr, "Cannot create hardlink: %s->%s\n", path, hpath ? hpath : "?"); 296 if (hpath) 297 free(hpath); 298 break; 299 } 300 ok = 1; 301 free(hpath); 302 } 303 break; 304 } 305 if ((fd = open(path, O_RDWR|O_CREAT|O_TRUNC, 0600)) < 0) { 306 fprintf(stderr, "Cannot create file: %s\n", path); 307 break; 308 } 309 if (node->fs_Bytes > 0) { 310 if (write(fd, node->fs_Data, node->fs_Bytes) != node->fs_Bytes) { 311 fprintf(stderr, "Cannot write file: %s\n", path); 312 remove(path); 313 close(fd); 314 break; 315 } 316 } 317 close(fd); 318 ok = 1; 319 break; 320 case S_IFLNK: 321 if (symlink(node->fs_Bytes > 0 ? node->fs_Data : "", path) < 0) { 322 fprintf(stderr, "Unable to create symbolic link: %s\n", path); 323 break; 324 } 325 ok = 1; 326 break; 327 case S_IFSOCK: 328 break; 329 case S_IFWHT: 330 break; 331 default: 332 break; 333 } 334 335 /* 336 * Set perms 337 */ 338 if (ok) { 339 struct stat *st = &node->fs_St; 340 341 times[0].tv_sec = st->st_atime; 342 times[0].tv_usec = 0; 343 times[1].tv_sec = st->st_mtime; 344 times[1].tv_usec = 0; 345 346 if (lchown(path, st->st_uid, st->st_gid) < 0) 347 fprintf(stderr, "lchown failed on %s\n", path); 348 if (lutimes(path, times) < 0) 349 fprintf(stderr, "lutimes failed on %s\n", path); 350 if (lchmod(path, st->st_mode & ALLPERMS) < 0) 351 fprintf(stderr, "lchmod failed on %s\n", path); 352 if (!S_ISLNK(st->st_mode)) { 353 if (chflags(path, st->st_flags) < 0) 354 fprintf(stderr, "chflags failed on %s\n", path); 355 } 356 } 357 } 358 359