2 * Copyright (c) 2003 Matthew Dillon <dillon@backplane.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
26 * $DragonFly: src/sbin/newfs/fscopy.c,v 1.7 2005/08/08 17:06:18 joerg Exp $
29 #include <sys/types.h>
43 struct FSNode
*fs_Next
;
44 struct FSNode
*fs_HNext
;
45 struct FSNode
*fs_Base
;
46 struct FSNode
*fs_Parent
;
56 fsmknode(const char *path
)
58 int pathlen
= strlen(path
);
59 fsnode_t node
= malloc(offsetof(struct FSNode
, fs_Name
[pathlen
+1]));
62 fprintf(stderr
, "ran out of memory copying filesystem\n");
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
);
76 fsgethlink(fsnode_t hlinks
, fsnode_t node
)
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
91 fshardpath(fsnode_t hlink
, fsnode_t node
)
97 for (scan
= hlink
; scan
; scan
= scan
->fs_Parent
)
99 for (scan
= node
; scan
; scan
= scan
->fs_Parent
) {
100 if (scan
->fs_Marker
== 1) {
109 * Build the path backwards
111 asprintf(&path
, "%s", hlink
->fs_Name
);
112 for (scan
= hlink
->fs_Parent
; scan
->fs_Marker
== 1; scan
= scan
->fs_Parent
) {
114 asprintf(&path
, "%s/%s", scan
->fs_Name
, tmp
);
117 for (scan
= node
->fs_Parent
; scan
; scan
= scan
->fs_Parent
) {
118 if (scan
->fs_Marker
== 2)
121 asprintf(&path
, "../%s", tmp
);
125 for (scan
= hlink
; scan
; scan
= scan
->fs_Parent
)
127 for (scan
= node
; scan
; scan
= scan
->fs_Parent
)
133 FSCopy(fsnode_t
*phlinks
, const char *path
)
140 node
= fsmknode(path
);
142 switch(node
->fs_St
.st_mode
& S_IFMT
) {
148 if ((dir
= opendir(path
)) != NULL
) {
153 if (chdir(path
) < 0) {
154 fprintf(stderr
, "Unable to chdir into %s\n", path
);
157 pscan
= &node
->fs_Base
;
158 while ((den
= readdir(dir
)) != NULL
) {
159 if (strcmp(den
->d_name
, ".") == 0)
161 if (strcmp(den
->d_name
, "..") == 0)
163 scan
= FSCopy(phlinks
, den
->d_name
);
166 scan
->fs_Parent
= node
;
167 pscan
= &scan
->fs_Next
;
170 if (chdir("..") < 0) {
171 fprintf(stderr
, "Unable to chdir .. after scanning %s\n", path
);
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
);
186 } else if ((node
->fs_Data
= malloc(node
->fs_St
.st_size
)) == NULL
) {
187 fprintf(stderr
, "Ran out of memory copying %s\n", path
);
190 } else if ((n
= open(path
, O_RDONLY
)) < 0) {
191 fprintf(stderr
, "Unable to open %s for reading\n", path
);
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
);
202 node
->fs_Bytes
= node
->fs_St
.st_size
;
203 if (node
->fs_St
.st_nlink
> 1) {
204 node
->fs_HNext
= *phlinks
;
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");
217 bcopy(buf
, node
->fs_Data
, n
);
218 node
->fs_Data
[n
] = 0;
221 node
->fs_Data
= NULL
;
224 fprintf(stderr
, "Unable to read link: %s\n", path
);
241 FSPaste(const char *path
, fsnode_t node
, fsnode_t hlinks
)
243 struct timeval times
[2];
248 switch(node
->fs_St
.st_mode
& S_IFMT
) {
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
);
260 fd
= open(".", O_RDONLY
);
262 fprintf(stderr
, "Paste: cannot open current directory\n");
265 if (mkdir(path
, 0700) < 0 && errno
!= EEXIST
) {
266 printf("Paste: unable to create directory %s\n", path
);
270 if (chdir(path
) < 0) {
271 printf("Paste: unable to chdir into %s\n", path
);
274 for (scan
= node
->fs_Base
; scan
; scan
= scan
->fs_Next
) {
275 FSPaste(scan
->fs_Name
, scan
, hlinks
);
277 if (fchdir(fd
) < 0) {
278 fprintf(stderr
, "Paste: cannot fchdir current dir\n");
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
);
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
: "?");
302 if ((fd
= open(path
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600)) < 0) {
303 fprintf(stderr
, "Cannot create file: %s\n", path
);
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
);
318 if (symlink(node
->fs_Bytes
> 0 ? node
->fs_Data
: "", path
) < 0) {
319 fprintf(stderr
, "Unable to create symbolic link: %s\n", path
);
336 struct stat
*st
= &node
->fs_St
;
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;
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
);