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.7 2005/08/08 17:06:18 joerg 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 (strcmp(den->d_name, ".") == 0) 160 continue; 161 if (strcmp(den->d_name, "..") == 0) 162 continue; 163 scan = FSCopy(phlinks, den->d_name); 164 if (scan) { 165 *pscan = scan; 166 scan->fs_Parent = node; 167 pscan = &scan->fs_Next; 168 } 169 } 170 if (chdir("..") < 0) { 171 fprintf(stderr, "Unable to chdir .. after scanning %s\n", path); 172 exit(1); 173 } 174 closedir(dir); 175 } 176 break; 177 case S_IFBLK: 178 break; 179 case S_IFREG: 180 if (node->fs_St.st_nlink > 1 && fsgethlink(*phlinks, node)) { 181 node->fs_Bytes = -1; /* hardlink indicator */ 182 } else if (node->fs_St.st_size >= 0x80000000LL) { 183 fprintf(stderr, "File %s too large to copy\n", path); 184 free(node); 185 node = NULL; 186 } else if ((node->fs_Data = malloc(node->fs_St.st_size)) == NULL) { 187 fprintf(stderr, "Ran out of memory copying %s\n", path); 188 free(node); 189 node = NULL; 190 } else if ((n = open(path, O_RDONLY)) < 0) { 191 fprintf(stderr, "Unable to open %s for reading\n", path); 192 free(node->fs_Data); 193 free(node); 194 node = NULL; 195 } else if (read(n, node->fs_Data, node->fs_St.st_size) != node->fs_St.st_size) { 196 fprintf(stderr, "Unable to read %s\n", path); 197 free(node->fs_Data); 198 free(node); 199 node = NULL; 200 201 } else { 202 node->fs_Bytes = node->fs_St.st_size; 203 if (node->fs_St.st_nlink > 1) { 204 node->fs_HNext = *phlinks; 205 *phlinks = node; 206 } 207 } 208 break; 209 case S_IFLNK: 210 if ((n = readlink(path, buf, sizeof(buf))) > 0) { 211 if ((node->fs_Data = malloc(n + 1)) == NULL) { 212 fprintf(stderr, "Ran out of memory\n"); 213 free(node); 214 node = NULL; 215 } else { 216 node->fs_Bytes = n; 217 bcopy(buf, node->fs_Data, n); 218 node->fs_Data[n] = 0; 219 } 220 } else if (n == 0) { 221 node->fs_Data = NULL; 222 node->fs_Bytes = 0; 223 } else { 224 fprintf(stderr, "Unable to read link: %s\n", path); 225 free(node); 226 node = NULL; 227 } 228 break; 229 case S_IFSOCK: 230 break; 231 case S_IFWHT: 232 break; 233 default: 234 break; 235 } 236 } 237 return(node); 238 } 239 240 void 241 FSPaste(const char *path, fsnode_t node, fsnode_t hlinks) 242 { 243 struct timeval times[2]; 244 fsnode_t scan; 245 int fd; 246 int ok = 0; 247 248 switch(node->fs_St.st_mode & S_IFMT) { 249 case S_IFIFO: 250 break; 251 case S_IFCHR: 252 case S_IFBLK: 253 if (mknod(path, node->fs_St.st_mode, node->fs_St.st_rdev) < 0) { 254 fprintf(stderr, "Paste: mknod failed on %s\n", path); 255 break; 256 } 257 ok = 1; 258 break; 259 case S_IFDIR: 260 fd = open(".", O_RDONLY); 261 if (fd < 0) { 262 fprintf(stderr, "Paste: cannot open current directory\n"); 263 exit(1); 264 } 265 if (mkdir(path, 0700) < 0 && errno != EEXIST) { 266 printf("Paste: unable to create directory %s\n", path); 267 close(fd); 268 break; 269 } 270 if (chdir(path) < 0) { 271 printf("Paste: unable to chdir into %s\n", path); 272 exit(1); 273 } 274 for (scan = node->fs_Base; scan; scan = scan->fs_Next) { 275 FSPaste(scan->fs_Name, scan, hlinks); 276 } 277 if (fchdir(fd) < 0) { 278 fprintf(stderr, "Paste: cannot fchdir current dir\n"); 279 close(fd); 280 exit(1); 281 } 282 close(fd); 283 ok = 1; 284 break; 285 case S_IFREG: 286 if (node->fs_St.st_nlink > 1 && node->fs_Bytes < 0) { 287 if ((scan = fsgethlink(hlinks, node)) == NULL) { 288 fprintf(stderr, "Cannot find hardlink for %s\n", path); 289 } else { 290 char *hpath = fshardpath(scan, node); 291 if (hpath == NULL || link(hpath, path) < 0) { 292 fprintf(stderr, "Cannot create hardlink: %s->%s\n", path, hpath ? hpath : "?"); 293 if (hpath) 294 free(hpath); 295 break; 296 } 297 ok = 1; 298 free(hpath); 299 } 300 break; 301 } 302 if ((fd = open(path, O_RDWR|O_CREAT|O_TRUNC, 0600)) < 0) { 303 fprintf(stderr, "Cannot create file: %s\n", path); 304 break; 305 } 306 if (node->fs_Bytes > 0) { 307 if (write(fd, node->fs_Data, node->fs_Bytes) != node->fs_Bytes) { 308 fprintf(stderr, "Cannot write file: %s\n", path); 309 remove(path); 310 close(fd); 311 break; 312 } 313 } 314 close(fd); 315 ok = 1; 316 break; 317 case S_IFLNK: 318 if (symlink(node->fs_Bytes > 0 ? node->fs_Data : "", path) < 0) { 319 fprintf(stderr, "Unable to create symbolic link: %s\n", path); 320 break; 321 } 322 ok = 1; 323 break; 324 case S_IFSOCK: 325 break; 326 case S_IFWHT: 327 break; 328 default: 329 break; 330 } 331 332 /* 333 * Set perms 334 */ 335 if (ok) { 336 struct stat *st = &node->fs_St; 337 338 times[0].tv_sec = st->st_atime; 339 times[0].tv_usec = 0; 340 times[1].tv_sec = st->st_mtime; 341 times[1].tv_usec = 0; 342 343 if (lchown(path, st->st_uid, st->st_gid) < 0) 344 fprintf(stderr, "lchown failed on %s\n", path); 345 if (lutimes(path, times) < 0) 346 fprintf(stderr, "lutimes failed on %s\n", path); 347 if (lchmod(path, st->st_mode & ALLPERMS) < 0) 348 fprintf(stderr, "lchmod failed on %s\n", path); 349 if (!S_ISLNK(st->st_mode)) { 350 if (chflags(path, st->st_flags) < 0) 351 fprintf(stderr, "chflags failed on %s\n", path); 352 } 353 } 354 } 355 356