]>
git.wh0rd.org - dump.git/blob - restore/utilities.c
2 * Ported to Linux's Second Extended File System as part of the
3 * dump and restore backup suit
4 * Remy Card <card@Linux.EU.Org>, 1994-1997
5 * Stelian Pop <stelian@popies.net>, 1999-2000
6 * Stelian Pop <stelian@popies.net> - AlcĂ´ve <www.alcove.com>, 2000-2002
10 * Copyright (c) 1983, 1993
11 * The Regents of the University of California. All rights reserved.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 static const char rcsid
[] =
40 "$Id: utilities.c,v 1.26 2004/12/15 11:00:01 stelian Exp $";
44 #include <compatlfs.h>
45 #include <sys/types.h>
47 #include <compaterr.h>
52 #include <sys/param.h>
59 #ifdef HAVE_EXT2FS_EXT2_FS_H
60 #include <ext2fs/ext2_fs.h>
62 #include <linux/ext2_fs.h>
64 #include <ext2fs/ext2fs.h>
65 #include <bsdcompat.h>
69 #include <sys/fcntl.h>
70 #include <bsdcompat.h>
72 #include <ufs/ufs/dinode.h>
73 #include <ufs/ufs/dir.h>
75 #endif /* __linux__ */
83 * Insure that all the components of a pathname exist.
92 start
= strchr(name
, '/');
95 for (cp
= start
; *cp
!= '\0'; cp
++) {
99 ep
= lookupname(name
);
101 /* Safe; we know the pathname exists in the dump. */
102 ep
= addentry(name
, pathsearch(name
)->d_ino
, NODE
);
105 ep
->e_flags
|= NEW
|KEEP
;
111 * Change a name to a unique temporary name.
114 mktempname(struct entry
*ep
)
116 char oldname
[MAXPATHLEN
];
118 if (ep
->e_flags
& TMPNAME
)
119 badentry(ep
, "mktempname: called with TMPNAME");
120 ep
->e_flags
|= TMPNAME
;
121 (void) strcpy(oldname
, myname(ep
));
122 freename(ep
->e_name
);
123 ep
->e_name
= savename(gentempname(ep
));
124 ep
->e_namlen
= strlen(ep
->e_name
);
125 renameit(oldname
, myname(ep
));
129 * Generate a temporary name for an entry.
132 gentempname(struct entry
*ep
)
134 static char name
[MAXPATHLEN
];
138 for (np
= lookupino(ep
->e_ino
);
139 np
!= NULL
&& np
!= ep
; np
= np
->e_links
)
142 badentry(ep
, "not on ino list");
143 (void) snprintf(name
, sizeof(name
), "%s%ld%lu", TMPHDR
, i
, (unsigned long)ep
->e_ino
);
148 * Rename a file or directory.
151 renameit(char *from
, char *to
)
153 if (!Nflag
&& rename(from
, to
) < 0) {
154 warn("cannot rename %s to %s", from
, to
);
157 Vprintf(stdout
, "rename %s to %s\n", from
, to
);
161 * Create a new node (directory).
164 newnode(struct entry
*np
)
167 if (np
->e_type
!= NODE
)
168 badentry(np
, "newnode: not a node");
170 if (command
== 'C') return;
172 if (!Nflag
&& mkdir(cp
, 0777) < 0 && !uflag
) {
173 np
->e_flags
|= EXISTED
;
177 Vprintf(stdout
, "Make node %s\n", cp
);
181 * Remove an old node (directory).
184 removenode(struct entry
*ep
)
188 if (ep
->e_type
!= NODE
)
189 badentry(ep
, "removenode: not a node");
190 if (ep
->e_entries
!= NULL
) {
192 for (i
= 0; i
< DIRHASH_SIZE
; i
++) {
193 if (ep
->e_entries
[i
] != NULL
)
194 badentry(ep
, "removenode: non-empty directory");
197 ep
->e_flags
|= REMOVED
;
198 ep
->e_flags
&= ~TMPNAME
;
200 if (!Nflag
&& rmdir(cp
) < 0) {
204 Vprintf(stdout
, "Remove node %s\n", cp
);
211 removeleaf(struct entry
*ep
)
215 if (command
== 'C') return;
217 if (ep
->e_type
!= LEAF
)
218 badentry(ep
, "removeleaf: not a leaf");
219 ep
->e_flags
|= REMOVED
;
220 ep
->e_flags
&= ~TMPNAME
;
222 if (!Nflag
&& unlink(cp
) < 0) {
226 Vprintf(stdout
, "Remove leaf %s\n", cp
);
233 linkit(char *existing
, char *new, int type
)
236 /* if we want to unlink first, do it now so *link() won't fail */
240 if (type
== SYMLINK
) {
241 if (!Nflag
&& symlink(existing
, new) < 0) {
242 warn("cannot create symbolic link %s->%s",
246 } else if (type
== HARDLINK
) {
249 if (!Nflag
&& (ret
= link(existing
, new)) < 0) {
251 #if !defined(__linux__) && !defined(sunos)
255 * Most likely, the schg flag is set. Clear the
256 * flags and try again.
258 if (stat(existing
, &s
) == 0 && s
.st_flags
!= 0 &&
259 chflags(existing
, 0) == 0) {
260 ret
= link(existing
, new);
261 chflags(existing
, s
.st_flags
);
267 * Most likely, the immutable or append-only attribute
268 * is set. Clear the attributes and try again.
272 if (lgetflags (existing
, &s
) != -1 &&
273 lsetflags (existing
, 0) != -1) {
274 ret
= link(existing
, new);
275 lsetflags(existing
, s
);
280 warn("warning: cannot create hard link %s->%s",
286 panic("linkit: unknown type %d\n", type
);
289 Vprintf(stdout
, "Create %s link %s->%s\n",
290 type
== SYMLINK
? "symbolic" : "hard", new, existing
);
294 #if !defined(__linux__) && !defined(sunos)
299 addwhiteout(char *name
)
302 if (!Nflag
&& mknod(name
, S_IFWHT
, 0) < 0) {
303 warn("cannot create whiteout %s", name
);
306 Vprintf(stdout
, "Create whiteout %s\n", name
);
314 delwhiteout(struct entry
*ep
)
318 if (ep
->e_type
!= LEAF
)
319 badentry(ep
, "delwhiteout: not a leaf");
320 ep
->e_flags
|= REMOVED
;
321 ep
->e_flags
&= ~TMPNAME
;
323 if (!Nflag
&& undelete(name
) < 0) {
324 warn("cannot delete whiteout %s", name
);
327 Vprintf(stdout
, "Delete whiteout %s\n", name
);
332 * find lowest number file (above "start") that needs to be extracted
335 lowerbnd(dump_ino_t start
)
339 for ( ; start
< maxino
; start
++) {
340 ep
= lookupino(start
);
341 if (ep
== NULL
|| ep
->e_type
== NODE
)
343 if (ep
->e_flags
& (NEW
|EXTRACT
))
350 * find highest number file (below "start") that needs to be extracted
353 upperbnd(dump_ino_t start
)
357 for ( ; start
> ROOTINO
; start
--) {
358 ep
= lookupino(start
);
359 if (ep
== NULL
|| ep
->e_type
== NODE
)
361 if (ep
->e_flags
& (NEW
|EXTRACT
))
368 * report on a badly formed entry
371 badentry(struct entry
*ep
, const char *msg
)
374 fprintf(stderr
, "bad entry: %s\n", msg
);
375 fprintf(stderr
, "name: %s\n", myname(ep
));
376 fprintf(stderr
, "parent name %s\n", myname(ep
->e_parent
));
377 if (ep
->e_sibling
!= NULL
)
378 fprintf(stderr
, "sibling name: %s\n", myname(ep
->e_sibling
));
379 if (ep
->e_entries
!= NULL
) {
381 for (i
= 0; i
< DIRHASH_SIZE
; i
++) {
382 if (ep
->e_entries
[i
] != NULL
) {
383 fprintf(stderr
, "next entry name: %s\n", myname(ep
->e_entries
[0]));
388 if (ep
->e_links
!= NULL
)
389 fprintf(stderr
, "next link name: %s\n", myname(ep
->e_links
));
390 if (ep
->e_next
!= NULL
)
392 "next hashchain name: %s\n", myname(ep
->e_next
));
393 fprintf(stderr
, "entry type: %s\n",
394 ep
->e_type
== NODE
? "NODE" : "LEAF");
395 fprintf(stderr
, "inode number: %lu\n", (unsigned long)ep
->e_ino
);
396 panic("flags: %s\n", flagvalues(ep
));
400 * Construct a string indicating the active flag bits of an entry.
403 flagvalues(struct entry
*ep
)
405 static char flagbuf
[BUFSIZ
];
407 (void) strcpy(flagbuf
, "|NIL");
409 if (ep
->e_flags
& REMOVED
)
410 (void) strcat(flagbuf
, "|REMOVED");
411 if (ep
->e_flags
& TMPNAME
)
412 (void) strcat(flagbuf
, "|TMPNAME");
413 if (ep
->e_flags
& EXTRACT
)
414 (void) strcat(flagbuf
, "|EXTRACT");
415 if (ep
->e_flags
& NEW
)
416 (void) strcat(flagbuf
, "|NEW");
417 if (ep
->e_flags
& KEEP
)
418 (void) strcat(flagbuf
, "|KEEP");
419 if (ep
->e_flags
& EXISTED
)
420 (void) strcat(flagbuf
, "|EXISTED");
421 return (&flagbuf
[1]);
425 * Check to see if a name is on a dump tape.
428 dirlookup(const char *name
)
433 ino
= ((dp
= pathsearch(name
)) == NULL
) ? 0 : dp
->d_ino
;
435 if (ino
== 0 || TSTINO(ino
, dumpmap
) == 0)
436 fprintf(stderr
, "%s is not on the tape\n", name
);
444 reply(const char *question
)
449 fprintf(stderr
, "%s? [yn] ", question
);
450 (void) fflush(stderr
);
452 while (c
!= '\n' && getc(terminal
) != '\n')
455 } while (c
!= 'y' && c
!= 'n');
462 * handle unexpected inconsistencies
472 panic(const char *fmt
, ...)
486 vfprintf(stderr
, fmt
, ap
);
489 if (reply("abort") == GOOD
) {
490 if (reply("dump core") == GOOD
)
496 void resizemaps(dump_ino_t oldmax
, dump_ino_t newmax
)
501 map
= calloc((unsigned)1, (unsigned)howmany(newmax
, NBBY
));
503 errx(1, "no memory for active inode map");
504 memcpy(map
, usedinomap
, howmany(oldmax
, NBBY
));
509 map
= calloc((unsigned)1, (unsigned)howmany(newmax
, NBBY
));
511 errx(1, "no memory for file dump list");
512 memcpy(map
, dumpmap
, howmany(oldmax
, NBBY
));
519 GetPathFile(char *source
, char *path
, char *fname
)
535 strncpy(path
, source
, p
- source
);
536 path
[p
- source
] = 0;
543 * search for ino in QFA file
546 * if ino found return tape number and tape position
547 * if ino not found return tnum=0 and tpos=0
550 * if ino found return tape number and tape position
551 * if ino not found return tape number and tape position of last smaller ino
552 * if no smaller inode found return tnum=0 and tpos=0
555 Inode2Tapepos(dump_ino_t ino
, long *tnum
, long long *tpos
, int exactmatch
)
559 unsigned long tmpino
;
565 if (fseek(gTapeposfp
, gSeekstart
, SEEK_SET
) == -1)
568 gSeekstart
= ftell(gTapeposfp
); /* remember for later use */
569 if (fgets(gTps
, sizeof(gTps
), gTapeposfp
) == NULL
) {
572 gTps
[strlen(gTps
) - 1] = 0; /* delete end of line */
574 bzero(numbuff
, sizeof(numbuff
));
577 while ((*p
!= 0) && (*p
!= '\t'))
579 tmpino
= atol(numbuff
);
581 return 1; /* may NOT happen */
583 bzero(numbuff
, sizeof(numbuff
));
586 while ((*p
!= 0) && (*p
!= '\t'))
589 return 1; /* may NOT happen */
590 tmptnum
= atol(numbuff
);
592 bzero(numbuff
, sizeof(numbuff
));
595 while ((*p
!= 0) && (*p
!= '\t'))
597 tmptpos
= atoll(numbuff
);
619 GetSCSIIDFromPath(char *devPath
, long *id
)
629 bzero(fbuff
, sizeof(fbuff
));
630 if ((len
= readlink(devPath
, fbuff
, 2048)) == -1) {
634 GetPathFile(fbuff
, path
, fname
);
635 (void)memset(idstr
, 0, sizeof(idstr
));
636 while (*fpn
&& (*fpn
!= ',')) {
637 if (*fpn
<= '9' && *fpn
>= '0') {
655 CreateAppleDoubleFileRes(char *oFile
, FndrFileInfo
*finderinfo
, mode_t mode
, int flags
,
656 struct timeval
*timep
, u_int32_t uid
, u_int32_t gid
)
668 n
= 1; /* number of entries in double file ._ only finderinfo */
672 currently no resource fork
676 thesize
= sizeof(ASDHeader
) + (n
* sizeof(ASDEntry
)) + INFOLEN
;
677 if ((pp
= p
= (char *)malloc(thesize
)) == NULL
) {
682 hp
= (ASDHeaderPtr
)p
;
683 p
+= sizeof(ASDHeader
);
685 p
+= sizeof(ASDEntry
) * n
;
687 hp
->magic
= ADOUBLE_MAGIC
;
688 hp
->version
= ASD_VERSION2
;
690 bzero(&hp
->filler
, sizeof(hp
->filler
));
691 hp
->entries
= (short)n
;
693 ep
->entryID
= EntryFinderInfo
;
694 ep
->offset
= p
- pp
- CORRECT
;
695 ep
->len
= INFOLEN
; /* sizeof(MacFInfo) + sizeof(FXInfo); */
697 bcopy(finderinfo
, p
, sizeof(FndrFileInfo
));
701 if ((fdout
= open(oFile
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0666)) < 0) {
707 /* write the ASDHeader */
708 if (write(fdout
, pp
, sizeof(ASDHeader
) - CORRECT
) == -1) {
715 /* write the ASDEntries */
716 if (write(fdout
, pp
+ sizeof(ASDHeader
), thesize
- sizeof(ASDHeader
)) == -1) {
724 (void)fchown(fdout
, uid
, gid
);
725 (void)fchmod(fdout
, mode
);
727 (void)lsetflags(oFile
, flags
);
728 utimes(oFile
, timep
);
732 #endif /* DUMP_MACOSX */
735 lgetflags(const char *path
, unsigned long *flags
)
740 err
= LSTAT(path
, &sb
);
744 if (S_ISLNK(sb
.st_mode
) || S_ISFIFO(sb
.st_mode
)) {
745 // no way to get/set flags on a symlink
750 return fgetflags(path
, flags
);
754 lsetflags(const char *path
, unsigned long flags
)
759 err
= LSTAT(path
, &sb
);
763 if (S_ISLNK(sb
.st_mode
) || S_ISFIFO(sb
.st_mode
)) {
764 // no way to get/set flags on a symlink
768 return fsetflags(path
, flags
);