File: | src/sbin/restore/dirs.c |
Warning: | line 545, column 26 The right operand of '-' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: dirs.c,v 1.42 2019/06/28 13:32:46 deraadt Exp $ */ | |||
2 | /* $NetBSD: dirs.c,v 1.26 1997/07/01 05:37:49 lukem Exp $ */ | |||
3 | ||||
4 | /* | |||
5 | * Copyright (c) 1983, 1993 | |||
6 | * The Regents of the University of California. All rights reserved. | |||
7 | * (c) UNIX System Laboratories, Inc. | |||
8 | * All or some portions of this file are derived from material licensed | |||
9 | * to the University of California by American Telephone and Telegraph | |||
10 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with | |||
11 | * the permission of UNIX System Laboratories, Inc. | |||
12 | * | |||
13 | * Redistribution and use in source and binary forms, with or without | |||
14 | * modification, are permitted provided that the following conditions | |||
15 | * are met: | |||
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. | |||
24 | * | |||
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 | |||
35 | * SUCH DAMAGE. | |||
36 | */ | |||
37 | ||||
38 | #include <sys/stat.h> | |||
39 | #include <sys/time.h> | |||
40 | ||||
41 | #include <ufs/ffs/fs.h> | |||
42 | #include <ufs/ufs/dinode.h> | |||
43 | #include <ufs/ufs/dir.h> | |||
44 | #include <protocols/dumprestore.h> | |||
45 | ||||
46 | #include <endian.h> | |||
47 | #include <err.h> | |||
48 | #include <errno(*__errno()).h> | |||
49 | #include <fcntl.h> | |||
50 | #include <paths.h> | |||
51 | #include <stdio.h> | |||
52 | #include <stdlib.h> | |||
53 | #include <string.h> | |||
54 | #include <unistd.h> | |||
55 | #include <limits.h> | |||
56 | ||||
57 | #include "restore.h" | |||
58 | #include "extern.h" | |||
59 | ||||
60 | /* | |||
61 | * Symbol table of directories read from tape. | |||
62 | */ | |||
63 | #define HASHSIZE1000 1000 | |||
64 | #define INOHASH(val)(val % 1000) (val % HASHSIZE1000) | |||
65 | struct inotab { | |||
66 | struct inotab *t_next; | |||
67 | ino_t t_ino; | |||
68 | int32_t t_seekpt; | |||
69 | int32_t t_size; | |||
70 | }; | |||
71 | static struct inotab *inotab[HASHSIZE1000]; | |||
72 | ||||
73 | /* | |||
74 | * Information retained about directories. | |||
75 | */ | |||
76 | struct modeinfo { | |||
77 | ino_t ino; | |||
78 | struct timespec ctimep[2]; | |||
79 | struct timespec mtimep[2]; | |||
80 | mode_t mode; | |||
81 | uid_t uid; | |||
82 | gid_t gid; | |||
83 | u_int flags; | |||
84 | }; | |||
85 | ||||
86 | /* | |||
87 | * Definitions for library routines operating on directories. | |||
88 | */ | |||
89 | #undef DIRBLKSIZ1024 | |||
90 | #define DIRBLKSIZ1024 1024 | |||
91 | struct rstdirdesc { | |||
92 | int dd_fd; | |||
93 | int32_t dd_loc; | |||
94 | int32_t dd_size; | |||
95 | char dd_buf[DIRBLKSIZ1024]; | |||
96 | }; | |||
97 | ||||
98 | /* | |||
99 | * Global variables for this file. | |||
100 | */ | |||
101 | static long seekpt; | |||
102 | static FILE *df, *mf; | |||
103 | static RST_DIR *dirp; | |||
104 | static char dirfile[PATH_MAX1024] = "#"; /* No file */ | |||
105 | static char modefile[PATH_MAX1024] = "#"; /* No file */ | |||
106 | static char dot[2] = "."; /* So it can be modified */ | |||
107 | ||||
108 | /* | |||
109 | * Format of old style directories. | |||
110 | */ | |||
111 | #define ODIRSIZ14 14 | |||
112 | struct odirect { | |||
113 | u_short d_ino; | |||
114 | char d_name[ODIRSIZ14]; | |||
115 | }; | |||
116 | ||||
117 | static struct inotab *allocinotab(FILE *, struct context *, long); | |||
118 | static void dcvt(struct odirect *, struct direct *); | |||
119 | static void flushent(void); | |||
120 | static struct inotab *inotablookup(ino_t); | |||
121 | static RST_DIR *opendirfile(const char *); | |||
122 | static void putdir(char *, size_t); | |||
123 | static void putent(struct direct *); | |||
124 | static void rst_seekdir(RST_DIR *, long, long); | |||
125 | static long rst_telldir(RST_DIR *); | |||
126 | static struct direct *searchdir(ino_t, char *); | |||
127 | ||||
128 | /* | |||
129 | * Extract directory contents, building up a directory structure | |||
130 | * on disk for extraction by name. | |||
131 | * If genmode is requested, save mode, owner, and times for all | |||
132 | * directories on the tape. | |||
133 | */ | |||
134 | void | |||
135 | extractdirs(int genmode) | |||
136 | { | |||
137 | int i; | |||
138 | struct inotab *itp; | |||
139 | struct direct nulldir; | |||
140 | int fd; | |||
141 | ||||
142 | Vprintfif (vflag) fprintf(stdout(&__sF[1]), "Extract directories from tape\n"); | |||
143 | (void)snprintf(dirfile, sizeof(dirfile), "%s/rstdir%lld", tmpdir, | |||
144 | (long long)dumpdate); | |||
145 | if (command != 'r' && command != 'R') { | |||
146 | strlcat(dirfile, "-XXXXXXXXXX", sizeof(dirfile)); | |||
147 | fd = mkstemp(dirfile); | |||
148 | } else | |||
149 | fd = open(dirfile, O_RDWR0x0002|O_CREAT0x0200|O_EXCL0x0800, 0666); | |||
150 | if (fd == -1 || (df = fdopen(fd, "w")) == NULL((void *)0)) { | |||
151 | int saved_errno = errno(*__errno()); | |||
152 | if (fd != -1) | |||
153 | close(fd); | |||
154 | errc(1, saved_errno, | |||
155 | "cannot create directory temporary %s", dirfile); | |||
156 | } | |||
157 | if (genmode != 0) { | |||
158 | (void)snprintf(modefile, sizeof(modefile), "%s/rstmode%lld", | |||
159 | tmpdir, (long long)dumpdate); | |||
160 | if (command != 'r' && command != 'R') { | |||
161 | strlcat(modefile, "-XXXXXXXXXX", sizeof(modefile)); | |||
162 | fd = mkstemp(modefile); | |||
163 | } else | |||
164 | fd = open(modefile, O_RDWR0x0002|O_CREAT0x0200|O_EXCL0x0800, 0666); | |||
165 | if (fd == -1 || (mf = fdopen(fd, "w")) == NULL((void *)0)) { | |||
166 | int saved_errno = errno(*__errno()); | |||
167 | if (fd != -1) | |||
168 | close(fd); | |||
169 | errc(1, saved_errno, | |||
170 | "cannot create modefile %s", modefile); | |||
171 | } | |||
172 | } | |||
173 | nulldir.d_ino = 0; | |||
174 | nulldir.d_type = DT_DIR4; | |||
175 | nulldir.d_namlen = 1; | |||
176 | nulldir.d_name[0] = '/'; | |||
177 | nulldir.d_name[1] = '\0'; | |||
178 | nulldir.d_reclen = DIRSIZ(0, &nulldir)((0) ? ((sizeof(struct direct) - (255 +1)) + (((&nulldir) ->d_type+1 + 3) &~ 3)) : ((sizeof(struct direct) - (255 +1)) + (((&nulldir)->d_namlen+1 + 3) &~ 3))); | |||
179 | for (;;) { | |||
180 | curfile.name = "<directory file - name unknown>"; | |||
181 | curfile.action = USING1; | |||
182 | if (curfile.mode == 0 || (curfile.mode & IFMT0170000) != IFDIR0040000) { | |||
183 | (void)fclose(df); | |||
184 | dirp = opendirfile(dirfile); | |||
185 | if (dirp == NULL((void *)0)) | |||
186 | warn("opendirfile"); | |||
187 | if (mf != NULL((void *)0)) | |||
188 | (void)fclose(mf); | |||
189 | i = dirlookup(dot); | |||
190 | if (i == 0) | |||
191 | panic("Root directory is not on tape\n"); | |||
192 | return; | |||
193 | } | |||
194 | itp = allocinotab(mf, &curfile, seekpt); | |||
195 | getfile(putdir, xtrnull); | |||
196 | putent(&nulldir); | |||
197 | flushent(); | |||
198 | itp->t_size = seekpt - itp->t_seekpt; | |||
199 | } | |||
200 | } | |||
201 | ||||
202 | /* | |||
203 | * skip over all the directories on the tape | |||
204 | */ | |||
205 | void | |||
206 | skipdirs(void) | |||
207 | { | |||
208 | ||||
209 | while (curfile.ino && (curfile.mode & IFMT0170000) == IFDIR0040000) { | |||
210 | skipfile(); | |||
211 | } | |||
212 | } | |||
213 | ||||
214 | /* | |||
215 | * Recursively find names and inumbers of all files in subtree | |||
216 | * pname and pass them off to be processed. | |||
217 | */ | |||
218 | void | |||
219 | treescan(char *pname, ino_t ino, long (*todo)(char *, ino_t, int)) | |||
220 | { | |||
221 | struct inotab *itp; | |||
222 | struct direct *dp; | |||
223 | size_t namelen; | |||
224 | long bpt; | |||
225 | char locname[PATH_MAX1024 + 1]; | |||
226 | ||||
227 | itp = inotablookup(ino); | |||
228 | if (itp == NULL((void *)0)) { | |||
229 | /* | |||
230 | * Pname is name of a simple file or an unchanged directory. | |||
231 | */ | |||
232 | (void)(*todo)(pname, ino, LEAF1); | |||
233 | return; | |||
234 | } | |||
235 | /* | |||
236 | * Pname is a dumped directory name. | |||
237 | */ | |||
238 | if ((*todo)(pname, ino, NODE2) == FAIL0) | |||
239 | return; | |||
240 | /* | |||
241 | * begin search through the directory | |||
242 | * skipping over "." and ".." | |||
243 | */ | |||
244 | namelen = strlcpy(locname, pname, sizeof(locname)); | |||
245 | if (namelen >= sizeof(locname) - 1) | |||
246 | namelen = sizeof(locname) - 2; | |||
247 | locname[namelen++] = '/'; | |||
248 | locname[namelen] = '\0'; | |||
249 | rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); | |||
250 | dp = rst_readdir(dirp); /* "." */ | |||
251 | if (dp != NULL((void *)0) && strcmp(dp->d_name, ".") == 0) | |||
252 | dp = rst_readdir(dirp); /* ".." */ | |||
253 | else | |||
254 | fprintf(stderr(&__sF[2]), "Warning: `.' missing from directory %s\n", | |||
255 | pname); | |||
256 | if (dp != NULL((void *)0) && strcmp(dp->d_name, "..") == 0) | |||
257 | dp = rst_readdir(dirp); /* first real entry */ | |||
258 | else | |||
259 | fprintf(stderr(&__sF[2]), "Warning: `..' missing from directory %s\n", | |||
260 | pname); | |||
261 | bpt = rst_telldir(dirp); | |||
262 | /* | |||
263 | * a zero inode signals end of directory | |||
264 | */ | |||
265 | while (dp != NULL((void *)0)) { | |||
266 | locname[namelen] = '\0'; | |||
267 | if (namelen + dp->d_namlen >= sizeof(locname)) { | |||
268 | fprintf(stderr(&__sF[2]), "%s%s: name exceeds %zd char\n", | |||
269 | locname, dp->d_name, sizeof(locname) - 1); | |||
270 | } else { | |||
271 | (void)strlcat(locname, dp->d_name, sizeof(locname)); | |||
272 | treescan(locname, dp->d_ino, todo); | |||
273 | rst_seekdir(dirp, bpt, itp->t_seekpt); | |||
274 | } | |||
275 | dp = rst_readdir(dirp); | |||
276 | bpt = rst_telldir(dirp); | |||
277 | } | |||
278 | } | |||
279 | ||||
280 | /* | |||
281 | * Lookup a pathname which is always assumed to start from the ROOTINO. | |||
282 | */ | |||
283 | struct direct * | |||
284 | pathsearch(const char *pathname) | |||
285 | { | |||
286 | ino_t ino; | |||
287 | struct direct *dp; | |||
288 | char *path, *name, buffer[PATH_MAX1024]; | |||
289 | ||||
290 | strlcpy(buffer, pathname, sizeof buffer); | |||
291 | path = buffer; | |||
292 | ino = ROOTINO((ufsino_t)2); | |||
293 | while (*path == '/') | |||
294 | path++; | |||
295 | dp = NULL((void *)0); | |||
296 | while ((name = strsep(&path, "/")) != NULL((void *)0) && *name != '\0') { | |||
297 | if ((dp = searchdir(ino, name)) == NULL((void *)0)) | |||
298 | return (NULL((void *)0)); | |||
299 | ino = dp->d_ino; | |||
300 | } | |||
301 | return (dp); | |||
302 | } | |||
303 | ||||
304 | /* | |||
305 | * Lookup the requested name in directory inum. | |||
306 | * Return its inode number if found, zero if it does not exist. | |||
307 | */ | |||
308 | static struct direct * | |||
309 | searchdir(ino_t inum, char *name) | |||
310 | { | |||
311 | struct direct *dp; | |||
312 | struct inotab *itp; | |||
313 | int len; | |||
314 | ||||
315 | itp = inotablookup(inum); | |||
316 | if (itp == NULL((void *)0)) | |||
317 | return (NULL((void *)0)); | |||
318 | rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); | |||
319 | len = strlen(name); | |||
320 | do { | |||
321 | dp = rst_readdir(dirp); | |||
322 | if (dp == NULL((void *)0)) | |||
323 | return (NULL((void *)0)); | |||
324 | } while (dp->d_namlen != len || strncmp(dp->d_name, name, len) != 0); | |||
325 | return (dp); | |||
326 | } | |||
327 | ||||
328 | /* | |||
329 | * Put the directory entries in the directory file | |||
330 | */ | |||
331 | static void | |||
332 | putdir(char *buf, size_t size) | |||
333 | { | |||
334 | struct direct cvtbuf; | |||
335 | struct odirect *odp; | |||
336 | struct odirect *eodp; | |||
337 | struct direct *dp; | |||
338 | size_t loc, i; | |||
339 | ||||
340 | if (cvtflag) { | |||
341 | eodp = (struct odirect *)&buf[size]; | |||
342 | for (odp = (struct odirect *)buf; odp < eodp; odp++) | |||
343 | if (odp->d_ino != 0) { | |||
344 | dcvt(odp, &cvtbuf); | |||
345 | putent(&cvtbuf); | |||
346 | } | |||
347 | } else { | |||
348 | for (loc = 0; loc < size; ) { | |||
349 | dp = (struct direct *)(buf + loc); | |||
350 | if (Bcvt) { | |||
351 | dp->d_ino = swap32(dp->d_ino)(__uint32_t)(__builtin_constant_p(dp->d_ino) ? (__uint32_t )(((__uint32_t)(dp->d_ino) & 0xff) << 24 | ((__uint32_t )(dp->d_ino) & 0xff00) << 8 | ((__uint32_t)(dp-> d_ino) & 0xff0000) >> 8 | ((__uint32_t)(dp->d_ino ) & 0xff000000) >> 24) : __swap32md(dp->d_ino)); | |||
352 | dp->d_reclen = swap16(dp->d_reclen)(__uint16_t)(__builtin_constant_p(dp->d_reclen) ? (__uint16_t )(((__uint16_t)(dp->d_reclen) & 0xffU) << 8 | (( __uint16_t)(dp->d_reclen) & 0xff00U) >> 8) : __swap16md (dp->d_reclen)); | |||
353 | } | |||
354 | if (oldinofmt && dp->d_ino != 0) { | |||
355 | # if BYTE_ORDER1234 == BIG_ENDIAN4321 | |||
356 | if (Bcvt) | |||
357 | dp->d_namlen = dp->d_type; | |||
358 | # else | |||
359 | if (!Bcvt) | |||
360 | dp->d_namlen = dp->d_type; | |||
361 | # endif | |||
362 | dp->d_type = DT_UNKNOWN0; | |||
363 | } | |||
364 | i = DIRBLKSIZ1024 - (loc & (DIRBLKSIZ1024 - 1)); | |||
365 | if ((dp->d_reclen & 0x3) != 0 || | |||
366 | dp->d_reclen > i || | |||
367 | dp->d_reclen < DIRSIZ(0, dp)((0) ? ((sizeof(struct direct) - (255 +1)) + (((dp)->d_type +1 + 3) &~ 3)) : ((sizeof(struct direct) - (255 +1)) + (( (dp)->d_namlen+1 + 3) &~ 3))) || | |||
368 | dp->d_namlen > NAME_MAX255) { | |||
369 | Vprintfif (vflag) fprintf(stdout(&__sF[1]), "Mangled directory: "); | |||
370 | if ((dp->d_reclen & 0x3) != 0) | |||
371 | Vprintfif (vflag) fprintf(stdout(&__sF[1]), | |||
372 | "reclen not multiple of 4 "); | |||
373 | if (dp->d_reclen < DIRSIZ(0, dp)((0) ? ((sizeof(struct direct) - (255 +1)) + (((dp)->d_type +1 + 3) &~ 3)) : ((sizeof(struct direct) - (255 +1)) + (( (dp)->d_namlen+1 + 3) &~ 3)))) | |||
374 | Vprintfif (vflag) fprintf(stdout(&__sF[1]), | |||
375 | "reclen less than DIRSIZ (%u < %u) ", | |||
376 | (unsigned)dp->d_reclen, | |||
377 | (unsigned)DIRSIZ(0, dp)((0) ? ((sizeof(struct direct) - (255 +1)) + (((dp)->d_type +1 + 3) &~ 3)) : ((sizeof(struct direct) - (255 +1)) + (( (dp)->d_namlen+1 + 3) &~ 3)))); | |||
378 | if (dp->d_namlen > NAME_MAX255) | |||
379 | Vprintfif (vflag) fprintf(stdout(&__sF[1]), | |||
380 | "reclen name too big (%u > %u) ", | |||
381 | (unsigned)dp->d_namlen, NAME_MAX255); | |||
382 | Vprintfif (vflag) fprintf(stdout(&__sF[1]), "\n"); | |||
383 | loc += i; | |||
384 | continue; | |||
385 | } | |||
386 | loc += dp->d_reclen; | |||
387 | if (dp->d_ino != 0) { | |||
388 | putent(dp); | |||
389 | } | |||
390 | } | |||
391 | } | |||
392 | } | |||
393 | ||||
394 | /* | |||
395 | * These variables are "local" to the following two functions. | |||
396 | */ | |||
397 | char dirbuf[DIRBLKSIZ1024]; | |||
398 | long dirloc = 0; | |||
399 | long prev = 0; | |||
400 | ||||
401 | /* | |||
402 | * add a new directory entry to a file. | |||
403 | */ | |||
404 | static void | |||
405 | putent(struct direct *dp) | |||
406 | { | |||
407 | dp->d_reclen = DIRSIZ(0, dp)((0) ? ((sizeof(struct direct) - (255 +1)) + (((dp)->d_type +1 + 3) &~ 3)) : ((sizeof(struct direct) - (255 +1)) + (( (dp)->d_namlen+1 + 3) &~ 3))); | |||
408 | if (dirloc + dp->d_reclen > DIRBLKSIZ1024) { | |||
409 | ((struct direct *)(dirbuf + prev))->d_reclen = | |||
410 | DIRBLKSIZ1024 - prev; | |||
411 | (void)fwrite(dirbuf, 1, DIRBLKSIZ1024, df); | |||
412 | dirloc = 0; | |||
413 | } | |||
414 | memcpy(dirbuf + dirloc, dp, dp->d_reclen); | |||
415 | prev = dirloc; | |||
416 | dirloc += dp->d_reclen; | |||
417 | } | |||
418 | ||||
419 | /* | |||
420 | * flush out a directory that is finished. | |||
421 | */ | |||
422 | static void | |||
423 | flushent(void) | |||
424 | { | |||
425 | ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ1024 - prev; | |||
426 | (void)fwrite(dirbuf, dirloc, 1, df); | |||
427 | seekpt = ftell(df); | |||
428 | dirloc = 0; | |||
429 | } | |||
430 | ||||
431 | static void | |||
432 | dcvt(struct odirect *odp, struct direct *ndp) | |||
433 | { | |||
434 | ||||
435 | memset(ndp, 0, sizeof *ndp); | |||
436 | if (Bcvt) | |||
437 | ndp->d_ino = swap16(odp->d_ino)(__uint16_t)(__builtin_constant_p(odp->d_ino) ? (__uint16_t )(((__uint16_t)(odp->d_ino) & 0xffU) << 8 | ((__uint16_t )(odp->d_ino) & 0xff00U) >> 8) : __swap16md(odp-> d_ino)); | |||
438 | else | |||
439 | ndp->d_ino = odp->d_ino; | |||
440 | ndp->d_type = DT_UNKNOWN0; | |||
441 | (void)strncpy(ndp->d_name, odp->d_name, ODIRSIZ14); | |||
442 | ndp->d_namlen = strlen(ndp->d_name); | |||
443 | ndp->d_reclen = DIRSIZ(0, ndp)((0) ? ((sizeof(struct direct) - (255 +1)) + (((ndp)->d_type +1 + 3) &~ 3)) : ((sizeof(struct direct) - (255 +1)) + (( (ndp)->d_namlen+1 + 3) &~ 3))); | |||
444 | } | |||
445 | ||||
446 | /* | |||
447 | * Seek to an entry in a directory. | |||
448 | * Only values returned by rst_telldir should be passed to rst_seekdir. | |||
449 | * This routine handles many directories in a single file. | |||
450 | * It takes the base of the directory in the file, plus | |||
451 | * the desired seek offset into it. | |||
452 | */ | |||
453 | static void | |||
454 | rst_seekdir(RST_DIR *dirp, long loc, long base) | |||
455 | { | |||
456 | ||||
457 | if (loc == rst_telldir(dirp)) | |||
458 | return; | |||
459 | loc -= base; | |||
460 | if (loc < 0) | |||
461 | fprintf(stderr(&__sF[2]), "bad seek pointer to rst_seekdir %ld\n", loc); | |||
462 | (void)lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ1024 - 1)), SEEK_SET0); | |||
463 | dirp->dd_loc = loc & (DIRBLKSIZ1024 - 1); | |||
464 | if (dirp->dd_loc != 0) | |||
465 | dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ1024); | |||
466 | } | |||
467 | ||||
468 | /* | |||
469 | * get next entry in a directory. | |||
470 | */ | |||
471 | struct direct * | |||
472 | rst_readdir(RST_DIR *dirp) | |||
473 | { | |||
474 | struct direct *dp; | |||
475 | ||||
476 | for (;;) { | |||
477 | if (dirp->dd_loc == 0) { | |||
478 | dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, | |||
479 | DIRBLKSIZ1024); | |||
480 | if (dirp->dd_size <= 0) { | |||
481 | Dprintfif (dflag) fprintf(stderr(&__sF[2]), "error reading directory\n"); | |||
482 | return (NULL((void *)0)); | |||
483 | } | |||
484 | } | |||
485 | if (dirp->dd_loc >= dirp->dd_size) { | |||
486 | dirp->dd_loc = 0; | |||
487 | continue; | |||
488 | } | |||
489 | dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc); | |||
490 | if (dp->d_reclen == 0 || | |||
491 | dp->d_reclen > DIRBLKSIZ1024 + 1 - dirp->dd_loc) { | |||
492 | Dprintfif (dflag) fprintf(stderr(&__sF[2]), "corrupted directory: bad reclen %d\n", | |||
493 | dp->d_reclen); | |||
494 | return (NULL((void *)0)); | |||
495 | } | |||
496 | dirp->dd_loc += dp->d_reclen; | |||
497 | if (dp->d_ino == 0 && strcmp(dp->d_name, "/") == 0) | |||
498 | return (NULL((void *)0)); | |||
499 | if (dp->d_ino >= maxino) { | |||
500 | Dprintfif (dflag) fprintf(stderr(&__sF[2]), "corrupted directory: bad inum %llu\n", | |||
501 | (unsigned long long)dp->d_ino); | |||
502 | continue; | |||
503 | } | |||
504 | return (dp); | |||
505 | } | |||
506 | } | |||
507 | ||||
508 | /* | |||
509 | * Simulate the opening of a directory | |||
510 | */ | |||
511 | RST_DIR * | |||
512 | rst_opendir(const char *name) | |||
513 | { | |||
514 | struct inotab *itp; | |||
515 | RST_DIR *dirp; | |||
516 | ino_t ino; | |||
517 | ||||
518 | if ((ino = dirlookup(name)) > 0 && | |||
| ||||
519 | (itp = inotablookup(ino)) != NULL((void *)0)) { | |||
520 | dirp = opendirfile(dirfile); | |||
521 | rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); | |||
522 | return (dirp); | |||
523 | } | |||
524 | return (NULL((void *)0)); | |||
525 | } | |||
526 | ||||
527 | /* | |||
528 | * In our case, there is nothing to do when closing a directory. | |||
529 | */ | |||
530 | void | |||
531 | rst_closedir(RST_DIR *dirp) | |||
532 | { | |||
533 | (void)close(dirp->dd_fd); | |||
534 | free(dirp); | |||
535 | return; | |||
536 | } | |||
537 | ||||
538 | /* | |||
539 | * Simulate finding the current offset in the directory. | |||
540 | */ | |||
541 | static long | |||
542 | rst_telldir(RST_DIR *dirp) | |||
543 | { | |||
544 | return ((long)lseek(dirp->dd_fd, | |||
545 | (off_t)0, SEEK_CUR1) - dirp->dd_size + dirp->dd_loc); | |||
| ||||
546 | } | |||
547 | ||||
548 | /* | |||
549 | * Open a directory file. | |||
550 | */ | |||
551 | static RST_DIR * | |||
552 | opendirfile(const char *name) | |||
553 | { | |||
554 | RST_DIR *dirp; | |||
555 | int fd; | |||
556 | ||||
557 | if ((fd = open(name, O_RDONLY0x0000)) == -1) | |||
558 | return (NULL((void *)0)); | |||
559 | if ((dirp = malloc(sizeof(RST_DIR))) == NULL((void *)0)) { | |||
560 | (void)close(fd); | |||
561 | return (NULL((void *)0)); | |||
562 | } | |||
563 | dirp->dd_fd = fd; | |||
564 | dirp->dd_loc = 0; | |||
565 | return (dirp); | |||
566 | } | |||
567 | ||||
568 | /* | |||
569 | * Set the mode, owner, and times for all new or changed directories | |||
570 | */ | |||
571 | void | |||
572 | setdirmodes(int flags) | |||
573 | { | |||
574 | FILE *mf; | |||
575 | struct modeinfo node; | |||
576 | struct entry *ep; | |||
577 | char *cp; | |||
578 | ||||
579 | Vprintfif (vflag) fprintf(stdout(&__sF[1]), "Set directory mode, owner, and times.\n"); | |||
580 | if (command == 'r' || command == 'R') | |||
581 | (void)snprintf(modefile, sizeof(modefile), "%s/rstmode%lld", | |||
582 | tmpdir, (long long)dumpdate); | |||
583 | if (modefile[0] == '#') { | |||
584 | panic("modefile not defined\n"); | |||
585 | fputs("directory mode, owner, and times not set\n", stderr(&__sF[2])); | |||
586 | return; | |||
587 | } | |||
588 | mf = fopen(modefile, "r"); | |||
589 | if (mf == NULL((void *)0)) { | |||
590 | warn("fopen"); | |||
591 | fprintf(stderr(&__sF[2]), "cannot open mode file %s\n", modefile); | |||
592 | fprintf(stderr(&__sF[2]), "directory mode, owner, and times not set\n"); | |||
593 | return; | |||
594 | } | |||
595 | clearerr(mf)(!__isthreaded ? ((void)((mf)->_flags &= ~(0x0040|0x0020 ))) : (clearerr)(mf)); | |||
596 | for (;;) { | |||
597 | (void)fread((char *)&node, 1, sizeof(struct modeinfo), mf); | |||
598 | if (feof(mf)(!__isthreaded ? (((mf)->_flags & 0x0020) != 0) : (feof )(mf))) | |||
599 | break; | |||
600 | ep = lookupino(node.ino); | |||
601 | if (command == 'i' || command == 'x') { | |||
602 | if (ep == NULL((void *)0)) | |||
603 | continue; | |||
604 | if ((flags & FORCE0x0001) == 0 && ep->e_flags & EXISTED0x0040) { | |||
605 | ep->e_flags &= ~NEW0x0002; | |||
606 | continue; | |||
607 | } | |||
608 | if (node.ino == ROOTINO((ufsino_t)2) && | |||
609 | reply("set owner/mode for '.'") == FAIL0) | |||
610 | continue; | |||
611 | } | |||
612 | if (ep == NULL((void *)0)) { | |||
613 | panic("cannot find directory inode %llu\n", | |||
614 | (unsigned long long)node.ino); | |||
615 | } else { | |||
616 | if (!Nflag) { | |||
617 | cp = myname(ep); | |||
618 | (void)chown(cp, node.uid, node.gid); | |||
619 | (void)chmod(cp, node.mode); | |||
620 | (void)chflags(cp, node.flags); | |||
621 | (void)utimensat(AT_FDCWD-100, cp, node.ctimep, 0); | |||
622 | (void)utimensat(AT_FDCWD-100, cp, node.mtimep, 0); | |||
623 | } | |||
624 | ep->e_flags &= ~NEW0x0002; | |||
625 | } | |||
626 | } | |||
627 | if (ferror(mf)(!__isthreaded ? (((mf)->_flags & 0x0040) != 0) : (ferror )(mf))) | |||
628 | panic("error setting directory modes\n"); | |||
629 | (void)fclose(mf); | |||
630 | } | |||
631 | ||||
632 | /* | |||
633 | * Generate a literal copy of a directory. | |||
634 | */ | |||
635 | int | |||
636 | genliteraldir(char *name, ino_t ino) | |||
637 | { | |||
638 | struct inotab *itp; | |||
639 | int ofile, dp, i, size; | |||
640 | char buf[BUFSIZ1024]; | |||
641 | ||||
642 | itp = inotablookup(ino); | |||
643 | if (itp == NULL((void *)0)) | |||
644 | panic("Cannot find directory inode %llu named %s\n", | |||
645 | (unsigned long long)ino, name); | |||
646 | if ((ofile = open(name, O_WRONLY0x0001 | O_CREAT0x0200 | O_TRUNC0x0400, 0666)) == -1) { | |||
647 | warn("%s: cannot create file", name); | |||
648 | return (FAIL0); | |||
649 | } | |||
650 | rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); | |||
651 | dp = dup(dirp->dd_fd); | |||
652 | for (i = itp->t_size; i > 0; i -= BUFSIZ1024) { | |||
653 | size = i < BUFSIZ1024 ? i : BUFSIZ1024; | |||
654 | if (read(dp, buf, size) == -1) | |||
655 | err(1, "read error extracting inode %llu, name %s", | |||
656 | (unsigned long long)curfile.ino, curfile.name); | |||
657 | xtrfile(buf, size); | |||
658 | } | |||
659 | (void)close(dp); | |||
660 | (void)close(ofile); | |||
661 | return (GOOD1); | |||
662 | } | |||
663 | ||||
664 | /* | |||
665 | * Determine the type of an inode | |||
666 | */ | |||
667 | int | |||
668 | inodetype(ino_t ino) | |||
669 | { | |||
670 | struct inotab *itp; | |||
671 | ||||
672 | itp = inotablookup(ino); | |||
673 | if (itp == NULL((void *)0)) | |||
674 | return (LEAF1); | |||
675 | return (NODE2); | |||
676 | } | |||
677 | ||||
678 | /* | |||
679 | * Allocate and initialize a directory inode entry. | |||
680 | * If requested, save its pertinent mode, owner, and time info. | |||
681 | */ | |||
682 | static struct inotab * | |||
683 | allocinotab(FILE *mf, struct context *ctxp, long seekpt) | |||
684 | { | |||
685 | struct inotab *itp; | |||
686 | struct modeinfo node; | |||
687 | ||||
688 | itp = calloc(1, sizeof(struct inotab)); | |||
689 | if (itp == NULL((void *)0)) | |||
690 | panic("no memory directory table\n"); | |||
691 | itp->t_next = inotab[INOHASH(ctxp->ino)(ctxp->ino % 1000)]; | |||
692 | inotab[INOHASH(ctxp->ino)(ctxp->ino % 1000)] = itp; | |||
693 | itp->t_ino = ctxp->ino; | |||
694 | itp->t_seekpt = seekpt; | |||
695 | if (mf == NULL((void *)0)) | |||
696 | return (itp); | |||
697 | node.ino = ctxp->ino; | |||
698 | node.mtimep[0].tv_sec = ctxp->atime_sec; | |||
699 | node.mtimep[0].tv_nsec = ctxp->atime_nsec; | |||
700 | node.mtimep[1].tv_sec = ctxp->mtime_sec; | |||
701 | node.mtimep[1].tv_nsec = ctxp->mtime_nsec; | |||
702 | node.ctimep[0].tv_sec = ctxp->atime_sec; | |||
703 | node.ctimep[0].tv_nsec = ctxp->atime_nsec; | |||
704 | node.ctimep[1].tv_sec = ctxp->birthtime_sec; | |||
705 | node.ctimep[1].tv_nsec = ctxp->birthtime_nsec; | |||
706 | node.mode = ctxp->mode; | |||
707 | node.flags = ctxp->file_flags; | |||
708 | node.uid = ctxp->uid; | |||
709 | node.gid = ctxp->gid; | |||
710 | (void)fwrite((char *)&node, 1, sizeof(struct modeinfo), mf); | |||
711 | return (itp); | |||
712 | } | |||
713 | ||||
714 | /* | |||
715 | * Look up an inode in the table of directories | |||
716 | */ | |||
717 | static struct inotab * | |||
718 | inotablookup(ino_t ino) | |||
719 | { | |||
720 | struct inotab *itp; | |||
721 | ||||
722 | for (itp = inotab[INOHASH(ino)(ino % 1000)]; itp != NULL((void *)0); itp = itp->t_next) | |||
723 | if (itp->t_ino == ino) | |||
724 | return (itp); | |||
725 | return (NULL((void *)0)); | |||
726 | } | |||
727 | ||||
728 | /* | |||
729 | * Clean up and exit | |||
730 | */ | |||
731 | void | |||
732 | cleanup(void) | |||
733 | { | |||
734 | ||||
735 | closemt(); | |||
736 | if (modefile[0] != '#') | |||
737 | (void)unlink(modefile); | |||
738 | if (dirfile[0] != '#') | |||
739 | (void)unlink(dirfile); | |||
740 | } |