Fix section ref.
[dragonfly.git] / sbin / newfs / fscopy.c
blob4494d89d022ceeeb3f97a15384e74c1d16e9e9b2
1 /*
2 * Copyright (c) 2003 Matthew Dillon <dillon@backplane.com>
3 * All rights reserved.
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.
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.
26 * $DragonFly: src/sbin/newfs/fscopy.c,v 1.7 2005/08/08 17:06:18 joerg Exp $
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"
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];
54 static
55 fsnode_t
56 fsmknode(const char *path)
58 int pathlen = strlen(path);
59 fsnode_t node = malloc(offsetof(struct FSNode, fs_Name[pathlen+1]));
61 if (node == NULL) {
62 fprintf(stderr, "ran out of memory copying filesystem\n");
63 return(NULL);
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);
72 return(node);
75 static fsnode_t
76 fsgethlink(fsnode_t hlinks, fsnode_t node)
78 fsnode_t scan;
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);
87 return(NULL);
90 static char *
91 fshardpath(fsnode_t hlink, fsnode_t node)
93 fsnode_t scan;
94 char *path;
95 char *tmp;
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;
105 if (scan == NULL)
106 return(NULL);
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) {
113 tmp = path;
114 asprintf(&path, "%s/%s", scan->fs_Name, tmp);
115 free(tmp);
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);
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);
132 fsnode_t
133 FSCopy(fsnode_t *phlinks, const char *path)
135 int n;
136 DIR *dir;
137 fsnode_t node;
138 char buf[1024];
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;
153 if (chdir(path) < 0) {
154 fprintf(stderr, "Unable to chdir into %s\n", path);
155 break;
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;
170 if (chdir("..") < 0) {
171 fprintf(stderr, "Unable to chdir .. after scanning %s\n", path);
172 exit(1);
174 closedir(dir);
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;
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;
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;
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;
228 break;
229 case S_IFSOCK:
230 break;
231 case S_IFWHT:
232 break;
233 default:
234 break;
237 return(node);
240 void
241 FSPaste(const char *path, fsnode_t node, fsnode_t hlinks)
243 struct timeval times[2];
244 fsnode_t scan;
245 int fd;
246 int ok = 0;
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;
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);
265 if (mkdir(path, 0700) < 0 && errno != EEXIST) {
266 printf("Paste: unable to create directory %s\n", path);
267 close(fd);
268 break;
270 if (chdir(path) < 0) {
271 printf("Paste: unable to chdir into %s\n", path);
272 exit(1);
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");
279 close(fd);
280 exit(1);
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;
297 ok = 1;
298 free(hpath);
300 break;
302 if ((fd = open(path, O_RDWR|O_CREAT|O_TRUNC, 0600)) < 0) {
303 fprintf(stderr, "Cannot create file: %s\n", path);
304 break;
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;
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;
322 ok = 1;
323 break;
324 case S_IFSOCK:
325 break;
326 case S_IFWHT:
327 break;
328 default:
329 break;
333 * Set perms
335 if (ok) {
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);