Commit | Line | Data |
---|---|---|
8c5eec2f | 1 | /* |
e7a042ee KB |
2 | * Copyright (c) 1983, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
b42768a6 | 4 | * |
70ab3c27 | 5 | * %sccs.include.redist.c% |
8c5eec2f | 6 | */ |
f743fc86 | 7 | |
8c5eec2f | 8 | #ifndef lint |
e7a042ee | 9 | static char sccsid[] = "@(#)dirs.c 8.1 (Berkeley) %G%"; |
b42768a6 | 10 | #endif /* not lint */ |
ebd1f727 | 11 | |
451eb9a1 | 12 | #include <sys/param.h> |
9f13f26d | 13 | #include <sys/file.h> |
451eb9a1 KB |
14 | #include <sys/stat.h> |
15 | #include <sys/time.h> | |
16 | ||
17 | #include <ufs/ffs/fs.h> | |
18 | #include <ufs/ufs/dinode.h> | |
54e63ce6 | 19 | #include <ufs/ufs/dir.h> |
451eb9a1 KB |
20 | #include <protocols/dumprestore.h> |
21 | ||
22 | #include <errno.h> | |
23 | #include <stdio.h> | |
24 | #include <stdlib.h> | |
25 | #include <string.h> | |
26 | #include <unistd.h> | |
27 | ||
7abf8d65 | 28 | #include "pathnames.h" |
451eb9a1 KB |
29 | #include "restore.h" |
30 | #include "extern.h" | |
f743fc86 | 31 | |
7432ff81 KM |
32 | /* |
33 | * Symbol table of directories read from tape. | |
34 | */ | |
f743fc86 | 35 | #define HASHSIZE 1000 |
f743fc86 KM |
36 | #define INOHASH(val) (val % HASHSIZE) |
37 | struct inotab { | |
a1026118 | 38 | struct inotab *t_next; |
f743fc86 | 39 | ino_t t_ino; |
a1026118 KM |
40 | long t_seekpt; |
41 | long t_size; | |
9f13f26d KM |
42 | }; |
43 | static struct inotab *inotab[HASHSIZE]; | |
f743fc86 | 44 | |
7432ff81 KM |
45 | /* |
46 | * Information retained about directories. | |
47 | */ | |
f743fc86 KM |
48 | struct modeinfo { |
49 | ino_t ino; | |
2934efa5 | 50 | struct timeval timep[2]; |
f743fc86 KM |
51 | short mode; |
52 | short uid; | |
53 | short gid; | |
54 | }; | |
55 | ||
460e5a20 KM |
56 | /* |
57 | * Definitions for library routines operating on directories. | |
58 | */ | |
8b58f36b KM |
59 | #undef DIRBLKSIZ |
60 | #define DIRBLKSIZ 1024 | |
964196c4 | 61 | struct rstdirdesc { |
460e5a20 KM |
62 | int dd_fd; |
63 | long dd_loc; | |
64 | long dd_size; | |
65 | char dd_buf[DIRBLKSIZ]; | |
66 | }; | |
460e5a20 | 67 | |
7432ff81 KM |
68 | /* |
69 | * Global variables for this file. | |
70 | */ | |
a1026118 | 71 | static long seekpt; |
9f13f26d | 72 | static FILE *df, *mf; |
964196c4 | 73 | static RST_DIR *dirp; |
7432ff81 KM |
74 | static char dirfile[32] = "#"; /* No file */ |
75 | static char modefile[32] = "#"; /* No file */ | |
d3b2e2cc | 76 | static char dot[2] = "."; /* So it can be modified */ |
f743fc86 | 77 | |
7432ff81 KM |
78 | /* |
79 | * Format of old style directories. | |
80 | */ | |
f743fc86 KM |
81 | #define ODIRSIZ 14 |
82 | struct odirect { | |
83 | u_short d_ino; | |
84 | char d_name[ODIRSIZ]; | |
85 | }; | |
86 | ||
451eb9a1 KB |
87 | static struct inotab *allocinotab __P((ino_t, struct dinode *, long)); |
88 | static void dcvt __P((struct odirect *, struct direct *)); | |
89 | static void flushent __P((void)); | |
90 | static struct inotab *inotablookup __P((ino_t)); | |
2528da40 | 91 | static RST_DIR *opendirfile __P((const char *)); |
451eb9a1 KB |
92 | static void putdir __P((char *, long)); |
93 | static void putent __P((struct direct *)); | |
94 | static void rst_seekdir __P((RST_DIR *, long, long)); | |
95 | static long rst_telldir __P((RST_DIR *)); | |
2e723f30 | 96 | static struct direct *searchdir __P((ino_t, char *)); |
451eb9a1 | 97 | |
f743fc86 KM |
98 | /* |
99 | * Extract directory contents, building up a directory structure | |
100 | * on disk for extraction by name. | |
7432ff81 | 101 | * If genmode is requested, save mode, owner, and times for all |
f743fc86 KM |
102 | * directories on the tape. |
103 | */ | |
451eb9a1 | 104 | void |
7432ff81 KM |
105 | extractdirs(genmode) |
106 | int genmode; | |
f743fc86 KM |
107 | { |
108 | register int i; | |
109 | register struct dinode *ip; | |
9730f69a | 110 | struct inotab *itp; |
f743fc86 | 111 | struct direct nulldir; |
f743fc86 KM |
112 | |
113 | vprintf(stdout, "Extract directories from tape\n"); | |
7abf8d65 | 114 | (void) sprintf(dirfile, "%s/rstdir%d", _PATH_TMP, dumpdate); |
f743fc86 | 115 | df = fopen(dirfile, "w"); |
202d77b7 | 116 | if (df == NULL) { |
f743fc86 | 117 | fprintf(stderr, |
97b06931 | 118 | "restore: %s - cannot create directory temporary\n", |
f743fc86 | 119 | dirfile); |
451eb9a1 | 120 | fprintf(stderr, "fopen: %s\n", strerror(errno)); |
f743fc86 KM |
121 | done(1); |
122 | } | |
7432ff81 | 123 | if (genmode != 0) { |
7abf8d65 | 124 | (void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate); |
f743fc86 | 125 | mf = fopen(modefile, "w"); |
202d77b7 | 126 | if (mf == NULL) { |
f743fc86 | 127 | fprintf(stderr, |
97b06931 | 128 | "restore: %s - cannot create modefile \n", |
f743fc86 | 129 | modefile); |
451eb9a1 | 130 | fprintf(stderr, "fopen: %s\n", strerror(errno)); |
f743fc86 KM |
131 | done(1); |
132 | } | |
133 | } | |
9730f69a | 134 | nulldir.d_ino = 0; |
aa79807a | 135 | nulldir.d_type = DT_DIR; |
f743fc86 | 136 | nulldir.d_namlen = 1; |
93d90477 | 137 | (void) strcpy(nulldir.d_name, "/"); |
aa79807a | 138 | nulldir.d_reclen = DIRSIZ(0, &nulldir); |
f743fc86 KM |
139 | for (;;) { |
140 | curfile.name = "<directory file - name unknown>"; | |
141 | curfile.action = USING; | |
142 | ip = curfile.dip; | |
58ee757a | 143 | if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) { |
82d46726 | 144 | (void) fclose(df); |
97d5016b | 145 | dirp = opendirfile(dirfile); |
f743fc86 | 146 | if (dirp == NULL) |
451eb9a1 KB |
147 | fprintf(stderr, "opendirfile: %s\n", |
148 | strerror(errno)); | |
f743fc86 | 149 | if (mf != NULL) |
82d46726 | 150 | (void) fclose(mf); |
d3b2e2cc | 151 | i = dirlookup(dot); |
7432ff81 | 152 | if (i == 0) |
7851e15d | 153 | panic("Root directory is not on tape\n"); |
f743fc86 KM |
154 | return; |
155 | } | |
9730f69a | 156 | itp = allocinotab(curfile.ino, ip, seekpt); |
053180fe | 157 | getfile(putdir, xtrnull); |
f743fc86 KM |
158 | putent(&nulldir); |
159 | flushent(); | |
9730f69a KM |
160 | itp->t_size = seekpt - itp->t_seekpt; |
161 | } | |
162 | } | |
163 | ||
164 | /* | |
165 | * skip over all the directories on the tape | |
166 | */ | |
451eb9a1 | 167 | void |
9730f69a KM |
168 | skipdirs() |
169 | { | |
170 | ||
171 | while ((curfile.dip->di_mode & IFMT) == IFDIR) { | |
172 | skipfile(); | |
f743fc86 KM |
173 | } |
174 | } | |
175 | ||
176 | /* | |
177 | * Recursively find names and inumbers of all files in subtree | |
178 | * pname and pass them off to be processed. | |
179 | */ | |
451eb9a1 | 180 | void |
f743fc86 KM |
181 | treescan(pname, ino, todo) |
182 | char *pname; | |
183 | ino_t ino; | |
451eb9a1 | 184 | long (*todo) __P((char *, ino_t, int)); |
f743fc86 KM |
185 | { |
186 | register struct inotab *itp; | |
93d90477 | 187 | register struct direct *dp; |
f743fc86 | 188 | int namelen; |
a1026118 | 189 | long bpt; |
4796d2a4 | 190 | char locname[MAXPATHLEN + 1]; |
f743fc86 KM |
191 | |
192 | itp = inotablookup(ino); | |
193 | if (itp == NULL) { | |
194 | /* | |
195 | * Pname is name of a simple file or an unchanged directory. | |
196 | */ | |
314ac756 | 197 | (void) (*todo)(pname, ino, LEAF); |
f743fc86 KM |
198 | return; |
199 | } | |
200 | /* | |
201 | * Pname is a dumped directory name. | |
202 | */ | |
314ac756 KM |
203 | if ((*todo)(pname, ino, NODE) == FAIL) |
204 | return; | |
f743fc86 KM |
205 | /* |
206 | * begin search through the directory | |
207 | * skipping over "." and ".." | |
208 | */ | |
7432ff81 KM |
209 | (void) strncpy(locname, pname, MAXPATHLEN); |
210 | (void) strncat(locname, "/", MAXPATHLEN); | |
f743fc86 | 211 | namelen = strlen(locname); |
e9e7ecc4 KM |
212 | rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); |
213 | dp = rst_readdir(dirp); /* "." */ | |
329dd5fb | 214 | if (dp != NULL && strcmp(dp->d_name, ".") == 0) |
e9e7ecc4 | 215 | dp = rst_readdir(dirp); /* ".." */ |
329dd5fb KM |
216 | else |
217 | fprintf(stderr, "Warning: `.' missing from directory %s\n", | |
218 | pname); | |
219 | if (dp != NULL && strcmp(dp->d_name, "..") == 0) | |
e9e7ecc4 | 220 | dp = rst_readdir(dirp); /* first real entry */ |
329dd5fb KM |
221 | else |
222 | fprintf(stderr, "Warning: `..' missing from directory %s\n", | |
223 | pname); | |
97d5016b | 224 | bpt = rst_telldir(dirp); |
f743fc86 | 225 | /* |
93d90477 | 226 | * a zero inode signals end of directory |
f743fc86 | 227 | */ |
93d90477 | 228 | while (dp != NULL && dp->d_ino != 0) { |
f743fc86 | 229 | locname[namelen] = '\0'; |
4796d2a4 | 230 | if (namelen + dp->d_namlen >= MAXPATHLEN) { |
f743fc86 | 231 | fprintf(stderr, "%s%s: name exceeds %d char\n", |
4796d2a4 | 232 | locname, dp->d_name, MAXPATHLEN); |
f743fc86 | 233 | } else { |
7432ff81 | 234 | (void) strncat(locname, dp->d_name, (int)dp->d_namlen); |
f743fc86 | 235 | treescan(locname, dp->d_ino, todo); |
e9e7ecc4 | 236 | rst_seekdir(dirp, bpt, itp->t_seekpt); |
f743fc86 | 237 | } |
e9e7ecc4 | 238 | dp = rst_readdir(dirp); |
97d5016b | 239 | bpt = rst_telldir(dirp); |
f743fc86 KM |
240 | } |
241 | if (dp == NULL) | |
242 | fprintf(stderr, "corrupted directory: %s.\n", locname); | |
243 | } | |
244 | ||
245 | /* | |
053180fe | 246 | * Lookup a pathname which is always assumed to start from the ROOTINO. |
f743fc86 | 247 | */ |
2e723f30 | 248 | struct direct * |
053180fe | 249 | pathsearch(pathname) |
2528da40 | 250 | const char *pathname; |
f743fc86 | 251 | { |
f743fc86 | 252 | ino_t ino; |
2e723f30 | 253 | struct direct *dp; |
2528da40 | 254 | char *path, *name, buffer[MAXPATHLEN]; |
f743fc86 | 255 | |
053180fe | 256 | strcpy(buffer, pathname); |
2528da40 | 257 | path = buffer; |
f743fc86 | 258 | ino = ROOTINO; |
2528da40 KB |
259 | while (*path == '/') |
260 | path++; | |
202d77b7 | 261 | dp = NULL; |
2528da40 | 262 | while ((name = strsep(&path, "/")) != NULL && *name != NULL) { |
202d77b7 | 263 | if ((dp = searchdir(ino, name)) == NULL) |
2e723f30 KM |
264 | return (NULL); |
265 | ino = dp->d_ino; | |
266 | } | |
267 | return (dp); | |
f743fc86 KM |
268 | } |
269 | ||
270 | /* | |
053180fe KM |
271 | * Lookup the requested name in directory inum. |
272 | * Return its inode number if found, zero if it does not exist. | |
f743fc86 | 273 | */ |
2e723f30 | 274 | static struct direct * |
053180fe | 275 | searchdir(inum, name) |
f743fc86 | 276 | ino_t inum; |
053180fe | 277 | char *name; |
f743fc86 KM |
278 | { |
279 | register struct direct *dp; | |
280 | register struct inotab *itp; | |
281 | int len; | |
282 | ||
283 | itp = inotablookup(inum); | |
284 | if (itp == NULL) | |
202d77b7 | 285 | return (NULL); |
e9e7ecc4 | 286 | rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); |
053180fe | 287 | len = strlen(name); |
f743fc86 | 288 | do { |
e9e7ecc4 | 289 | dp = rst_readdir(dirp); |
93d90477 | 290 | if (dp == NULL || dp->d_ino == 0) |
2e723f30 | 291 | return (NULL); |
053180fe | 292 | } while (dp->d_namlen != len || strncmp(dp->d_name, name, len) != 0); |
2e723f30 | 293 | return (dp); |
f743fc86 KM |
294 | } |
295 | ||
296 | /* | |
297 | * Put the directory entries in the directory file | |
298 | */ | |
451eb9a1 | 299 | static void |
f743fc86 KM |
300 | putdir(buf, size) |
301 | char *buf; | |
451eb9a1 | 302 | long size; |
f743fc86 KM |
303 | { |
304 | struct direct cvtbuf; | |
305 | register struct odirect *odp; | |
306 | struct odirect *eodp; | |
307 | register struct direct *dp; | |
308 | long loc, i; | |
309 | ||
310 | if (cvtflag) { | |
311 | eodp = (struct odirect *)&buf[size]; | |
312 | for (odp = (struct odirect *)buf; odp < eodp; odp++) | |
313 | if (odp->d_ino != 0) { | |
314 | dcvt(odp, &cvtbuf); | |
315 | putent(&cvtbuf); | |
316 | } | |
317 | } else { | |
318 | for (loc = 0; loc < size; ) { | |
319 | dp = (struct direct *)(buf + loc); | |
aa79807a KM |
320 | if (oldinofmt) { |
321 | if (Bcvt) { | |
451eb9a1 | 322 | swabst((u_char *)"l2s", (u_char *) dp); |
aa79807a KM |
323 | } |
324 | } else { | |
325 | if (Bcvt) { | |
451eb9a1 | 326 | swabst((u_char *)"ls", (u_char *) dp); |
aa79807a | 327 | } |
10462cc1 | 328 | } |
f743fc86 | 329 | i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); |
8b58f36b KM |
330 | if ((dp->d_reclen & 0x3) != 0 || |
331 | dp->d_reclen > i || | |
aa79807a | 332 | dp->d_reclen < DIRSIZ(0, dp) || |
a1026118 KM |
333 | dp->d_namlen > NAME_MAX) { |
334 | vprintf(stdout, "Mangled directory: "); | |
335 | if ((dp->d_reclen & 0x3) != 0) | |
336 | vprintf(stdout, | |
337 | "reclen not multiple of 4 "); | |
aa79807a | 338 | if (dp->d_reclen < DIRSIZ(0, dp)) |
a1026118 KM |
339 | vprintf(stdout, |
340 | "reclen less than DIRSIZ (%d < %d) ", | |
aa79807a | 341 | dp->d_reclen, DIRSIZ(0, dp)); |
a1026118 KM |
342 | if (dp->d_namlen > NAME_MAX) |
343 | vprintf(stdout, | |
344 | "reclen name too big (%d > %d) ", | |
345 | dp->d_namlen, NAME_MAX); | |
346 | vprintf(stdout, "\n"); | |
f743fc86 KM |
347 | loc += i; |
348 | continue; | |
349 | } | |
350 | loc += dp->d_reclen; | |
351 | if (dp->d_ino != 0) { | |
352 | putent(dp); | |
353 | } | |
354 | } | |
355 | } | |
356 | } | |
357 | ||
358 | /* | |
359 | * These variables are "local" to the following two functions. | |
360 | */ | |
361 | char dirbuf[DIRBLKSIZ]; | |
362 | long dirloc = 0; | |
363 | long prev = 0; | |
364 | ||
365 | /* | |
366 | * add a new directory entry to a file. | |
367 | */ | |
451eb9a1 | 368 | static void |
f743fc86 KM |
369 | putent(dp) |
370 | struct direct *dp; | |
371 | { | |
aa79807a | 372 | dp->d_reclen = DIRSIZ(0, dp); |
f743fc86 KM |
373 | if (dirloc + dp->d_reclen > DIRBLKSIZ) { |
374 | ((struct direct *)(dirbuf + prev))->d_reclen = | |
375 | DIRBLKSIZ - prev; | |
82d46726 | 376 | (void) fwrite(dirbuf, 1, DIRBLKSIZ, df); |
f743fc86 KM |
377 | dirloc = 0; |
378 | } | |
379 | bcopy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen); | |
380 | prev = dirloc; | |
381 | dirloc += dp->d_reclen; | |
382 | } | |
383 | ||
384 | /* | |
385 | * flush out a directory that is finished. | |
386 | */ | |
451eb9a1 | 387 | static void |
f743fc86 KM |
388 | flushent() |
389 | { | |
f743fc86 | 390 | ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; |
82d46726 | 391 | (void) fwrite(dirbuf, (int)dirloc, 1, df); |
f743fc86 KM |
392 | seekpt = ftell(df); |
393 | dirloc = 0; | |
394 | } | |
395 | ||
451eb9a1 | 396 | static void |
f743fc86 KM |
397 | dcvt(odp, ndp) |
398 | register struct odirect *odp; | |
399 | register struct direct *ndp; | |
400 | { | |
401 | ||
402 | bzero((char *)ndp, (long)(sizeof *ndp)); | |
403 | ndp->d_ino = odp->d_ino; | |
aa79807a | 404 | ndp->d_type = DT_UNKNOWN; |
7432ff81 | 405 | (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ); |
f743fc86 | 406 | ndp->d_namlen = strlen(ndp->d_name); |
aa79807a | 407 | ndp->d_reclen = DIRSIZ(0, ndp); |
f743fc86 KM |
408 | } |
409 | ||
410 | /* | |
411 | * Seek to an entry in a directory. | |
97d5016b | 412 | * Only values returned by rst_telldir should be passed to rst_seekdir. |
82d46726 KM |
413 | * This routine handles many directories in a single file. |
414 | * It takes the base of the directory in the file, plus | |
415 | * the desired seek offset into it. | |
f743fc86 | 416 | */ |
451eb9a1 | 417 | static void |
e9e7ecc4 | 418 | rst_seekdir(dirp, loc, base) |
964196c4 | 419 | register RST_DIR *dirp; |
a1026118 | 420 | long loc, base; |
f743fc86 KM |
421 | { |
422 | ||
97d5016b | 423 | if (loc == rst_telldir(dirp)) |
f743fc86 KM |
424 | return; |
425 | loc -= base; | |
426 | if (loc < 0) | |
e9e7ecc4 | 427 | fprintf(stderr, "bad seek pointer to rst_seekdir %d\n", loc); |
451eb9a1 | 428 | (void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), SEEK_SET); |
f743fc86 KM |
429 | dirp->dd_loc = loc & (DIRBLKSIZ - 1); |
430 | if (dirp->dd_loc != 0) | |
431 | dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ); | |
432 | } | |
433 | ||
434 | /* | |
435 | * get next entry in a directory. | |
436 | */ | |
437 | struct direct * | |
e9e7ecc4 | 438 | rst_readdir(dirp) |
964196c4 | 439 | register RST_DIR *dirp; |
f743fc86 KM |
440 | { |
441 | register struct direct *dp; | |
442 | ||
443 | for (;;) { | |
444 | if (dirp->dd_loc == 0) { | |
445 | dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, | |
446 | DIRBLKSIZ); | |
93d90477 KM |
447 | if (dirp->dd_size <= 0) { |
448 | dprintf(stderr, "error reading directory\n"); | |
451eb9a1 | 449 | return (NULL); |
93d90477 | 450 | } |
f743fc86 KM |
451 | } |
452 | if (dirp->dd_loc >= dirp->dd_size) { | |
453 | dirp->dd_loc = 0; | |
454 | continue; | |
455 | } | |
456 | dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc); | |
457 | if (dp->d_reclen == 0 || | |
93d90477 KM |
458 | dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) { |
459 | dprintf(stderr, "corrupted directory: bad reclen %d\n", | |
460 | dp->d_reclen); | |
451eb9a1 | 461 | return (NULL); |
93d90477 | 462 | } |
f743fc86 | 463 | dirp->dd_loc += dp->d_reclen; |
93d90477 KM |
464 | if (dp->d_ino == 0 && strcmp(dp->d_name, "/") != 0) |
465 | continue; | |
e9e7ecc4 | 466 | if (dp->d_ino >= maxino) { |
93d90477 KM |
467 | dprintf(stderr, "corrupted directory: bad inum %d\n", |
468 | dp->d_ino); | |
469 | continue; | |
470 | } | |
f743fc86 KM |
471 | return (dp); |
472 | } | |
473 | } | |
474 | ||
f97d7036 KM |
475 | /* |
476 | * Simulate the opening of a directory | |
477 | */ | |
964196c4 | 478 | RST_DIR * |
f97d7036 | 479 | rst_opendir(name) |
2528da40 | 480 | const char *name; |
f97d7036 KM |
481 | { |
482 | struct inotab *itp; | |
2e723f30 | 483 | RST_DIR *dirp; |
f97d7036 KM |
484 | ino_t ino; |
485 | ||
486 | if ((ino = dirlookup(name)) > 0 && | |
487 | (itp = inotablookup(ino)) != NULL) { | |
2e723f30 | 488 | dirp = opendirfile(dirfile); |
f97d7036 KM |
489 | rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); |
490 | return (dirp); | |
491 | } | |
202d77b7 | 492 | return (NULL); |
f97d7036 KM |
493 | } |
494 | ||
2e723f30 KM |
495 | /* |
496 | * In our case, there is nothing to do when closing a directory. | |
497 | */ | |
498 | void | |
499 | rst_closedir(dirp) | |
500 | RST_DIR *dirp; | |
501 | { | |
502 | ||
2528da40 | 503 | (void)close(dirp->dd_fd); |
2e723f30 KM |
504 | free(dirp); |
505 | return; | |
506 | } | |
507 | ||
97d5016b KM |
508 | /* |
509 | * Simulate finding the current offset in the directory. | |
510 | */ | |
451eb9a1 | 511 | static long |
97d5016b | 512 | rst_telldir(dirp) |
964196c4 | 513 | RST_DIR *dirp; |
97d5016b | 514 | { |
451eb9a1 KB |
515 | return ((long)lseek(dirp->dd_fd, |
516 | (off_t)0, SEEK_CUR) - dirp->dd_size + dirp->dd_loc); | |
97d5016b KM |
517 | } |
518 | ||
519 | /* | |
520 | * Open a directory file. | |
521 | */ | |
451eb9a1 | 522 | static RST_DIR * |
97d5016b | 523 | opendirfile(name) |
2528da40 | 524 | const char *name; |
97d5016b | 525 | { |
964196c4 | 526 | register RST_DIR *dirp; |
97d5016b KM |
527 | register int fd; |
528 | ||
451eb9a1 KB |
529 | if ((fd = open(name, O_RDONLY)) == -1) |
530 | return (NULL); | |
531 | if ((dirp = malloc(sizeof(RST_DIR))) == NULL) { | |
532 | (void)close(fd); | |
533 | return (NULL); | |
97d5016b KM |
534 | } |
535 | dirp->dd_fd = fd; | |
536 | dirp->dd_loc = 0; | |
451eb9a1 | 537 | return (dirp); |
97d5016b KM |
538 | } |
539 | ||
f743fc86 KM |
540 | /* |
541 | * Set the mode, owner, and times for all new or changed directories | |
542 | */ | |
451eb9a1 | 543 | void |
c0e819cb KM |
544 | setdirmodes(flags) |
545 | int flags; | |
f743fc86 KM |
546 | { |
547 | FILE *mf; | |
548 | struct modeinfo node; | |
549 | struct entry *ep; | |
550 | char *cp; | |
551 | ||
552 | vprintf(stdout, "Set directory mode, owner, and times.\n"); | |
7abf8d65 | 553 | (void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate); |
f743fc86 KM |
554 | mf = fopen(modefile, "r"); |
555 | if (mf == NULL) { | |
451eb9a1 | 556 | fprintf(stderr, "fopen: %s\n", strerror(errno)); |
97b06931 KM |
557 | fprintf(stderr, "cannot open mode file %s\n", modefile); |
558 | fprintf(stderr, "directory mode, owner, and times not set\n"); | |
559 | return; | |
f743fc86 KM |
560 | } |
561 | clearerr(mf); | |
9f13f26d | 562 | for (;;) { |
82d46726 | 563 | (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf); |
9f13f26d KM |
564 | if (feof(mf)) |
565 | break; | |
f743fc86 | 566 | ep = lookupino(node.ino); |
47769c2e | 567 | if (command == 'i' || command == 'x') { |
451eb9a1 | 568 | if (ep == NULL) |
47769c2e | 569 | continue; |
c0e819cb | 570 | if ((flags & FORCE) == 0 && ep->e_flags & EXISTED) { |
a7d37956 KM |
571 | ep->e_flags &= ~NEW; |
572 | continue; | |
573 | } | |
47769c2e KM |
574 | if (node.ino == ROOTINO && |
575 | reply("set owner/mode for '.'") == FAIL) | |
9f13f26d | 576 | continue; |
9f13f26d | 577 | } |
451eb9a1 | 578 | if (ep == NULL) { |
47769c2e | 579 | panic("cannot find directory inode %d\n", node.ino); |
666f15d9 KM |
580 | } else { |
581 | cp = myname(ep); | |
582 | (void) chown(cp, node.uid, node.gid); | |
583 | (void) chmod(cp, node.mode); | |
584 | utimes(cp, node.timep); | |
585 | ep->e_flags &= ~NEW; | |
586 | } | |
f743fc86 KM |
587 | } |
588 | if (ferror(mf)) | |
589 | panic("error setting directory modes\n"); | |
82d46726 | 590 | (void) fclose(mf); |
f743fc86 KM |
591 | } |
592 | ||
593 | /* | |
594 | * Generate a literal copy of a directory. | |
595 | */ | |
451eb9a1 | 596 | int |
f743fc86 KM |
597 | genliteraldir(name, ino) |
598 | char *name; | |
599 | ino_t ino; | |
600 | { | |
601 | register struct inotab *itp; | |
602 | int ofile, dp, i, size; | |
603 | char buf[BUFSIZ]; | |
604 | ||
605 | itp = inotablookup(ino); | |
606 | if (itp == NULL) | |
9730f69a | 607 | panic("Cannot find directory inode %d named %s\n", ino, name); |
15aeb519 | 608 | if ((ofile = creat(name, 0666)) < 0) { |
e9e7ecc4 KM |
609 | fprintf(stderr, "%s: ", name); |
610 | (void) fflush(stderr); | |
451eb9a1 | 611 | fprintf(stderr, "cannot create file: %s\n", strerror(errno)); |
f743fc86 KM |
612 | return (FAIL); |
613 | } | |
e9e7ecc4 | 614 | rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); |
f743fc86 KM |
615 | dp = dup(dirp->dd_fd); |
616 | for (i = itp->t_size; i > 0; i -= BUFSIZ) { | |
617 | size = i < BUFSIZ ? i : BUFSIZ; | |
618 | if (read(dp, buf, (int) size) == -1) { | |
619 | fprintf(stderr, | |
620 | "write error extracting inode %d, name %s\n", | |
621 | curfile.ino, curfile.name); | |
451eb9a1 | 622 | fprintf(stderr, "read: %s\n", strerror(errno)); |
f743fc86 KM |
623 | done(1); |
624 | } | |
414c4f09 | 625 | if (!Nflag && write(ofile, buf, (int) size) == -1) { |
f743fc86 KM |
626 | fprintf(stderr, |
627 | "write error extracting inode %d, name %s\n", | |
628 | curfile.ino, curfile.name); | |
451eb9a1 | 629 | fprintf(stderr, "write: %s\n", strerror(errno)); |
f743fc86 KM |
630 | done(1); |
631 | } | |
632 | } | |
82d46726 KM |
633 | (void) close(dp); |
634 | (void) close(ofile); | |
f743fc86 KM |
635 | return (GOOD); |
636 | } | |
637 | ||
7432ff81 KM |
638 | /* |
639 | * Determine the type of an inode | |
640 | */ | |
451eb9a1 | 641 | int |
7432ff81 KM |
642 | inodetype(ino) |
643 | ino_t ino; | |
644 | { | |
645 | struct inotab *itp; | |
646 | ||
647 | itp = inotablookup(ino); | |
648 | if (itp == NULL) | |
649 | return (LEAF); | |
650 | return (NODE); | |
651 | } | |
652 | ||
f743fc86 KM |
653 | /* |
654 | * Allocate and initialize a directory inode entry. | |
655 | * If requested, save its pertinent mode, owner, and time info. | |
656 | */ | |
451eb9a1 | 657 | static struct inotab * |
f743fc86 KM |
658 | allocinotab(ino, dip, seekpt) |
659 | ino_t ino; | |
660 | struct dinode *dip; | |
a1026118 | 661 | long seekpt; |
f743fc86 KM |
662 | { |
663 | register struct inotab *itp; | |
664 | struct modeinfo node; | |
f743fc86 | 665 | |
451eb9a1 KB |
666 | itp = calloc(1, sizeof(struct inotab)); |
667 | if (itp == NULL) | |
ad4fabdf | 668 | panic("no memory directory table\n"); |
f743fc86 KM |
669 | itp->t_next = inotab[INOHASH(ino)]; |
670 | inotab[INOHASH(ino)] = itp; | |
671 | itp->t_ino = ino; | |
672 | itp->t_seekpt = seekpt; | |
f743fc86 | 673 | if (mf == NULL) |
202d77b7 | 674 | return (itp); |
f743fc86 | 675 | node.ino = ino; |
31b1a5cf KM |
676 | node.timep[0].tv_sec = dip->di_atime.ts_sec; |
677 | node.timep[0].tv_usec = dip->di_atime.ts_nsec / 1000; | |
678 | node.timep[1].tv_sec = dip->di_mtime.ts_sec; | |
679 | node.timep[1].tv_usec = dip->di_mtime.ts_nsec / 1000; | |
f743fc86 KM |
680 | node.mode = dip->di_mode; |
681 | node.uid = dip->di_uid; | |
682 | node.gid = dip->di_gid; | |
82d46726 | 683 | (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf); |
202d77b7 | 684 | return (itp); |
f743fc86 KM |
685 | } |
686 | ||
687 | /* | |
688 | * Look up an inode in the table of directories | |
689 | */ | |
451eb9a1 | 690 | static struct inotab * |
f743fc86 KM |
691 | inotablookup(ino) |
692 | ino_t ino; | |
693 | { | |
694 | register struct inotab *itp; | |
695 | ||
696 | for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next) | |
697 | if (itp->t_ino == ino) | |
202d77b7 | 698 | return (itp); |
451eb9a1 | 699 | return (NULL); |
f743fc86 KM |
700 | } |
701 | ||
702 | /* | |
703 | * Clean up and exit | |
704 | */ | |
202d77b7 | 705 | __dead void |
f743fc86 KM |
706 | done(exitcode) |
707 | int exitcode; | |
708 | { | |
709 | ||
710 | closemt(); | |
7432ff81 KM |
711 | if (modefile[0] != '#') |
712 | (void) unlink(modefile); | |
713 | if (dirfile[0] != '#') | |
714 | (void) unlink(dirfile); | |
f743fc86 KM |
715 | exit(exitcode); |
716 | } |