]>
git.wh0rd.org - dump.git/blob - restore/dirs.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, 1995, 1996
9 * Copyright (c) 1983, 1993
10 * The Regents of the University of California. All rights reserved.
11 * (c) UNIX System Laboratories, Inc.
12 * All or some portions of this file are derived from material licensed
13 * to the University of California by American Telephone and Telegraph
14 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
15 * the permission of UNIX System Laboratories, Inc.
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
25 * 3. All advertising materials mentioning features or use of this software
26 * must display the following acknowledgement:
27 * This product includes software developed by the University of
28 * California, Berkeley and its contributors.
29 * 4. Neither the name of the University nor the names of its contributors
30 * may be used to endorse or promote products derived from this software
31 * without specific prior written permission.
33 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 static char sccsid
[] = "@(#)dirs.c 8.7 (Berkeley) 5/1/95";
50 #include <sys/param.h>
56 #include <linux/ext2_fs.h>
57 #include <bsdcompat.h>
59 #include <ufs/ufs/dinode.h>
60 #include <ufs/ufs/dir.h>
61 #include <ufs/ffs/fs.h>
62 #endif /* __linux__ */
63 #include <protocols/dumprestore.h>
74 #include <machine/endian.h>
77 #include "pathnames.h"
82 * Symbol table of directories read from tape.
85 #define INOHASH(val) (val % HASHSIZE)
87 struct inotab
*t_next
;
92 static struct inotab
*inotab
[HASHSIZE
];
95 * Information retained about directories.
99 struct timeval timep
[2];
107 * Definitions for library routines operating on directories.
110 #define DIRBLKSIZ 1024
115 char dd_buf
[DIRBLKSIZ
];
119 * Global variables for this file.
122 static FILE *df
, *mf
;
123 static RST_DIR
*dirp
;
124 static char dirfile
[32] = "#"; /* No file */
125 static char modefile
[32] = "#"; /* No file */
126 static char dot
[2] = "."; /* So it can be modified */
129 * Format of old style directories.
134 char d_name
[ODIRSIZ
];
138 static struct inotab
*allocinotab
__P((ino_t
, struct new_bsd_inode
*, long));
140 static struct inotab
*allocinotab
__P((ino_t
, struct dinode
*, long));
142 static void dcvt
__P((struct odirect
*, struct direct
*));
143 static void flushent
__P((void));
144 static struct inotab
*inotablookup
__P((ino_t
));
145 static RST_DIR
*opendirfile
__P((const char *));
146 static void putdir
__P((char *, long));
147 static void putent
__P((struct direct
*));
148 static void rst_seekdir
__P((RST_DIR
*, long, long));
149 static long rst_telldir
__P((RST_DIR
*));
150 static struct direct
*searchdir
__P((ino_t
, char *));
153 * Extract directory contents, building up a directory structure
154 * on disk for extraction by name.
155 * If genmode is requested, save mode, owner, and times for all
156 * directories on the tape.
164 register struct new_bsd_inode
*ip
;
166 register struct dinode
*ip
;
169 struct direct nulldir
;
171 vprintf(stdout
, "Extract directories from tape\n");
172 (void) sprintf(dirfile
, "%s/rstdir%d", tmpdir
, dumpdate
);
173 df
= fopen(dirfile
, "w");
176 "restore: %s - cannot create directory temporary\n",
178 fprintf(stderr
, "fopen: %s\n", strerror(errno
));
182 (void) sprintf(modefile
, "%s/rstmode%d", tmpdir
, dumpdate
);
183 mf
= fopen(modefile
, "w");
186 "restore: %s - cannot create modefile \n",
188 fprintf(stderr
, "fopen: %s\n", strerror(errno
));
194 nulldir
.d_type
= DT_DIR
;
196 nulldir
.d_namlen
= 1;
197 (void) strcpy(nulldir
.d_name
, "/");
198 nulldir
.d_reclen
= DIRSIZ(0, &nulldir
);
200 curfile
.name
= "<directory file - name unknown>";
201 curfile
.action
= USING
;
203 if (ip
== NULL
|| (ip
->di_mode
& IFMT
) != IFDIR
) {
205 dirp
= opendirfile(dirfile
);
207 fprintf(stderr
, "opendirfile: %s\n",
213 panic("Root directory is not on tape\n");
216 itp
= allocinotab(curfile
.ino
, ip
, seekpt
);
217 getfile(putdir
, xtrnull
);
220 itp
->t_size
= seekpt
- itp
->t_seekpt
;
225 * skip over all the directories on the tape
231 while (curfile
.dip
&& (curfile
.dip
->di_mode
& IFMT
) == IFDIR
) {
237 * Recursively find names and inumbers of all files in subtree
238 * pname and pass them off to be processed.
241 treescan(pname
, ino
, todo
)
244 long (*todo
) __P((char *, ino_t
, int));
246 register struct inotab
*itp
;
247 register struct direct
*dp
;
250 char locname
[MAXPATHLEN
+ 1];
252 itp
= inotablookup(ino
);
255 * Pname is name of a simple file or an unchanged directory.
257 (void) (*todo
)(pname
, ino
, LEAF
);
261 * Pname is a dumped directory name.
263 if ((*todo
)(pname
, ino
, NODE
) == FAIL
)
266 * begin search through the directory
267 * skipping over "." and ".."
269 (void) strncpy(locname
, pname
, MAXPATHLEN
);
270 (void) strncat(locname
, "/", MAXPATHLEN
);
271 namelen
= strlen(locname
);
272 rst_seekdir(dirp
, itp
->t_seekpt
, itp
->t_seekpt
);
273 dp
= rst_readdir(dirp
); /* "." */
274 if (dp
!= NULL
&& strcmp(dp
->d_name
, ".") == 0)
275 dp
= rst_readdir(dirp
); /* ".." */
277 fprintf(stderr
, "Warning: `.' missing from directory %s\n",
279 if (dp
!= NULL
&& strcmp(dp
->d_name
, "..") == 0)
280 dp
= rst_readdir(dirp
); /* first real entry */
282 fprintf(stderr
, "Warning: `..' missing from directory %s\n",
284 bpt
= rst_telldir(dirp
);
286 * a zero inode signals end of directory
289 locname
[namelen
] = '\0';
290 if (namelen
+ dp
->d_namlen
>= MAXPATHLEN
) {
291 fprintf(stderr
, "%s%s: name exceeds %d char\n",
292 locname
, dp
->d_name
, MAXPATHLEN
);
294 (void) strncat(locname
, dp
->d_name
, (int)dp
->d_namlen
);
295 treescan(locname
, dp
->d_ino
, todo
);
296 rst_seekdir(dirp
, bpt
, itp
->t_seekpt
);
298 dp
= rst_readdir(dirp
);
299 bpt
= rst_telldir(dirp
);
304 * Lookup a pathname which is always assumed to start from the ROOTINO.
308 const char *pathname
;
312 char *path
, *name
, buffer
[MAXPATHLEN
];
314 strcpy(buffer
, pathname
);
320 while ((name
= strsep(&path
, "/")) != NULL
&& *name
/* != NULL */) {
321 if ((dp
= searchdir(ino
, name
)) == NULL
)
329 * Lookup the requested name in directory inum.
330 * Return its inode number if found, zero if it does not exist.
332 static struct direct
*
333 searchdir(inum
, name
)
337 register struct direct
*dp
;
338 register struct inotab
*itp
;
341 itp
= inotablookup(inum
);
344 rst_seekdir(dirp
, itp
->t_seekpt
, itp
->t_seekpt
);
347 dp
= rst_readdir(dirp
);
350 } while (dp
->d_namlen
!= len
|| strncmp(dp
->d_name
, name
, len
) != 0);
355 * Put the directory entries in the directory file
362 struct direct cvtbuf
;
363 register struct odirect
*odp
;
364 struct odirect
*eodp
;
365 register struct direct
*dp
;
369 eodp
= (struct odirect
*)&buf
[size
];
370 for (odp
= (struct odirect
*)buf
; odp
< eodp
; odp
++)
371 if (odp
->d_ino
!= 0) {
376 for (loc
= 0; loc
< size
; ) {
377 dp
= (struct direct
*)(buf
+ loc
);
379 printf ("reclen = %d, namlen = %d, type = %d\n",
380 dp
->d_reclen
, dp
->d_namlen
, dp
->d_type
);
383 swabst((u_char
*)"ls", (u_char
*) dp
);
384 if (oldinofmt
&& dp
->d_ino
!= 0) {
387 swabst((u_char
*)"s", (u_char
*)&dp
->d_namlen
);
389 # if BYTE_ORDER == BIG_ENDIAN
391 dp
->d_namlen
= dp
->d_type
;
394 dp
->d_namlen
= dp
->d_type
;
396 #endif /* __linux__ */
397 dp
->d_type
= DT_UNKNOWN
;
401 * Horrible hack to read FreeBSD 2.0 dumps
404 swabst((u_char
*)"6bs", (u_char
*) dp
);
405 #endif /* __linux__ */
407 printf ("reclen = %d, namlen = %d, type = %d\n",
408 dp
->d_reclen
, dp
->d_namlen
, dp
->d_type
);
410 i
= DIRBLKSIZ
- (loc
& (DIRBLKSIZ
- 1));
411 if ((dp
->d_reclen
& 0x3) != 0 ||
413 dp
->d_reclen
< DIRSIZ(0, dp
) ||
414 dp
->d_namlen
> NAME_MAX
) {
415 vprintf(stdout
, "Mangled directory: ");
416 if ((dp
->d_reclen
& 0x3) != 0)
418 "reclen not multiple of 4 ");
419 if (dp
->d_reclen
< DIRSIZ(0, dp
))
421 "reclen less than DIRSIZ (%d < %d) ",
422 dp
->d_reclen
, DIRSIZ(0, dp
));
423 if (dp
->d_namlen
> NAME_MAX
)
425 "reclen name too big (%d > %d) ",
426 dp
->d_namlen
, NAME_MAX
);
427 vprintf(stdout
, "\n");
432 if (dp
->d_ino
!= 0) {
440 * These variables are "local" to the following two functions.
442 char dirbuf
[DIRBLKSIZ
];
447 * add a new directory entry to a file.
453 dp
->d_reclen
= DIRSIZ(0, dp
);
454 if (dirloc
+ dp
->d_reclen
> DIRBLKSIZ
) {
455 ((struct direct
*)(dirbuf
+ prev
))->d_reclen
=
457 (void) fwrite(dirbuf
, 1, DIRBLKSIZ
, df
);
460 memmove(dirbuf
+ dirloc
, dp
, (long)dp
->d_reclen
);
462 dirloc
+= dp
->d_reclen
;
466 * flush out a directory that is finished.
471 ((struct direct
*)(dirbuf
+ prev
))->d_reclen
= DIRBLKSIZ
- prev
;
472 (void) fwrite(dirbuf
, (int)dirloc
, 1, df
);
479 register struct odirect
*odp
;
480 register struct direct
*ndp
;
483 memset(ndp
, 0, (long)(sizeof *ndp
));
484 ndp
->d_ino
= odp
->d_ino
;
486 ndp
->d_type
= DT_UNKNOWN
;
488 (void) strncpy(ndp
->d_name
, odp
->d_name
, ODIRSIZ
);
489 ndp
->d_namlen
= strlen(ndp
->d_name
);
490 ndp
->d_reclen
= DIRSIZ(0, ndp
);
494 * Seek to an entry in a directory.
495 * Only values returned by rst_telldir should be passed to rst_seekdir.
496 * This routine handles many directories in a single file.
497 * It takes the base of the directory in the file, plus
498 * the desired seek offset into it.
501 rst_seekdir(dirp
, loc
, base
)
502 register RST_DIR
*dirp
;
506 if (loc
== rst_telldir(dirp
))
510 fprintf(stderr
, "bad seek pointer to rst_seekdir %d\n", loc
);
511 (void) lseek(dirp
->dd_fd
, base
+ (loc
& ~(DIRBLKSIZ
- 1)), SEEK_SET
);
512 dirp
->dd_loc
= loc
& (DIRBLKSIZ
- 1);
513 if (dirp
->dd_loc
!= 0)
514 dirp
->dd_size
= read(dirp
->dd_fd
, dirp
->dd_buf
, DIRBLKSIZ
);
518 * get next entry in a directory.
522 register RST_DIR
*dirp
;
524 register struct direct
*dp
;
527 if (dirp
->dd_loc
== 0) {
528 dirp
->dd_size
= read(dirp
->dd_fd
, dirp
->dd_buf
,
530 if (dirp
->dd_size
<= 0) {
531 dprintf(stderr
, "error reading directory\n");
535 if (dirp
->dd_loc
>= dirp
->dd_size
) {
539 dp
= (struct direct
*)(dirp
->dd_buf
+ dirp
->dd_loc
);
540 if (dp
->d_reclen
== 0 ||
541 dp
->d_reclen
> DIRBLKSIZ
+ 1 - dirp
->dd_loc
) {
542 dprintf(stderr
, "corrupted directory: bad reclen %d\n"
543 "dd_loc = %d, dd_size = %d\n",
544 dp
->d_reclen
, dirp
->dd_loc
, dirp
->dd_size
);
547 dirp
->dd_loc
+= dp
->d_reclen
;
548 if (dp
->d_ino
== 0 && strcmp(dp
->d_name
, "/") == 0)
550 if (dp
->d_ino
>= maxino
) {
551 dprintf(stderr
, "corrupted directory: bad inum %d\n",
560 * Simulate the opening of a directory
570 if ((ino
= dirlookup(name
)) > 0 &&
571 (itp
= inotablookup(ino
)) != NULL
) {
572 dirp
= opendirfile(dirfile
);
573 rst_seekdir(dirp
, itp
->t_seekpt
, itp
->t_seekpt
);
580 * In our case, there is nothing to do when closing a directory.
587 (void)close(dirp
->dd_fd
);
593 * Simulate finding the current offset in the directory.
599 return ((long)lseek(dirp
->dd_fd
,
600 (off_t
)0, SEEK_CUR
) - dirp
->dd_size
+ dirp
->dd_loc
);
604 * Open a directory file.
610 register RST_DIR
*dirp
;
613 if ((fd
= open(name
, O_RDONLY
)) == -1)
615 if ((dirp
= malloc(sizeof(RST_DIR
))) == NULL
) {
625 * Set the mode, owner, and times for all new or changed directories
632 struct modeinfo node
;
636 vprintf(stdout
, "Set directory mode, owner, and times.\n");
637 (void) sprintf(modefile
, "%s/rstmode%d", tmpdir
, dumpdate
);
638 mf
= fopen(modefile
, "r");
640 fprintf(stderr
, "fopen: %s\n", strerror(errno
));
641 fprintf(stderr
, "cannot open mode file %s\n", modefile
);
642 fprintf(stderr
, "directory mode, owner, and times not set\n");
647 (void) fread((char *)&node
, 1, sizeof(struct modeinfo
), mf
);
650 ep
= lookupino(node
.ino
);
651 if (command
== 'i' || command
== 'x') {
654 if ((flags
& FORCE
) == 0 && ep
->e_flags
& EXISTED
) {
658 if (node
.ino
== ROOTINO
&&
659 reply("set owner/mode for '.'") == FAIL
)
663 panic("cannot find directory inode %d\n", node
.ino
);
666 (void) chown(cp
, node
.uid
, node
.gid
);
667 (void) chmod(cp
, node
.mode
);
669 (void) setflags(cp
, node
.flags
);
671 (void) chflags(cp
, node
.flags
);
673 utimes(cp
, node
.timep
);
678 panic("error setting directory modes\n");
683 * Generate a literal copy of a directory.
686 genliteraldir(name
, ino
)
690 register struct inotab
*itp
;
691 int ofile
, dp
, i
, size
;
694 itp
= inotablookup(ino
);
696 panic("Cannot find directory inode %d named %s\n", ino
, name
);
697 if ((ofile
= open(name
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0666)) < 0) {
698 fprintf(stderr
, "%s: ", name
);
699 (void) fflush(stderr
);
700 fprintf(stderr
, "cannot create file: %s\n", strerror(errno
));
703 rst_seekdir(dirp
, itp
->t_seekpt
, itp
->t_seekpt
);
704 dp
= dup(dirp
->dd_fd
);
705 for (i
= itp
->t_size
; i
> 0; i
-= BUFSIZ
) {
706 size
= i
< BUFSIZ
? i
: BUFSIZ
;
707 if (read(dp
, buf
, (int) size
) == -1) {
709 "write error extracting inode %d, name %s\n",
710 curfile
.ino
, curfile
.name
);
711 fprintf(stderr
, "read: %s\n", strerror(errno
));
714 if (!Nflag
&& write(ofile
, buf
, (int) size
) == -1) {
716 "write error extracting inode %d, name %s\n",
717 curfile
.ino
, curfile
.name
);
718 fprintf(stderr
, "write: %s\n", strerror(errno
));
728 * Determine the type of an inode
736 itp
= inotablookup(ino
);
743 * Allocate and initialize a directory inode entry.
744 * If requested, save its pertinent mode, owner, and time info.
746 static struct inotab
*
747 allocinotab(ino
, dip
, seekpt
)
750 struct new_bsd_inode
*dip
;
756 register struct inotab
*itp
;
757 struct modeinfo node
;
759 itp
= calloc(1, sizeof(struct inotab
));
761 panic("no memory directory table\n");
762 itp
->t_next
= inotab
[INOHASH(ino
)];
763 inotab
[INOHASH(ino
)] = itp
;
765 itp
->t_seekpt
= seekpt
;
770 node
.timep
[0].tv_sec
= dip
->di_atime
.tv_sec
;
771 node
.timep
[0].tv_usec
= dip
->di_atime
.tv_usec
;
772 node
.timep
[1].tv_sec
= dip
->di_mtime
.tv_sec
;
773 node
.timep
[1].tv_usec
= dip
->di_mtime
.tv_usec
;
774 #else /* __linux__ */
775 node
.timep
[0].tv_sec
= dip
->di_atime
;
776 node
.timep
[0].tv_usec
= dip
->di_atimensec
/ 1000;
777 node
.timep
[1].tv_sec
= dip
->di_mtime
;
778 node
.timep
[1].tv_usec
= dip
->di_mtimensec
/ 1000;
779 #endif /* __linux__ */
780 node
.mode
= dip
->di_mode
;
781 node
.flags
= dip
->di_flags
;
782 node
.uid
= dip
->di_uid
;
783 node
.gid
= dip
->di_gid
;
784 (void) fwrite((char *)&node
, 1, sizeof(struct modeinfo
), mf
);
789 * Look up an inode in the table of directories
791 static struct inotab
*
795 register struct inotab
*itp
;
797 for (itp
= inotab
[INOHASH(ino
)]; itp
!= NULL
; itp
= itp
->t_next
)
798 if (itp
->t_ino
== ino
)
812 if (modefile
[0] != '#')
813 (void) unlink(modefile
);
814 if (dirfile
[0] != '#')
815 (void) unlink(dirfile
);