Commit | Line | Data |
---|---|---|
461723e7 KM |
1 | /*- |
2 | * Copyright (c) 1980, 1988, 1991 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * %sccs.include.redist.c% | |
76797561 DF |
6 | */ |
7 | ||
8 | #ifndef lint | |
8ad91276 | 9 | static char sccsid[] = "@(#)traverse.c 5.25 (Berkeley) %G%"; |
6e6191dc | 10 | #endif /* not lint */ |
35fb2af5 | 11 | |
cdce5e6c | 12 | #include <sys/param.h> |
84c9527a KM |
13 | #include <sys/time.h> |
14 | #include <sys/stat.h> | |
15 | #ifdef sunos | |
16 | #include <sys/vnode.h> | |
17 | ||
3d66b39b | 18 | #include <ufs/fs.h> |
84c9527a KM |
19 | #include <ufs/fsdir.h> |
20 | #include <ufs/inode.h> | |
cdce5e6c | 21 | #else |
3d66b39b | 22 | #include <ufs/ffs/fs.h> |
49ecaf5f KM |
23 | #include <ufs/ufs/dir.h> |
24 | #include <ufs/ufs/dinode.h> | |
84c9527a KM |
25 | #endif |
26 | ||
13298603 | 27 | #include <protocols/dumprestore.h> |
84c9527a KM |
28 | |
29 | #include <ctype.h> | |
30 | #include <stdio.h> | |
13298603 | 31 | #ifdef __STDC__ |
13298603 | 32 | #include <string.h> |
84c9527a | 33 | #include <unistd.h> |
13298603 | 34 | #endif |
84c9527a | 35 | |
b6407c9d | 36 | #include "dump.h" |
35fb2af5 | 37 | |
7c643854 KM |
38 | #define HASDUMPEDFILE 0x1 |
39 | #define HASSUBDIRS 0x2 | |
6e6191dc | 40 | |
8ad91276 CT |
41 | #ifdef FS_44INODEFMT |
42 | typedef quad_t fsizeT; | |
43 | #else | |
44 | typedef long fsizeT; | |
45 | #endif | |
46 | ||
84c9527a | 47 | static int dirindir __P((ino_t ino, daddr_t blkno, int level, long *size)); |
8ad91276 | 48 | static void dmpindir __P((ino_t ino, daddr_t blk, int level, fsizeT *size)); |
84c9527a KM |
49 | static int searchdir __P((ino_t ino, daddr_t blkno, long size, long filesize)); |
50 | ||
6e6191dc CT |
51 | /* |
52 | * This is an estimation of the number of TP_BSIZE blocks in the file. | |
53 | * It estimates the number of blocks in files with holes by assuming | |
54 | * that all of the blocks accounted for by di_blocks are data blocks | |
55 | * (when some of the blocks are usually used for indirect pointers); | |
56 | * hence the estimate may be high. | |
57 | */ | |
7c643854 | 58 | long |
0a008f8c KM |
59 | blockest(dp) |
60 | register struct dinode *dp; | |
6e6191dc | 61 | { |
7c643854 | 62 | long blkest, sizeest; |
6e6191dc CT |
63 | |
64 | /* | |
0a008f8c KM |
65 | * dp->di_size is the size of the file in bytes. |
66 | * dp->di_blocks stores the number of sectors actually in the file. | |
6e6191dc CT |
67 | * If there are more sectors than the size would indicate, this just |
68 | * means that there are indirect blocks in the file or unused | |
69 | * sectors in the last file block; we can safely ignore these | |
7c643854 | 70 | * (blkest = sizeest below). |
6e6191dc CT |
71 | * If the file is bigger than the number of sectors would indicate, |
72 | * then the file has holes in it. In this case we must use the | |
73 | * block count to estimate the number of data blocks used, but | |
74 | * we use the actual size for estimating the number of indirect | |
7c643854 KM |
75 | * dump blocks (sizeest vs. blkest in the indirect block |
76 | * calculation). | |
6e6191dc | 77 | */ |
0a008f8c KM |
78 | blkest = howmany(dbtob(dp->di_blocks), TP_BSIZE); |
79 | sizeest = howmany(dp->di_size, TP_BSIZE); | |
7c643854 KM |
80 | if (blkest > sizeest) |
81 | blkest = sizeest; | |
0a008f8c | 82 | if (dp->di_size > sblock->fs_bsize * NDADDR) { |
6e6191dc | 83 | /* calculate the number of indirect blocks on the dump tape */ |
7c643854 KM |
84 | blkest += |
85 | howmany(sizeest - NDADDR * sblock->fs_bsize / TP_BSIZE, | |
6e6191dc CT |
86 | TP_NINDIR); |
87 | } | |
7c643854 | 88 | return (blkest + 1); |
6e6191dc CT |
89 | } |
90 | ||
8ad91276 CT |
91 | /* Auxiliary macro to pick up files changed since previous dump. */ |
92 | #ifdef FS_44INODEFMT | |
93 | #define CHANGEDSINCE(dp, t) \ | |
94 | ((dp)->di_mtime.ts_sec >= (t) || (dp)->di_ctime.ts_sec >= (t)) | |
95 | #else | |
96 | #define CHANGEDSINCE(dp, t) \ | |
97 | ((dp)->di_mtime >= (t) || (dp)->di_ctime >= (t)) | |
98 | #endif | |
99 | ||
100 | /* The WANTTODUMP macro decides whether a file should be dumped. */ | |
101 | #ifdef UF_NODUMP | |
102 | #define WANTTODUMP(dp) \ | |
103 | (CHANGEDSINCE(dp, spcl.c_ddate) && \ | |
104 | (nonodump || ((dp)->di_flags & UF_NODUMP) != UF_NODUMP)) | |
105 | #else | |
106 | #define WANTTODUMP(dp) CHANGEDSINCE(dp, spcl.c_ddate) | |
107 | #endif | |
108 | ||
7c643854 KM |
109 | /* |
110 | * Dump pass 1. | |
111 | * | |
112 | * Walk the inode list for a filesystem to find all allocated inodes | |
113 | * that have been modified since the previous dump time. Also, find all | |
114 | * the directories in the filesystem. | |
115 | */ | |
84c9527a | 116 | int |
7c643854 KM |
117 | mapfiles(maxino, tapesize) |
118 | ino_t maxino; | |
119 | long *tapesize; | |
6e6191dc | 120 | { |
7c643854 KM |
121 | register int mode; |
122 | register ino_t ino; | |
123 | register struct dinode *dp; | |
124 | int anydirskipped = 0; | |
125 | ||
8ad91276 | 126 | for (ino = ROOTINO; ino < maxino; ino++) { |
7c643854 KM |
127 | dp = getino(ino); |
128 | if ((mode = (dp->di_mode & IFMT)) == 0) | |
129 | continue; | |
130 | SETINO(ino, usedinomap); | |
131 | if (mode == IFDIR) | |
132 | SETINO(ino, dumpdirmap); | |
8ad91276 | 133 | if (WANTTODUMP(dp)) { |
7c643854 | 134 | SETINO(ino, dumpinomap); |
8ad91276 | 135 | if (mode != IFREG && mode != IFDIR && mode != IFLNK) |
7c643854 | 136 | *tapesize += 1; |
8ad91276 CT |
137 | else |
138 | *tapesize += blockest(dp); | |
7c643854 KM |
139 | continue; |
140 | } | |
141 | if (mode == IFDIR) | |
142 | anydirskipped = 1; | |
143 | } | |
144 | /* | |
145 | * Restore gets very upset if the root is not dumped, | |
146 | * so ensure that it always is dumped. | |
147 | */ | |
cf1d6835 | 148 | SETINO(ROOTINO, dumpinomap); |
7c643854 | 149 | return (anydirskipped); |
6e6191dc CT |
150 | } |
151 | ||
7c643854 KM |
152 | /* |
153 | * Dump pass 2. | |
154 | * | |
155 | * Scan each directory on the filesystem to see if it has any modified | |
156 | * files in it. If it does, and has not already been added to the dump | |
157 | * list (because it was itself modified), then add it. If a directory | |
158 | * has not been modified itself, contains no modified files and has no | |
159 | * subdirectories, then it can be deleted from the dump list and from | |
160 | * the list of directories. By deleting it from the list of directories, | |
161 | * its parent may now qualify for the same treatment on this or a later | |
162 | * pass using this algorithm. | |
163 | */ | |
84c9527a | 164 | int |
7c643854 | 165 | mapdirs(maxino, tapesize) |
003a2a9e | 166 | ino_t maxino; |
7c643854 KM |
167 | long *tapesize; |
168 | { | |
169 | register struct dinode *dp; | |
1f3bdc79 | 170 | register int i, isdir; |
7c643854 KM |
171 | register char *map; |
172 | register ino_t ino; | |
49ecaf5f | 173 | long filesize; |
7c643854 | 174 | int ret, change = 0; |
35fb2af5 | 175 | |
8ad91276 CT |
176 | isdir = 0; /* XXX just to get gcc to shut up */ |
177 | for (map = dumpdirmap, ino = 1; ino < maxino; ino++) { | |
178 | if (((ino - 1) % NBBY) == 0) /* map is offset by 1 */ | |
1f3bdc79 | 179 | isdir = *map++; |
7c643854 | 180 | else |
1f3bdc79 | 181 | isdir >>= 1; |
1f3bdc79 | 182 | if ((isdir & 1) == 0 || TSTINO(ino, dumpinomap)) |
7c643854 KM |
183 | continue; |
184 | dp = getino(ino); | |
185 | filesize = dp->di_size; | |
186 | for (ret = 0, i = 0; filesize > 0 && i < NDADDR; i++) { | |
187 | if (dp->di_db[i] != 0) | |
188 | ret |= searchdir(ino, dp->di_db[i], | |
1f3bdc79 KM |
189 | (long)dblksize(sblock, dp, i), |
190 | filesize); | |
7c643854 KM |
191 | if (ret & HASDUMPEDFILE) |
192 | filesize = 0; | |
193 | else | |
194 | filesize -= sblock->fs_bsize; | |
35fb2af5 | 195 | } |
7c643854 KM |
196 | for (i = 0; filesize > 0 && i < NIADDR; i++) { |
197 | if (dp->di_ib[i] == 0) | |
198 | continue; | |
199 | ret |= dirindir(ino, dp->di_ib[i], i, &filesize); | |
200 | } | |
201 | if (ret & HASDUMPEDFILE) { | |
1f3bdc79 KM |
202 | SETINO(ino, dumpinomap); |
203 | *tapesize += blockest(dp); | |
7c643854 KM |
204 | change = 1; |
205 | continue; | |
206 | } | |
207 | if ((ret & HASSUBDIRS) == 0) { | |
208 | if (!TSTINO(ino, dumpinomap)) { | |
209 | CLRINO(ino, dumpdirmap); | |
210 | change = 1; | |
211 | } | |
212 | } | |
213 | } | |
214 | return (change); | |
35fb2af5 BJ |
215 | } |
216 | ||
7c643854 KM |
217 | /* |
218 | * Read indirect blocks, and pass the data blocks to be searched | |
219 | * as directories. Quit as soon as any entry is found that will | |
220 | * require the directory to be dumped. | |
221 | */ | |
84c9527a | 222 | static int |
49ecaf5f | 223 | dirindir(ino, blkno, ind_level, filesize) |
7c643854 KM |
224 | ino_t ino; |
225 | daddr_t blkno; | |
49ecaf5f KM |
226 | int ind_level; |
227 | long *filesize; | |
35fb2af5 | 228 | { |
7c643854 | 229 | int ret = 0; |
b6407c9d | 230 | register int i; |
7c643854 | 231 | daddr_t idblk[MAXNINDIR]; |
35fb2af5 | 232 | |
49ecaf5f KM |
233 | bread(fsbtodb(sblock, blkno), (char *)idblk, (int)sblock->fs_bsize); |
234 | if (ind_level <= 0) { | |
7c643854 KM |
235 | for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) { |
236 | blkno = idblk[i]; | |
237 | if (blkno != 0) | |
1ac8af66 | 238 | ret |= searchdir(ino, blkno, sblock->fs_bsize, |
49ecaf5f | 239 | *filesize); |
7c643854 KM |
240 | if (ret & HASDUMPEDFILE) |
241 | *filesize = 0; | |
242 | else | |
243 | *filesize -= sblock->fs_bsize; | |
b6407c9d | 244 | } |
7c643854 | 245 | return (ret); |
35fb2af5 | 246 | } |
49ecaf5f | 247 | ind_level--; |
7c643854 KM |
248 | for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) { |
249 | blkno = idblk[i]; | |
250 | if (blkno != 0) | |
49ecaf5f | 251 | ret |= dirindir(ino, blkno, ind_level, filesize); |
7c643854 KM |
252 | } |
253 | return (ret); | |
35fb2af5 BJ |
254 | } |
255 | ||
7c643854 KM |
256 | /* |
257 | * Scan a disk block containing directory information looking to see if | |
258 | * any of the entries are on the dump list and to see if the directory | |
259 | * contains any subdirectories. | |
260 | */ | |
84c9527a | 261 | static int |
1ac8af66 | 262 | searchdir(ino, blkno, size, filesize) |
7c643854 KM |
263 | ino_t ino; |
264 | daddr_t blkno; | |
49ecaf5f KM |
265 | register long size; |
266 | long filesize; | |
b6407c9d | 267 | { |
7c643854 | 268 | register struct direct *dp; |
1f3bdc79 | 269 | register long loc, ret = 0; |
7c643854 | 270 | char dblk[MAXBSIZE]; |
b6407c9d | 271 | |
49ecaf5f | 272 | bread(fsbtodb(sblock, blkno), dblk, (int)size); |
1ac8af66 KM |
273 | if (filesize < size) |
274 | size = filesize; | |
7c643854 KM |
275 | for (loc = 0; loc < size; ) { |
276 | dp = (struct direct *)(dblk + loc); | |
277 | if (dp->d_reclen == 0) { | |
278 | msg("corrupted directory, inumber %d\n", ino); | |
279 | break; | |
b6407c9d | 280 | } |
7c643854 KM |
281 | loc += dp->d_reclen; |
282 | if (dp->d_ino == 0) | |
283 | continue; | |
284 | if (dp->d_name[0] == '.') { | |
285 | if (dp->d_name[1] == '\0') | |
286 | continue; | |
287 | if (dp->d_name[1] == '.' && dp->d_name[2] == '\0') | |
288 | continue; | |
b6407c9d | 289 | } |
1f3bdc79 KM |
290 | if (TSTINO(dp->d_ino, dumpinomap)) { |
291 | ret |= HASDUMPEDFILE; | |
292 | if (ret & HASSUBDIRS) | |
293 | break; | |
294 | } | |
295 | if (TSTINO(dp->d_ino, dumpdirmap)) { | |
296 | ret |= HASSUBDIRS; | |
297 | if (ret & HASDUMPEDFILE) | |
298 | break; | |
299 | } | |
b6407c9d | 300 | } |
1f3bdc79 | 301 | return (ret); |
b6407c9d KM |
302 | } |
303 | ||
7c643854 KM |
304 | /* |
305 | * Dump passes 3 and 4. | |
306 | * | |
307 | * Dump the contents of an inode to tape. | |
308 | */ | |
6e6191dc | 309 | void |
0a008f8c KM |
310 | dumpino(dp, ino) |
311 | register struct dinode *dp; | |
7c643854 | 312 | ino_t ino; |
35fb2af5 | 313 | { |
60c18125 | 314 | int ind_level, cnt; |
8ad91276 | 315 | fsizeT size; |
60c18125 | 316 | char buf[TP_BSIZE]; |
35fb2af5 | 317 | |
7c643854 | 318 | if (newtape) { |
35fb2af5 | 319 | newtape = 0; |
7c643854 | 320 | dumpmap(dumpinomap, TS_BITS, ino); |
35fb2af5 | 321 | } |
7c643854 | 322 | CLRINO(ino, dumpinomap); |
0a008f8c | 323 | spcl.c_dinode = *dp; |
35fb2af5 BJ |
324 | spcl.c_type = TS_INODE; |
325 | spcl.c_count = 0; | |
84c9527a | 326 | switch (dp->di_mode & S_IFMT) { |
60c18125 | 327 | |
84c9527a | 328 | case 0: |
60c18125 KM |
329 | /* |
330 | * Freed inode. | |
331 | */ | |
7b0c1d85 | 332 | return; |
60c18125 | 333 | |
84c9527a | 334 | case S_IFLNK: |
60c18125 KM |
335 | /* |
336 | * Check for short symbolic link. | |
337 | */ | |
84c9527a | 338 | #ifdef FS_44INODEFMT |
60c18125 KM |
339 | if (dp->di_size > 0 && |
340 | dp->di_size < sblock->fs_maxsymlinklen) { | |
341 | spcl.c_addr[0] = 1; | |
342 | spcl.c_count = 1; | |
343 | writeheader(ino); | |
344 | bcopy((caddr_t)dp->di_shortlink, buf, | |
345 | (u_long)dp->di_size); | |
346 | buf[dp->di_size] = '\0'; | |
347 | writerec(buf, 0); | |
348 | return; | |
349 | } | |
84c9527a | 350 | #endif |
60c18125 KM |
351 | /* fall through */ |
352 | ||
84c9527a KM |
353 | case S_IFDIR: |
354 | case S_IFREG: | |
60c18125 KM |
355 | if (dp->di_size > 0) |
356 | break; | |
357 | /* fall through */ | |
358 | ||
84c9527a KM |
359 | case S_IFIFO: |
360 | case S_IFSOCK: | |
361 | case S_IFCHR: | |
362 | case S_IFBLK: | |
7c643854 | 363 | writeheader(ino); |
35fb2af5 | 364 | return; |
60c18125 KM |
365 | |
366 | default: | |
367 | msg("Warning: undefined file type 0%o\n", dp->di_mode & IFMT); | |
368 | return; | |
35fb2af5 | 369 | } |
0a008f8c | 370 | if (dp->di_size > NDADDR * sblock->fs_bsize) |
7c643854 | 371 | cnt = NDADDR * sblock->fs_frag; |
1a350083 | 372 | else |
0a008f8c KM |
373 | cnt = howmany(dp->di_size, sblock->fs_fsize); |
374 | blksout(&dp->di_db[0], cnt, ino); | |
375 | if ((size = dp->di_size - NDADDR * sblock->fs_bsize) <= 0) | |
1a350083 | 376 | return; |
49ecaf5f KM |
377 | for (ind_level = 0; ind_level < NIADDR; ind_level++) { |
378 | dmpindir(ino, dp->di_ib[ind_level], ind_level, &size); | |
1a350083 KM |
379 | if (size <= 0) |
380 | return; | |
381 | } | |
35fb2af5 BJ |
382 | } |
383 | ||
7c643854 KM |
384 | /* |
385 | * Read indirect blocks, and pass the data blocks to be dumped. | |
386 | */ | |
84c9527a | 387 | static void |
49ecaf5f | 388 | dmpindir(ino, blk, ind_level, size) |
7c643854 | 389 | ino_t ino; |
1a350083 | 390 | daddr_t blk; |
49ecaf5f | 391 | int ind_level; |
8ad91276 | 392 | fsizeT *size; |
35fb2af5 | 393 | { |
1a350083 | 394 | int i, cnt; |
b6407c9d | 395 | daddr_t idblk[MAXNINDIR]; |
35fb2af5 | 396 | |
1a350083 | 397 | if (blk != 0) |
49ecaf5f | 398 | bread(fsbtodb(sblock, blk), (char *)idblk, (int) sblock->fs_bsize); |
1a350083 | 399 | else |
49ecaf5f KM |
400 | bzero((char *)idblk, (int)sblock->fs_bsize); |
401 | if (ind_level <= 0) { | |
b6407c9d KM |
402 | if (*size < NINDIR(sblock) * sblock->fs_bsize) |
403 | cnt = howmany(*size, sblock->fs_fsize); | |
1a350083 | 404 | else |
b6407c9d KM |
405 | cnt = NINDIR(sblock) * sblock->fs_frag; |
406 | *size -= NINDIR(sblock) * sblock->fs_bsize; | |
7c643854 | 407 | blksout(&idblk[0], cnt, ino); |
1a350083 KM |
408 | return; |
409 | } | |
49ecaf5f | 410 | ind_level--; |
b6407c9d | 411 | for (i = 0; i < NINDIR(sblock); i++) { |
49ecaf5f | 412 | dmpindir(ino, idblk[i], ind_level, size); |
1a350083 KM |
413 | if (*size <= 0) |
414 | return; | |
415 | } | |
416 | } | |
417 | ||
7c643854 KM |
418 | /* |
419 | * Collect up the data into tape record sized buffers and output them. | |
420 | */ | |
6e6191dc | 421 | void |
7c643854 | 422 | blksout(blkp, frags, ino) |
1a350083 KM |
423 | daddr_t *blkp; |
424 | int frags; | |
7c643854 | 425 | ino_t ino; |
1a350083 | 426 | { |
6e6191dc | 427 | register daddr_t *bp; |
b6407c9d | 428 | int i, j, count, blks, tbperdb; |
1a350083 | 429 | |
184c56be | 430 | blks = howmany(frags * sblock->fs_fsize, TP_BSIZE); |
6e6191dc | 431 | tbperdb = sblock->fs_bsize >> tp_bshift; |
1a350083 KM |
432 | for (i = 0; i < blks; i += TP_NINDIR) { |
433 | if (i + TP_NINDIR > blks) | |
434 | count = blks; | |
435 | else | |
436 | count = i + TP_NINDIR; | |
437 | for (j = i; j < count; j++) | |
b6407c9d | 438 | if (blkp[j / tbperdb] != 0) |
1a350083 KM |
439 | spcl.c_addr[j - i] = 1; |
440 | else | |
441 | spcl.c_addr[j - i] = 0; | |
442 | spcl.c_count = count - i; | |
7c643854 | 443 | writeheader(ino); |
6e6191dc CT |
444 | bp = &blkp[i / tbperdb]; |
445 | for (j = i; j < count; j += tbperdb, bp++) | |
446 | if (*bp != 0) | |
b6407c9d | 447 | if (j + tbperdb <= count) |
49ecaf5f | 448 | dumpblock(*bp, (int)sblock->fs_bsize); |
1a350083 | 449 | else |
7c643854 | 450 | dumpblock(*bp, (count - j) * TP_BSIZE); |
1a350083 | 451 | spcl.c_type = TS_ADDR; |
35fb2af5 | 452 | } |
35fb2af5 BJ |
453 | } |
454 | ||
7c643854 KM |
455 | /* |
456 | * Dump a map to the tape. | |
457 | */ | |
6e6191dc | 458 | void |
7c643854 | 459 | dumpmap(map, type, ino) |
b6407c9d | 460 | char *map; |
7c643854 KM |
461 | int type; |
462 | ino_t ino; | |
35fb2af5 | 463 | { |
7c643854 | 464 | register int i; |
35fb2af5 BJ |
465 | char *cp; |
466 | ||
7c643854 KM |
467 | spcl.c_type = type; |
468 | spcl.c_count = howmany(mapsize * sizeof(char), TP_BSIZE); | |
469 | writeheader(ino); | |
b6407c9d | 470 | for (i = 0, cp = map; i < spcl.c_count; i++, cp += TP_BSIZE) |
60c18125 | 471 | writerec(cp, 0); |
35fb2af5 BJ |
472 | } |
473 | ||
7c643854 KM |
474 | /* |
475 | * Write a header record to the dump tape. | |
476 | */ | |
6e6191dc | 477 | void |
7c643854 KM |
478 | writeheader(ino) |
479 | ino_t ino; | |
35fb2af5 | 480 | { |
7c643854 | 481 | register long sum, cnt, *lp; |
35fb2af5 BJ |
482 | |
483 | spcl.c_inumber = ino; | |
75c26040 | 484 | spcl.c_magic = NFS_MAGIC; |
35fb2af5 | 485 | spcl.c_checksum = 0; |
7c643854 KM |
486 | lp = (long *)&spcl; |
487 | sum = 0; | |
488 | cnt = sizeof(union u_spcl) / (4 * sizeof(long)); | |
489 | while (--cnt >= 0) { | |
490 | sum += *lp++; | |
491 | sum += *lp++; | |
492 | sum += *lp++; | |
493 | sum += *lp++; | |
35fb2af5 | 494 | } |
7c643854 | 495 | spcl.c_checksum = CHECKSUM - sum; |
60c18125 | 496 | writerec((char *)&spcl, 1); |
35fb2af5 BJ |
497 | } |
498 | ||
003a2a9e | 499 | struct dinode * |
7c643854 KM |
500 | getino(inum) |
501 | ino_t inum; | |
003a2a9e KM |
502 | { |
503 | static daddr_t minino, maxino; | |
7c643854 | 504 | static struct dinode inoblock[MAXINOPB]; |
003a2a9e | 505 | |
7c643854 KM |
506 | curino = inum; |
507 | if (inum >= minino && inum < maxino) | |
508 | return (&inoblock[inum - minino]); | |
49ecaf5f KM |
509 | bread(fsbtodb(sblock, itod(sblock, inum)), (char *)inoblock, |
510 | (int)sblock->fs_bsize); | |
7c643854 | 511 | minino = inum - (inum % INOPB(sblock)); |
b6407c9d | 512 | maxino = minino + INOPB(sblock); |
7c643854 | 513 | return (&inoblock[inum - minino]); |
003a2a9e KM |
514 | } |
515 | ||
7c643854 KM |
516 | /* |
517 | * Read a chunk of data from the disk. | |
518 | * Try to recover from hard errors by reading in sector sized pieces. | |
519 | * Error recovery is attempted at most BREADEMAX times before seeking | |
520 | * consent from the operator to continue. | |
521 | */ | |
35fb2af5 BJ |
522 | int breaderrors = 0; |
523 | #define BREADEMAX 32 | |
524 | ||
6e6191dc | 525 | void |
7c643854 KM |
526 | bread(blkno, buf, size) |
527 | daddr_t blkno; | |
528 | char *buf; | |
529 | int size; | |
35fb2af5 | 530 | { |
7c643854 | 531 | int cnt, i; |
396a5549 | 532 | extern int errno; |
35fb2af5 | 533 | |
d4c718f6 | 534 | loop: |
49ecaf5f | 535 | if ((int)lseek(diskfd, ((off_t)blkno << dev_bshift), 0) < 0) |
35fb2af5 | 536 | msg("bread: lseek fails\n"); |
7c643854 | 537 | if ((cnt = read(diskfd, buf, size)) == size) |
d4c718f6 | 538 | return; |
7c643854 | 539 | if (blkno + (size / dev_bsize) > fsbtodb(sblock, sblock->fs_size)) { |
d4c718f6 KM |
540 | /* |
541 | * Trying to read the final fragment. | |
542 | * | |
543 | * NB - dump only works in TP_BSIZE blocks, hence | |
ff96014a | 544 | * rounds `dev_bsize' fragments up to TP_BSIZE pieces. |
d4c718f6 KM |
545 | * It should be smarter about not actually trying to |
546 | * read more than it can get, but for the time being | |
547 | * we punt and scale back the read only when it gets | |
548 | * us into trouble. (mkm 9/25/83) | |
549 | */ | |
7c643854 | 550 | size -= dev_bsize; |
d4c718f6 KM |
551 | goto loop; |
552 | } | |
1e7fac77 KM |
553 | if (cnt == -1) |
554 | msg("read error from %s: %s: [block %d]: count=%d\n", | |
555 | disk, strerror(errno), blkno, size); | |
556 | else | |
557 | msg("short read error from %s: [block %d]: count=%d, got=%d\n", | |
558 | disk, blkno, size, cnt); | |
6e6191dc | 559 | if (++breaderrors > BREADEMAX) { |
d4c718f6 KM |
560 | msg("More than %d block read errors from %d\n", |
561 | BREADEMAX, disk); | |
562 | broadcast("DUMP IS AILING!\n"); | |
563 | msg("This is an unrecoverable error.\n"); | |
564 | if (!query("Do you want to attempt to continue?")){ | |
71b2d5ef | 565 | dumpabort(0); |
d4c718f6 KM |
566 | /*NOTREACHED*/ |
567 | } else | |
568 | breaderrors = 0; | |
35fb2af5 | 569 | } |
396a5549 MK |
570 | /* |
571 | * Zero buffer, then try to read each sector of buffer separately. | |
572 | */ | |
7c643854 KM |
573 | bzero(buf, size); |
574 | for (i = 0; i < size; i += dev_bsize, buf += dev_bsize, blkno++) { | |
49ecaf5f | 575 | if ((int)lseek(diskfd, ((off_t)blkno << dev_bshift), 0) < 0) |
396a5549 | 576 | msg("bread: lseek2 fails!\n"); |
49ecaf5f | 577 | if ((cnt = read(diskfd, buf, (int)dev_bsize)) == dev_bsize) |
1e7fac77 KM |
578 | continue; |
579 | if (cnt == -1) { | |
580 | msg("read error from %s: %s: [sector %d]: count=%d\n", | |
581 | disk, strerror(errno), blkno, dev_bsize); | |
582 | continue; | |
583 | } | |
584 | msg("short read error from %s: [sector %d]: count=%d, got=%d\n", | |
585 | disk, blkno, dev_bsize, cnt); | |
396a5549 | 586 | } |
35fb2af5 | 587 | } |