1 |
|
|
/* $OpenBSD: dirs.c,v 1.41 2015/08/25 04:18:43 guenther 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.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 HASHSIZE 1000 |
64 |
|
|
#define INOHASH(val) (val % HASHSIZE) |
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[HASHSIZE]; |
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 DIRBLKSIZ |
90 |
|
|
#define DIRBLKSIZ 1024 |
91 |
|
|
struct rstdirdesc { |
92 |
|
|
int dd_fd; |
93 |
|
|
int32_t dd_loc; |
94 |
|
|
int32_t dd_size; |
95 |
|
|
char dd_buf[DIRBLKSIZ]; |
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_MAX] = "#"; /* No file */ |
105 |
|
|
static char modefile[PATH_MAX] = "#"; /* No file */ |
106 |
|
|
static char dot[2] = "."; /* So it can be modified */ |
107 |
|
|
|
108 |
|
|
/* |
109 |
|
|
* Format of old style directories. |
110 |
|
|
*/ |
111 |
|
|
#define ODIRSIZ 14 |
112 |
|
|
struct odirect { |
113 |
|
|
u_short d_ino; |
114 |
|
|
char d_name[ODIRSIZ]; |
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 |
|
|
Vprintf(stdout, "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_RDWR|O_CREAT|O_EXCL, 0666); |
150 |
|
|
if (fd == -1 || (df = fdopen(fd, "w")) == NULL) { |
151 |
|
|
int saved_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_RDWR|O_CREAT|O_EXCL, 0666); |
165 |
|
|
if (fd == -1 || (mf = fdopen(fd, "w")) == NULL) { |
166 |
|
|
int saved_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_DIR; |
175 |
|
|
nulldir.d_namlen = 1; |
176 |
|
|
nulldir.d_name[0] = '/'; |
177 |
|
|
nulldir.d_name[1] = '\0'; |
178 |
|
|
nulldir.d_reclen = DIRSIZ(0, &nulldir); |
179 |
|
|
for (;;) { |
180 |
|
|
curfile.name = "<directory file - name unknown>"; |
181 |
|
|
curfile.action = USING; |
182 |
|
|
if (curfile.mode == 0 || (curfile.mode & IFMT) != IFDIR) { |
183 |
|
|
(void)fclose(df); |
184 |
|
|
dirp = opendirfile(dirfile); |
185 |
|
|
if (dirp == NULL) |
186 |
|
|
warn("opendirfile"); |
187 |
|
|
if (mf != NULL) |
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 & IFMT) == IFDIR) { |
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_MAX + 1]; |
226 |
|
|
|
227 |
|
|
itp = inotablookup(ino); |
228 |
|
|
if (itp == NULL) { |
229 |
|
|
/* |
230 |
|
|
* Pname is name of a simple file or an unchanged directory. |
231 |
|
|
*/ |
232 |
|
|
(void)(*todo)(pname, ino, LEAF); |
233 |
|
|
return; |
234 |
|
|
} |
235 |
|
|
/* |
236 |
|
|
* Pname is a dumped directory name. |
237 |
|
|
*/ |
238 |
|
|
if ((*todo)(pname, ino, NODE) == FAIL) |
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 && strcmp(dp->d_name, ".") == 0) |
252 |
|
|
dp = rst_readdir(dirp); /* ".." */ |
253 |
|
|
else |
254 |
|
|
fprintf(stderr, "Warning: `.' missing from directory %s\n", |
255 |
|
|
pname); |
256 |
|
|
if (dp != NULL && strcmp(dp->d_name, "..") == 0) |
257 |
|
|
dp = rst_readdir(dirp); /* first real entry */ |
258 |
|
|
else |
259 |
|
|
fprintf(stderr, "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) { |
266 |
|
|
locname[namelen] = '\0'; |
267 |
|
|
if (namelen + dp->d_namlen >= sizeof(locname)) { |
268 |
|
|
fprintf(stderr, "%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_MAX]; |
289 |
|
|
|
290 |
|
|
strlcpy(buffer, pathname, sizeof buffer); |
291 |
|
|
path = buffer; |
292 |
|
|
ino = ROOTINO; |
293 |
|
|
while (*path == '/') |
294 |
|
|
path++; |
295 |
|
|
dp = NULL; |
296 |
|
|
while ((name = strsep(&path, "/")) != NULL && *name != '\0') { |
297 |
|
|
if ((dp = searchdir(ino, name)) == NULL) |
298 |
|
|
return (NULL); |
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) |
317 |
|
|
return (NULL); |
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) |
323 |
|
|
return (NULL); |
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); |
352 |
|
|
dp->d_reclen = swap16(dp->d_reclen); |
353 |
|
|
} |
354 |
|
|
if (oldinofmt && dp->d_ino != 0) { |
355 |
|
|
# if BYTE_ORDER == BIG_ENDIAN |
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_UNKNOWN; |
363 |
|
|
} |
364 |
|
|
i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); |
365 |
|
|
if ((dp->d_reclen & 0x3) != 0 || |
366 |
|
|
dp->d_reclen > i || |
367 |
|
|
dp->d_reclen < DIRSIZ(0, dp) || |
368 |
|
|
dp->d_namlen > NAME_MAX) { |
369 |
|
|
Vprintf(stdout, "Mangled directory: "); |
370 |
|
|
if ((dp->d_reclen & 0x3) != 0) |
371 |
|
|
Vprintf(stdout, |
372 |
|
|
"reclen not multiple of 4 "); |
373 |
|
|
if (dp->d_reclen < DIRSIZ(0, dp)) |
374 |
|
|
Vprintf(stdout, |
375 |
|
|
"reclen less than DIRSIZ (%u < %u) ", |
376 |
|
|
(unsigned)dp->d_reclen, |
377 |
|
|
(unsigned)DIRSIZ(0, dp)); |
378 |
|
|
if (dp->d_namlen > NAME_MAX) |
379 |
|
|
Vprintf(stdout, |
380 |
|
|
"reclen name too big (%u > %u) ", |
381 |
|
|
(unsigned)dp->d_namlen, NAME_MAX); |
382 |
|
|
Vprintf(stdout, "\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[DIRBLKSIZ]; |
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); |
408 |
|
|
if (dirloc + dp->d_reclen > DIRBLKSIZ) { |
409 |
|
|
((struct direct *)(dirbuf + prev))->d_reclen = |
410 |
|
|
DIRBLKSIZ - prev; |
411 |
|
|
(void)fwrite(dirbuf, 1, DIRBLKSIZ, 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 = DIRBLKSIZ - 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); |
438 |
|
|
else |
439 |
|
|
ndp->d_ino = odp->d_ino; |
440 |
|
|
ndp->d_type = DT_UNKNOWN; |
441 |
|
|
(void)strncpy(ndp->d_name, odp->d_name, ODIRSIZ); |
442 |
|
|
ndp->d_namlen = strlen(ndp->d_name); |
443 |
|
|
ndp->d_reclen = DIRSIZ(0, ndp); |
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, "bad seek pointer to rst_seekdir %ld\n", loc); |
462 |
|
|
(void)lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), SEEK_SET); |
463 |
|
|
dirp->dd_loc = loc & (DIRBLKSIZ - 1); |
464 |
|
|
if (dirp->dd_loc != 0) |
465 |
|
|
dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ); |
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 |
|
|
DIRBLKSIZ); |
480 |
|
|
if (dirp->dd_size <= 0) { |
481 |
|
|
Dprintf(stderr, "error reading directory\n"); |
482 |
|
|
return (NULL); |
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 > DIRBLKSIZ + 1 - dirp->dd_loc) { |
492 |
|
|
Dprintf(stderr, "corrupted directory: bad reclen %d\n", |
493 |
|
|
dp->d_reclen); |
494 |
|
|
return (NULL); |
495 |
|
|
} |
496 |
|
|
dirp->dd_loc += dp->d_reclen; |
497 |
|
|
if (dp->d_ino == 0 && strcmp(dp->d_name, "/") == 0) |
498 |
|
|
return (NULL); |
499 |
|
|
if (dp->d_ino >= maxino) { |
500 |
|
|
Dprintf(stderr, "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) { |
520 |
|
|
dirp = opendirfile(dirfile); |
521 |
|
|
rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); |
522 |
|
|
return (dirp); |
523 |
|
|
} |
524 |
|
|
return (NULL); |
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_CUR) - 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_RDONLY)) == -1) |
558 |
|
|
return (NULL); |
559 |
|
|
if ((dirp = malloc(sizeof(RST_DIR))) == NULL) { |
560 |
|
|
(void)close(fd); |
561 |
|
|
return (NULL); |
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 |
|
|
Vprintf(stdout, "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); |
586 |
|
|
return; |
587 |
|
|
} |
588 |
|
|
mf = fopen(modefile, "r"); |
589 |
|
|
if (mf == NULL) { |
590 |
|
|
warn("fopen"); |
591 |
|
|
fprintf(stderr, "cannot open mode file %s\n", modefile); |
592 |
|
|
fprintf(stderr, "directory mode, owner, and times not set\n"); |
593 |
|
|
return; |
594 |
|
|
} |
595 |
|
|
clearerr(mf); |
596 |
|
|
for (;;) { |
597 |
|
|
(void)fread((char *)&node, 1, sizeof(struct modeinfo), mf); |
598 |
|
|
if (feof(mf)) |
599 |
|
|
break; |
600 |
|
|
ep = lookupino(node.ino); |
601 |
|
|
if (command == 'i' || command == 'x') { |
602 |
|
|
if (ep == NULL) |
603 |
|
|
continue; |
604 |
|
|
if ((flags & FORCE) == 0 && ep->e_flags & EXISTED) { |
605 |
|
|
ep->e_flags &= ~NEW; |
606 |
|
|
continue; |
607 |
|
|
} |
608 |
|
|
if (node.ino == ROOTINO && |
609 |
|
|
reply("set owner/mode for '.'") == FAIL) |
610 |
|
|
continue; |
611 |
|
|
} |
612 |
|
|
if (ep == NULL) { |
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, cp, node.ctimep, 0); |
622 |
|
|
(void)utimensat(AT_FDCWD, cp, node.mtimep, 0); |
623 |
|
|
} |
624 |
|
|
ep->e_flags &= ~NEW; |
625 |
|
|
} |
626 |
|
|
} |
627 |
|
|
if (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[BUFSIZ]; |
641 |
|
|
|
642 |
|
|
itp = inotablookup(ino); |
643 |
|
|
if (itp == NULL) |
644 |
|
|
panic("Cannot find directory inode %llu named %s\n", |
645 |
|
|
(unsigned long long)ino, name); |
646 |
|
|
if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) { |
647 |
|
|
warn("%s: cannot create file", name); |
648 |
|
|
return (FAIL); |
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 -= BUFSIZ) { |
653 |
|
|
size = i < BUFSIZ ? i : BUFSIZ; |
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 (GOOD); |
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) |
674 |
|
|
return (LEAF); |
675 |
|
|
return (NODE); |
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) |
690 |
|
|
panic("no memory directory table\n"); |
691 |
|
|
itp->t_next = inotab[INOHASH(ctxp->ino)]; |
692 |
|
|
inotab[INOHASH(ctxp->ino)] = itp; |
693 |
|
|
itp->t_ino = ctxp->ino; |
694 |
|
|
itp->t_seekpt = seekpt; |
695 |
|
|
if (mf == NULL) |
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)]; itp != NULL; itp = itp->t_next) |
723 |
|
|
if (itp->t_ino == ino) |
724 |
|
|
return (itp); |
725 |
|
|
return (NULL); |
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 |
|
|
} |