File: | src/sbin/dump/traverse.c |
Warning: | line 898, column 3 Null pointer passed as 2nd argument to memory copy function |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: traverse.c,v 1.41 2024/01/09 03:16:00 guenther Exp $ */ | |||
2 | /* $NetBSD: traverse.c,v 1.17 1997/06/05 11:13:27 lukem Exp $ */ | |||
3 | ||||
4 | /*- | |||
5 | * Copyright (c) 1980, 1988, 1991, 1993 | |||
6 | * The Regents of the University of California. All rights reserved. | |||
7 | * | |||
8 | * Redistribution and use in source and binary forms, with or without | |||
9 | * modification, are permitted provided that the following conditions | |||
10 | * are met: | |||
11 | * 1. Redistributions of source code must retain the above copyright | |||
12 | * notice, this list of conditions and the following disclaimer. | |||
13 | * 2. Redistributions in binary form must reproduce the above copyright | |||
14 | * notice, this list of conditions and the following disclaimer in the | |||
15 | * documentation and/or other materials provided with the distribution. | |||
16 | * 3. Neither the name of the University nor the names of its contributors | |||
17 | * may be used to endorse or promote products derived from this software | |||
18 | * without specific prior written permission. | |||
19 | * | |||
20 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
30 | * SUCH DAMAGE. | |||
31 | */ | |||
32 | ||||
33 | #include <sys/param.h> /* MAXBSIZE DEV_BSIZE dbtob */ | |||
34 | #include <sys/time.h> | |||
35 | #include <sys/stat.h> | |||
36 | #include <sys/disklabel.h> | |||
37 | #include <ufs/ffs/fs.h> | |||
38 | #include <ufs/ufs/dir.h> | |||
39 | #include <ufs/ufs/dinode.h> | |||
40 | ||||
41 | #include <protocols/dumprestore.h> | |||
42 | ||||
43 | #include <ctype.h> | |||
44 | #include <errno(*__errno()).h> | |||
45 | #include <fts.h> | |||
46 | #include <stdio.h> | |||
47 | #include <stdlib.h> | |||
48 | #include <string.h> | |||
49 | #include <unistd.h> | |||
50 | #include <limits.h> | |||
51 | ||||
52 | #include "dump.h" | |||
53 | ||||
54 | extern struct disklabel lab; | |||
55 | ||||
56 | union dinode { | |||
57 | struct ufs1_dinode dp1; | |||
58 | struct ufs2_dinode dp2; | |||
59 | }; | |||
60 | #define DIP(dp, field)((sblock->fs_magic == 0x011954) ? (dp)->dp1.field : (dp )->dp2.field) \ | |||
61 | ((sblock->fs_magic == FS_UFS1_MAGIC0x011954) ? \ | |||
62 | (dp)->dp1.field : (dp)->dp2.field) | |||
63 | ||||
64 | #define HASDUMPEDFILE0x1 0x1 | |||
65 | #define HASSUBDIRS0x2 0x2 | |||
66 | ||||
67 | static int dirindir(ino_t, daddr_t, int, off_t *, int64_t *, int); | |||
68 | static void dmpindir(ino_t, daddr_t, int, off_t *); | |||
69 | static int searchdir(ino_t, daddr_t, long, off_t, int64_t *, int); | |||
70 | void fs_mapinodes(ino_t maxino, off_t *tapesize, int *anydirskipped); | |||
71 | ||||
72 | /* | |||
73 | * This is an estimation of the number of TP_BSIZE blocks in the file. | |||
74 | * It estimates the number of blocks in files with holes by assuming | |||
75 | * that all of the blocks accounted for by di_blocks are data blocks | |||
76 | * (when some of the blocks are usually used for indirect pointers); | |||
77 | * hence the estimate may be high. | |||
78 | */ | |||
79 | int64_t | |||
80 | blockest(union dinode *dp) | |||
81 | { | |||
82 | int64_t blkest, sizeest; | |||
83 | ||||
84 | /* | |||
85 | * dp->di_size is the size of the file in bytes. | |||
86 | * dp->di_blocks stores the number of sectors actually in the file. | |||
87 | * If there are more sectors than the size would indicate, this just | |||
88 | * means that there are indirect blocks in the file or unused | |||
89 | * sectors in the last file block; we can safely ignore these | |||
90 | * (blkest = sizeest below). | |||
91 | * If the file is bigger than the number of sectors would indicate, | |||
92 | * then the file has holes in it. In this case we must use the | |||
93 | * block count to estimate the number of data blocks used, but | |||
94 | * we use the actual size for estimating the number of indirect | |||
95 | * dump blocks (sizeest vs. blkest in the indirect block | |||
96 | * calculation). | |||
97 | */ | |||
98 | blkest = howmany(dbtob((int64_t)DIP(dp, di_blocks)), TP_BSIZE)((((((int64_t)((sblock->fs_magic == 0x011954) ? (dp)->dp1 .di_blocks : (dp)->dp2.di_blocks)) << 9)) + ((1024) - 1)) / (1024)); | |||
99 | sizeest = howmany((int64_t)DIP(dp, di_size), TP_BSIZE)((((int64_t)((sblock->fs_magic == 0x011954) ? (dp)->dp1 .di_size : (dp)->dp2.di_size)) + ((1024) - 1)) / (1024)); | |||
100 | if (blkest > sizeest) | |||
101 | blkest = sizeest; | |||
102 | if (DIP(dp, di_size)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_size : ( dp)->dp2.di_size) > sblock->fs_bsize * NDADDR12) { | |||
103 | /* calculate the number of indirect blocks on the dump tape */ | |||
104 | blkest += | |||
105 | howmany(sizeest - NDADDR * sblock->fs_bsize / TP_BSIZE,(((sizeest - 12 * sblock->fs_bsize / 1024) + (((1024/2)) - 1)) / ((1024/2))) | |||
106 | TP_NINDIR)(((sizeest - 12 * sblock->fs_bsize / 1024) + (((1024/2)) - 1)) / ((1024/2))); | |||
107 | } | |||
108 | return (blkest + 1); | |||
109 | } | |||
110 | ||||
111 | /* true if "nodump" flag has no effect here, i.e. dumping allowed */ | |||
112 | #define CHECKNODUMP(dp)(nonodump || (((sblock->fs_magic == 0x011954) ? ((dp))-> dp1.di_flags : ((dp))->dp2.di_flags) & 0x00000001) != 0x00000001 ) \ | |||
113 | (nonodump || (DIP((dp), di_flags)((sblock->fs_magic == 0x011954) ? ((dp))->dp1.di_flags : ((dp))->dp2.di_flags) & UF_NODUMP0x00000001) != UF_NODUMP0x00000001) | |||
114 | ||||
115 | /* | |||
116 | * Determine if given inode should be dumped | |||
117 | */ | |||
118 | void | |||
119 | mapfileino(ino_t ino, int64_t *tapesize, int *dirskipped) | |||
120 | { | |||
121 | int mode; | |||
122 | union dinode *dp; | |||
123 | ||||
124 | dp = getino(ino, &mode); | |||
125 | if (mode == 0) | |||
126 | return; | |||
127 | SETINO(ino, usedinomap)usedinomap[(u_int)((ino) - 1) / 8] |= 1 << ((u_int)((ino ) - 1) % 8); | |||
128 | if (mode == IFDIR0040000) | |||
129 | SETINO(ino, dumpdirmap)dumpdirmap[(u_int)((ino) - 1) / 8] |= 1 << ((u_int)((ino ) - 1) % 8); | |||
130 | if (CHECKNODUMP(dp)(nonodump || (((sblock->fs_magic == 0x011954) ? ((dp))-> dp1.di_flags : ((dp))->dp2.di_flags) & 0x00000001) != 0x00000001 ) && | |||
131 | (DIP(dp, di_mtime)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_mtime : ( dp)->dp2.di_mtime) >= spclu_spcl.s_spcl.c_ddate || | |||
132 | DIP(dp, di_ctime)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_ctime : ( dp)->dp2.di_ctime) >= spclu_spcl.s_spcl.c_ddate)) { | |||
133 | SETINO(ino, dumpinomap)dumpinomap[(u_int)((ino) - 1) / 8] |= 1 << ((u_int)((ino ) - 1) % 8); | |||
134 | if (mode != IFREG0100000 && mode != IFDIR0040000 && mode != IFLNK0120000) | |||
135 | *tapesize += 1; | |||
136 | else | |||
137 | *tapesize += blockest(dp); | |||
138 | return; | |||
139 | } | |||
140 | if (mode == IFDIR0040000) { | |||
141 | if (!CHECKNODUMP(dp)(nonodump || (((sblock->fs_magic == 0x011954) ? ((dp))-> dp1.di_flags : ((dp))->dp2.di_flags) & 0x00000001) != 0x00000001 )) | |||
142 | CLRINO(ino, usedinomap)usedinomap[(u_int)((ino) - 1) / 8] &= ~(1 << ((u_int )((ino) - 1) % 8)); | |||
143 | *dirskipped = 1; | |||
144 | } | |||
145 | } | |||
146 | ||||
147 | void | |||
148 | fs_mapinodes(ino_t maxino, int64_t *tapesize, int *anydirskipped) | |||
149 | { | |||
150 | int i, cg, inosused; | |||
151 | struct cg *cgp; | |||
152 | ino_t ino; | |||
153 | char *cp; | |||
154 | ||||
155 | if ((cgp = malloc(sblock->fs_cgsize)) == NULL((void *)0)) | |||
156 | quit("fs_mapinodes: cannot allocate memory.\n"); | |||
157 | ||||
158 | for (cg = 0; cg < sblock->fs_ncg; cg++) { | |||
159 | ino = cg * (ino_t)sblock->fs_ipg; | |||
160 | bread(fsbtodb(sblock, cgtod(sblock, cg))((((((daddr_t)(sblock)->fs_fpg * (cg)) + (sblock)->fs_cgoffset * ((cg) & ~((sblock)->fs_cgmask))) + (sblock)->fs_cblkno )) << (sblock)->fs_fsbtodb), (char *)cgp, | |||
161 | sblock->fs_cgsize); | |||
162 | if (sblock->fs_magic == FS_UFS2_MAGIC0x19540119) | |||
163 | inosused = cgp->cg_initediblk; | |||
164 | else | |||
165 | inosused = sblock->fs_ipg; | |||
166 | /* | |||
167 | * If we are using soft updates, then we can trust the | |||
168 | * cylinder group inode allocation maps to tell us which | |||
169 | * inodes are allocated. We will scan the used inode map | |||
170 | * to find the inodes that are really in use, and then | |||
171 | * read only those inodes in from disk. | |||
172 | */ | |||
173 | if (sblock->fs_flags & FS_DOSOFTDEP0x02) { | |||
174 | if (!cg_chkmagic(cgp)((cgp)->cg_magic == 0x090255 || ((struct ocg *)(cgp))-> cg_magic == 0x090255)) | |||
175 | quit("mapfiles: cg %d: bad magic number\n", cg); | |||
176 | cp = &cg_inosused(cgp)(((cgp)->cg_magic != 0x090255) ? (((struct ocg *)(cgp))-> cg_iused) : ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_iusedoff )))[(inosused - 1) / CHAR_BIT8]; | |||
177 | for ( ; inosused > 0; inosused -= CHAR_BIT8, cp--) { | |||
178 | if (*cp == 0) | |||
179 | continue; | |||
180 | for (i = 1 << (CHAR_BIT8 - 1); i > 0; i >>= 1) { | |||
181 | if (*cp & i) | |||
182 | break; | |||
183 | inosused--; | |||
184 | } | |||
185 | break; | |||
186 | } | |||
187 | if (inosused <= 0) | |||
188 | continue; | |||
189 | } | |||
190 | for (i = 0; i < inosused; i++, ino++) { | |||
191 | if (ino < ROOTINO((ufsino_t)2)) | |||
192 | continue; | |||
193 | mapfileino(ino, tapesize, anydirskipped); | |||
194 | } | |||
195 | } | |||
196 | ||||
197 | free(cgp); | |||
198 | } | |||
199 | ||||
200 | /* | |||
201 | * Dump pass 1. | |||
202 | * | |||
203 | * Walk the inode list for a filesystem to find all allocated inodes | |||
204 | * that have been modified since the previous dump time. Also, find all | |||
205 | * the directories in the filesystem. | |||
206 | */ | |||
207 | int | |||
208 | mapfiles(ino_t maxino, int64_t *tapesize, char *disk, char * const *dirv) | |||
209 | { | |||
210 | int anydirskipped = 0; | |||
211 | ||||
212 | if (dirv != NULL((void *)0)) { | |||
213 | char curdir[PATH_MAX1024]; | |||
214 | FTS *dirh; | |||
215 | FTSENT *entry; | |||
216 | int d; | |||
217 | ||||
218 | if (getcwd(curdir, sizeof(curdir)) == NULL((void *)0)) { | |||
219 | msg("Can't determine cwd: %s\n", strerror(errno(*__errno()))); | |||
220 | dumpabort(0); | |||
221 | } | |||
222 | if ((dirh = fts_open(dirv, FTS_PHYSICAL0x0010|FTS_SEEDOT0x0020|FTS_XDEV0x0040, | |||
223 | NULL((void *)0))) == NULL((void *)0)) { | |||
224 | msg("fts_open failed: %s\n", strerror(errno(*__errno()))); | |||
225 | dumpabort(0); | |||
226 | } | |||
227 | while ((entry = fts_read(dirh)) != NULL((void *)0)) { | |||
228 | switch (entry->fts_info) { | |||
229 | case FTS_DNR4: /* an error */ | |||
230 | case FTS_ERR7: | |||
231 | case FTS_NS10: | |||
232 | msg("Can't fts_read %s: %s\n", entry->fts_path, | |||
233 | strerror(errno(*__errno()))); | |||
234 | /* FALLTHROUGH */ | |||
235 | case FTS_DP6: /* already seen dir */ | |||
236 | continue; | |||
237 | } | |||
238 | mapfileino(entry->fts_statp->st_ino, tapesize, | |||
239 | &anydirskipped); | |||
240 | } | |||
241 | if (errno(*__errno())) { | |||
242 | msg("fts_read failed: %s\n", strerror(errno(*__errno()))); | |||
243 | dumpabort(0); | |||
244 | } | |||
245 | (void)fts_close(dirh); | |||
246 | ||||
247 | /* | |||
248 | * Add any parent directories | |||
249 | */ | |||
250 | for (d = 0 ; dirv[d] != NULL((void *)0) ; d++) { | |||
251 | char path[PATH_MAX1024]; | |||
252 | ||||
253 | if (dirv[d][0] != '/') | |||
254 | (void)snprintf(path, sizeof(path), "%s/%s", | |||
255 | curdir, dirv[d]); | |||
256 | else | |||
257 | (void)snprintf(path, sizeof(path), "%s", | |||
258 | dirv[d]); | |||
259 | while (strcmp(path, disk) != 0) { | |||
260 | char *p; | |||
261 | struct stat sb; | |||
262 | ||||
263 | if (*path == '\0') | |||
264 | break; | |||
265 | if ((p = strrchr(path, '/')) == NULL((void *)0)) | |||
266 | break; | |||
267 | if (p == path) | |||
268 | break; | |||
269 | *p = '\0'; | |||
270 | if (stat(path, &sb) == -1) { | |||
271 | msg("Can't stat %s: %s\n", path, | |||
272 | strerror(errno(*__errno()))); | |||
273 | break; | |||
274 | } | |||
275 | mapfileino(sb.st_ino, tapesize, &anydirskipped); | |||
276 | } | |||
277 | } | |||
278 | ||||
279 | /* | |||
280 | * Ensure that the root inode actually appears in the | |||
281 | * file list for a subdir | |||
282 | */ | |||
283 | mapfileino(ROOTINO((ufsino_t)2), tapesize, &anydirskipped); | |||
284 | } else { | |||
285 | fs_mapinodes(maxino, tapesize, &anydirskipped); | |||
286 | } | |||
287 | /* | |||
288 | * Restore gets very upset if the root is not dumped, | |||
289 | * so ensure that it always is dumped. | |||
290 | */ | |||
291 | SETINO(ROOTINO, dumpinomap)dumpinomap[(u_int)((((ufsino_t)2)) - 1) / 8] |= 1 << (( u_int)((((ufsino_t)2)) - 1) % 8); | |||
292 | return (anydirskipped); | |||
293 | } | |||
294 | ||||
295 | /* | |||
296 | * Dump pass 2. | |||
297 | * | |||
298 | * Scan each directory on the filesystem to see if it has any modified | |||
299 | * files in it. If it does, and has not already been added to the dump | |||
300 | * list (because it was itself modified), then add it. If a directory | |||
301 | * has not been modified itself, contains no modified files and has no | |||
302 | * subdirectories, then it can be deleted from the dump list and from | |||
303 | * the list of directories. By deleting it from the list of directories, | |||
304 | * its parent may now qualify for the same treatment on this or a later | |||
305 | * pass using this algorithm. | |||
306 | */ | |||
307 | int | |||
308 | mapdirs(ino_t maxino, int64_t *tapesize) | |||
309 | { | |||
310 | union dinode *dp; | |||
311 | int i, isdir, nodump; | |||
312 | char *map; | |||
313 | ino_t ino; | |||
314 | union dinode di; | |||
315 | off_t filesize; | |||
316 | int ret, change = 0; | |||
317 | ||||
318 | isdir = 0; /* XXX just to get gcc to shut up */ | |||
319 | for (map = dumpdirmap, ino = 1; ino < maxino; ino++) { | |||
320 | if (((ino - 1) % NBBY8) == 0) /* map is offset by 1 */ | |||
321 | isdir = *map++; | |||
322 | else | |||
323 | isdir >>= 1; | |||
324 | /* | |||
325 | * If a directory has been removed from usedinomap, it | |||
326 | * either has the nodump flag set, or has inherited | |||
327 | * it. Although a directory can't be in dumpinomap if | |||
328 | * it isn't in usedinomap, we have to go through it to | |||
329 | * propagate the nodump flag. | |||
330 | */ | |||
331 | nodump = !nonodump && !TSTINO(ino, usedinomap)(usedinomap[(u_int)((ino) - 1) / 8] & (1 << ((u_int )((ino) - 1) % 8))); | |||
332 | if ((isdir & 1) == 0 || (TSTINO(ino, dumpinomap)(dumpinomap[(u_int)((ino) - 1) / 8] & (1 << ((u_int )((ino) - 1) % 8))) && !nodump)) | |||
333 | continue; | |||
334 | dp = getino(ino, &i); | |||
335 | /* | |||
336 | * inode buf may change in searchdir(). | |||
337 | */ | |||
338 | if (sblock->fs_magic == FS_UFS1_MAGIC0x011954) | |||
339 | di.dp1 = dp->dp1; | |||
340 | else | |||
341 | di.dp2 = dp->dp2; | |||
342 | filesize = (off_t)DIP(dp, di_size)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_size : ( dp)->dp2.di_size); | |||
343 | for (ret = 0, i = 0; filesize > 0 && i < NDADDR12; i++) { | |||
344 | if (DIP(&di, di_db[i])((sblock->fs_magic == 0x011954) ? (&di)->dp1.di_db[ i] : (&di)->dp2.di_db[i]) != 0) | |||
345 | ret |= searchdir(ino, DIP(&di, di_db[i])((sblock->fs_magic == 0x011954) ? (&di)->dp1.di_db[ i] : (&di)->dp2.di_db[i]), | |||
346 | sblksize(sblock, DIP(dp, di_size), i)(((i) >= 12 || (((sblock->fs_magic == 0x011954) ? (dp)-> dp1.di_size : (dp)->dp2.di_size)) >= ((i) + 1) << (sblock)->fs_bshift) ? (u_int64_t)(sblock)->fs_bsize : (((((((((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_size : (dp)->dp2.di_size))) & (sblock)->fs_qbmask)) + ( sblock)->fs_qfmask) & (sblock)->fs_fmask))), | |||
347 | filesize, tapesize, nodump); | |||
348 | if (ret & HASDUMPEDFILE0x1) | |||
349 | filesize = 0; | |||
350 | else | |||
351 | filesize -= sblock->fs_bsize; | |||
352 | } | |||
353 | for (i = 0; filesize > 0 && i < NIADDR3; i++) { | |||
354 | if (DIP(&di, di_ib[i])((sblock->fs_magic == 0x011954) ? (&di)->dp1.di_ib[ i] : (&di)->dp2.di_ib[i]) == 0) | |||
355 | continue; | |||
356 | ret |= dirindir(ino, DIP(&di, di_ib[i])((sblock->fs_magic == 0x011954) ? (&di)->dp1.di_ib[ i] : (&di)->dp2.di_ib[i]), i, &filesize, | |||
357 | tapesize, nodump); | |||
358 | } | |||
359 | if (ret & HASDUMPEDFILE0x1) { | |||
360 | SETINO(ino, dumpinomap)dumpinomap[(u_int)((ino) - 1) / 8] |= 1 << ((u_int)((ino ) - 1) % 8); | |||
361 | *tapesize += blockest(dp); | |||
362 | change = 1; | |||
363 | continue; | |||
364 | } | |||
365 | if (nodump) { | |||
366 | if (ret & HASSUBDIRS0x2) | |||
367 | change = 1; /* subdirs inherit nodump */ | |||
368 | CLRINO(ino, dumpdirmap)dumpdirmap[(u_int)((ino) - 1) / 8] &= ~(1 << ((u_int )((ino) - 1) % 8)); | |||
369 | } else if ((ret & HASSUBDIRS0x2) == 0) { | |||
370 | if (!TSTINO(ino, dumpinomap)(dumpinomap[(u_int)((ino) - 1) / 8] & (1 << ((u_int )((ino) - 1) % 8)))) { | |||
371 | CLRINO(ino, dumpdirmap)dumpdirmap[(u_int)((ino) - 1) / 8] &= ~(1 << ((u_int )((ino) - 1) % 8)); | |||
372 | change = 1; | |||
373 | } | |||
374 | } | |||
375 | } | |||
376 | return (change); | |||
377 | } | |||
378 | ||||
379 | /* | |||
380 | * Read indirect blocks, and pass the data blocks to be searched | |||
381 | * as directories. Quit as soon as any entry is found that will | |||
382 | * require the directory to be dumped. | |||
383 | */ | |||
384 | static int | |||
385 | dirindir(ino_t ino, daddr_t blkno, int ind_level, off_t *filesize, | |||
386 | int64_t *tapesize, int nodump) | |||
387 | { | |||
388 | int ret = 0; | |||
389 | int i; | |||
390 | char idblk[MAXBSIZE(64 * 1024)]; | |||
391 | ||||
392 | bread(fsbtodb(sblock, blkno)((blkno) << (sblock)->fs_fsbtodb), idblk, (int)sblock->fs_bsize); | |||
393 | if (ind_level <= 0) { | |||
394 | for (i = 0; *filesize > 0 && i < NINDIR(sblock)((sblock)->fs_nindir); i++) { | |||
395 | if (sblock->fs_magic == FS_UFS1_MAGIC0x011954) | |||
396 | blkno = ((int32_t *)idblk)[i]; | |||
397 | else | |||
398 | blkno = ((int64_t *)idblk)[i]; | |||
399 | if (blkno != 0) | |||
400 | ret |= searchdir(ino, blkno, sblock->fs_bsize, | |||
401 | *filesize, tapesize, nodump); | |||
402 | if (ret & HASDUMPEDFILE0x1) | |||
403 | *filesize = 0; | |||
404 | else | |||
405 | *filesize -= sblock->fs_bsize; | |||
406 | } | |||
407 | return (ret); | |||
408 | } | |||
409 | ind_level--; | |||
410 | for (i = 0; *filesize > 0 && i < NINDIR(sblock)((sblock)->fs_nindir); i++) { | |||
411 | if (sblock->fs_magic == FS_UFS1_MAGIC0x011954) | |||
412 | blkno = ((int32_t *)idblk)[i]; | |||
413 | else | |||
414 | blkno = ((int64_t *)idblk)[i]; | |||
415 | if (blkno != 0) | |||
416 | ret |= dirindir(ino, blkno, ind_level, filesize, | |||
417 | tapesize, nodump); | |||
418 | } | |||
419 | return (ret); | |||
420 | } | |||
421 | ||||
422 | /* | |||
423 | * Scan a disk block containing directory information looking to see if | |||
424 | * any of the entries are on the dump list and to see if the directory | |||
425 | * contains any subdirectories. | |||
426 | */ | |||
427 | static int | |||
428 | searchdir(ino_t ino, daddr_t blkno, long size, off_t filesize, | |||
429 | int64_t *tapesize, int nodump) | |||
430 | { | |||
431 | struct direct *dp; | |||
432 | union dinode *ip; | |||
433 | long loc; | |||
434 | static caddr_t dblk; | |||
435 | int mode, ret = 0; | |||
436 | ||||
437 | if (dblk == NULL((void *)0) && (dblk = malloc(sblock->fs_bsize)) == NULL((void *)0)) | |||
438 | quit("searchdir: cannot allocate indirect memory.\n"); | |||
439 | bread(fsbtodb(sblock, blkno)((blkno) << (sblock)->fs_fsbtodb), dblk, (int)size); | |||
440 | if (filesize < size) | |||
441 | size = filesize; | |||
442 | for (loc = 0; loc < size; ) { | |||
443 | dp = (struct direct *)(dblk + loc); | |||
444 | if (dp->d_reclen == 0) { | |||
445 | msg("corrupted directory, inumber %llu\n", | |||
446 | (unsigned long long)ino); | |||
447 | break; | |||
448 | } | |||
449 | loc += dp->d_reclen; | |||
450 | if (dp->d_ino == 0) | |||
451 | continue; | |||
452 | if (dp->d_name[0] == '.') { | |||
453 | if (dp->d_name[1] == '\0') | |||
454 | continue; | |||
455 | if (dp->d_name[1] == '.' && dp->d_name[2] == '\0') | |||
456 | continue; | |||
457 | } | |||
458 | if (nodump) { | |||
459 | ip = getino(dp->d_ino, &mode); | |||
460 | if (TSTINO(dp->d_ino, dumpinomap)(dumpinomap[(u_int)((dp->d_ino) - 1) / 8] & (1 << ((u_int)((dp->d_ino) - 1) % 8)))) { | |||
461 | CLRINO(dp->d_ino, dumpinomap)dumpinomap[(u_int)((dp->d_ino) - 1) / 8] &= ~(1 << ((u_int)((dp->d_ino) - 1) % 8)); | |||
462 | *tapesize -= blockest(ip); | |||
463 | } | |||
464 | /* | |||
465 | * Add back to dumpdirmap and remove from usedinomap | |||
466 | * to propagate nodump. | |||
467 | */ | |||
468 | if (mode == IFDIR0040000) { | |||
469 | SETINO(dp->d_ino, dumpdirmap)dumpdirmap[(u_int)((dp->d_ino) - 1) / 8] |= 1 << ((u_int )((dp->d_ino) - 1) % 8); | |||
470 | CLRINO(dp->d_ino, usedinomap)usedinomap[(u_int)((dp->d_ino) - 1) / 8] &= ~(1 << ((u_int)((dp->d_ino) - 1) % 8)); | |||
471 | ret |= HASSUBDIRS0x2; | |||
472 | } | |||
473 | } else { | |||
474 | if (TSTINO(dp->d_ino, dumpinomap)(dumpinomap[(u_int)((dp->d_ino) - 1) / 8] & (1 << ((u_int)((dp->d_ino) - 1) % 8)))) { | |||
475 | ret |= HASDUMPEDFILE0x1; | |||
476 | if (ret & HASSUBDIRS0x2) | |||
477 | break; | |||
478 | } | |||
479 | if (TSTINO(dp->d_ino, dumpdirmap)(dumpdirmap[(u_int)((dp->d_ino) - 1) / 8] & (1 << ((u_int)((dp->d_ino) - 1) % 8)))) { | |||
480 | ret |= HASSUBDIRS0x2; | |||
481 | if (ret & HASDUMPEDFILE0x1) | |||
482 | break; | |||
483 | } | |||
484 | } | |||
485 | } | |||
486 | return (ret); | |||
487 | } | |||
488 | ||||
489 | /* | |||
490 | * Dump passes 3 and 4. | |||
491 | * | |||
492 | * Dump the contents of an inode to tape. | |||
493 | */ | |||
494 | void | |||
495 | dumpino(union dinode *dp, ino_t ino) | |||
496 | { | |||
497 | int ind_level, cnt; | |||
498 | off_t size; | |||
499 | char buf[TP_BSIZE1024]; | |||
500 | ||||
501 | if (newtape) { | |||
| ||||
502 | newtape = 0; | |||
503 | dumpmap(dumpinomap, TS_BITS3, ino); | |||
504 | } | |||
505 | CLRINO(ino, dumpinomap)dumpinomap[(u_int)((ino) - 1) / 8] &= ~(1 << ((u_int )((ino) - 1) % 8)); | |||
506 | if (sblock->fs_magic == FS_UFS1_MAGIC0x011954) { | |||
507 | spclu_spcl.s_spcl.c_mode__c_ino.__uc_ino.__uc_mode = dp->dp1.di_mode; | |||
508 | spclu_spcl.s_spcl.c_size__c_ino.__uc_ino.__uc_size = dp->dp1.di_size; | |||
509 | spclu_spcl.s_spcl.c_old_atime__c_ino.__uc_ino.__uc_old_atime = (time_t)dp->dp1.di_atime; | |||
510 | spclu_spcl.s_spcl.c_atime__c_ino.__uc_ino.__uc_atime = dp->dp1.di_atime; | |||
511 | spclu_spcl.s_spcl.c_atimensec__c_ino.__uc_ino.__uc_atimensec = dp->dp1.di_atimensec; | |||
512 | spclu_spcl.s_spcl.c_old_mtime__c_ino.__uc_ino.__uc_old_mtime = (time_t)dp->dp1.di_mtime; | |||
513 | spclu_spcl.s_spcl.c_mtime__c_ino.__uc_ino.__uc_mtime = dp->dp1.di_mtime; | |||
514 | spclu_spcl.s_spcl.c_mtimensec__c_ino.__uc_ino.__uc_mtimensec = dp->dp1.di_mtimensec; | |||
515 | spclu_spcl.s_spcl.c_birthtime__c_ino.__uc_ino.__uc_birthtime = 0; | |||
516 | spclu_spcl.s_spcl.c_birthtimensec__c_ino.__uc_ino.__uc_birthtimensec = 0; | |||
517 | spclu_spcl.s_spcl.c_rdev__c_ino.__uc_ino.__uc_rdev = dp->dp1.di_rdevdi_db[0]; | |||
518 | spclu_spcl.s_spcl.c_file_flags__c_ino.__uc_ino.__uc_file_flags = dp->dp1.di_flags; | |||
519 | spclu_spcl.s_spcl.c_uid__c_ino.__uc_ino.__uc_uid = dp->dp1.di_uid; | |||
520 | spclu_spcl.s_spcl.c_gid__c_ino.__uc_ino.__uc_gid = dp->dp1.di_gid; | |||
521 | } else { | |||
522 | spclu_spcl.s_spcl.c_mode__c_ino.__uc_ino.__uc_mode = dp->dp2.di_mode; | |||
523 | spclu_spcl.s_spcl.c_size__c_ino.__uc_ino.__uc_size = dp->dp2.di_size; | |||
524 | spclu_spcl.s_spcl.c_atime__c_ino.__uc_ino.__uc_atime = dp->dp2.di_atime; | |||
525 | spclu_spcl.s_spcl.c_atimensec__c_ino.__uc_ino.__uc_atimensec = dp->dp2.di_atimensec; | |||
526 | spclu_spcl.s_spcl.c_mtime__c_ino.__uc_ino.__uc_mtime = dp->dp2.di_mtime; | |||
527 | spclu_spcl.s_spcl.c_mtimensec__c_ino.__uc_ino.__uc_mtimensec = dp->dp2.di_mtimensec; | |||
528 | spclu_spcl.s_spcl.c_birthtime__c_ino.__uc_ino.__uc_birthtime = dp->dp2.di_birthtime; | |||
529 | spclu_spcl.s_spcl.c_birthtimensec__c_ino.__uc_ino.__uc_birthtimensec = dp->dp2.di_birthnsec; | |||
530 | spclu_spcl.s_spcl.c_rdev__c_ino.__uc_ino.__uc_rdev = dp->dp2.di_rdevdi_db[0]; | |||
531 | spclu_spcl.s_spcl.c_file_flags__c_ino.__uc_ino.__uc_file_flags = dp->dp2.di_flags; | |||
532 | spclu_spcl.s_spcl.c_uid__c_ino.__uc_ino.__uc_uid = dp->dp2.di_uid; | |||
533 | spclu_spcl.s_spcl.c_gid__c_ino.__uc_ino.__uc_gid = dp->dp2.di_gid; | |||
534 | } | |||
535 | spclu_spcl.s_spcl.c_type = TS_INODE2; | |||
536 | spclu_spcl.s_spcl.c_count = 0; | |||
537 | switch (DIP(dp, di_mode)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_mode : ( dp)->dp2.di_mode) & S_IFMT0170000) { | |||
538 | ||||
539 | case 0: | |||
540 | /* | |||
541 | * Freed inode. | |||
542 | */ | |||
543 | return; | |||
544 | ||||
545 | case IFLNK0120000: | |||
546 | /* | |||
547 | * Check for short symbolic link. | |||
548 | */ | |||
549 | if (DIP(dp, di_size)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_size : ( dp)->dp2.di_size) > 0 && | |||
550 | DIP(dp, di_size)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_size : ( dp)->dp2.di_size) < sblock->fs_maxsymlinklen) { | |||
551 | void *shortlink; | |||
552 | ||||
553 | spclu_spcl.s_spcl.c_addr[0] = 1; | |||
554 | spclu_spcl.s_spcl.c_count = 1; | |||
555 | writeheader(ino); | |||
556 | if (sblock->fs_magic == FS_UFS1_MAGIC0x011954) | |||
557 | shortlink = dp->dp1.di_shortlinkdi_db; | |||
558 | else | |||
559 | shortlink = dp->dp2.di_shortlinkdi_db; | |||
560 | memcpy(buf, shortlink, DIP(dp, di_size)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_size : ( dp)->dp2.di_size)); | |||
561 | buf[DIP(dp, di_size)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_size : ( dp)->dp2.di_size)] = '\0'; | |||
562 | writerec(buf, 0); | |||
563 | return; | |||
564 | } | |||
565 | /* FALLTHROUGH */ | |||
566 | ||||
567 | case IFDIR0040000: | |||
568 | case IFREG0100000: | |||
569 | if (DIP(dp, di_size)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_size : ( dp)->dp2.di_size) > 0) | |||
570 | break; | |||
571 | /* FALLTHROUGH */ | |||
572 | ||||
573 | case IFIFO0010000: | |||
574 | case IFSOCK0140000: | |||
575 | case IFCHR0020000: | |||
576 | case IFBLK0060000: | |||
577 | writeheader(ino); | |||
578 | return; | |||
579 | ||||
580 | default: | |||
581 | msg("Warning: undefined file type 0%o\n", | |||
582 | DIP(dp, di_mode)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_mode : ( dp)->dp2.di_mode) & IFMT0170000); | |||
583 | return; | |||
584 | } | |||
585 | if (DIP(dp, di_size)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_size : ( dp)->dp2.di_size) > NDADDR12 * sblock->fs_bsize) | |||
586 | cnt = NDADDR12 * sblock->fs_frag; | |||
587 | else | |||
588 | cnt = howmany(DIP(dp, di_size), sblock->fs_fsize)(((((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_size : (dp)->dp2.di_size)) + ((sblock->fs_fsize) - 1)) / (sblock ->fs_fsize)); | |||
589 | if (sblock->fs_magic
| |||
590 | ufs1_blksout(&dp->dp1.di_db[0], cnt, ino); | |||
591 | else | |||
592 | ufs2_blksout(&dp->dp2.di_db[0], cnt, ino); | |||
593 | if ((size = DIP(dp, di_size)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_size : ( dp)->dp2.di_size) - NDADDR12 * sblock->fs_bsize) <= 0) | |||
594 | return; | |||
595 | for (ind_level = 0; ind_level < NIADDR3; ind_level++) { | |||
596 | dmpindir(ino, DIP(dp, di_ib[ind_level])((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_ib[ind_level ] : (dp)->dp2.di_ib[ind_level]), ind_level, &size); | |||
597 | if (size <= 0) | |||
598 | return; | |||
599 | } | |||
600 | } | |||
601 | ||||
602 | /* | |||
603 | * Read indirect blocks, and pass the data blocks to be dumped. | |||
604 | */ | |||
605 | static void | |||
606 | dmpindir(ino_t ino, daddr_t blk, int ind_level, off_t *size) | |||
607 | { | |||
608 | int i, cnt; | |||
609 | char idblk[MAXBSIZE(64 * 1024)]; | |||
610 | ||||
611 | if (blk != 0) | |||
612 | bread(fsbtodb(sblock, blk)((blk) << (sblock)->fs_fsbtodb), idblk, (int) sblock->fs_bsize); | |||
613 | else | |||
614 | memset(idblk, 0, (int)sblock->fs_bsize); | |||
615 | if (ind_level <= 0) { | |||
616 | if (*size < NINDIR(sblock)((sblock)->fs_nindir) * sblock->fs_bsize) | |||
617 | cnt = howmany(*size, sblock->fs_fsize)(((*size) + ((sblock->fs_fsize) - 1)) / (sblock->fs_fsize )); | |||
618 | else | |||
619 | cnt = NINDIR(sblock)((sblock)->fs_nindir) * sblock->fs_frag; | |||
620 | *size -= NINDIR(sblock)((sblock)->fs_nindir) * sblock->fs_bsize; | |||
621 | if (sblock->fs_magic == FS_UFS1_MAGIC0x011954) | |||
622 | ufs1_blksout((int32_t *)idblk, cnt, ino); | |||
623 | else | |||
624 | ufs2_blksout((int64_t *)idblk, cnt, ino); | |||
625 | return; | |||
626 | } | |||
627 | ind_level--; | |||
628 | for (i = 0; i < NINDIR(sblock)((sblock)->fs_nindir); i++) { | |||
629 | if (sblock->fs_magic == FS_UFS1_MAGIC0x011954) | |||
630 | dmpindir(ino, ((int32_t *)idblk)[i], ind_level, | |||
631 | size); | |||
632 | else | |||
633 | dmpindir(ino, ((int64_t *)idblk)[i], ind_level, | |||
634 | size); | |||
635 | if (*size <= 0) | |||
636 | return; | |||
637 | } | |||
638 | } | |||
639 | ||||
640 | /* | |||
641 | * Collect up the data into tape record sized buffers and output them. | |||
642 | */ | |||
643 | void | |||
644 | ufs1_blksout(int32_t *blkp, int frags, ino_t ino) | |||
645 | { | |||
646 | int32_t *bp; | |||
647 | int i, j, count, blks, tbperdb; | |||
648 | ||||
649 | blks = howmany(frags * sblock->fs_fsize, TP_BSIZE)(((frags * sblock->fs_fsize) + ((1024) - 1)) / (1024)); | |||
650 | tbperdb = sblock->fs_bsize >> tp_bshift; | |||
651 | for (i = 0; i < blks; i += TP_NINDIR(1024/2)) { | |||
652 | if (i + TP_NINDIR(1024/2) > blks) | |||
653 | count = blks; | |||
654 | else | |||
655 | count = i + TP_NINDIR(1024/2); | |||
656 | for (j = i; j < count; j++) | |||
657 | if (blkp[j / tbperdb] != 0) | |||
658 | spclu_spcl.s_spcl.c_addr[j - i] = 1; | |||
659 | else | |||
660 | spclu_spcl.s_spcl.c_addr[j - i] = 0; | |||
661 | spclu_spcl.s_spcl.c_count = count - i; | |||
662 | writeheader(ino); | |||
663 | bp = &blkp[i / tbperdb]; | |||
664 | for (j = i; j < count; j += tbperdb, bp++) | |||
665 | if (*bp != 0) { | |||
666 | if (j + tbperdb <= count) | |||
667 | dumpblock(*bp, (int)sblock->fs_bsize); | |||
668 | else | |||
669 | dumpblock(*bp, (count - j) * TP_BSIZE1024); | |||
670 | } | |||
671 | spclu_spcl.s_spcl.c_type = TS_ADDR4; | |||
672 | } | |||
673 | } | |||
674 | ||||
675 | /* | |||
676 | * Collect up the data into tape record sized buffers and output them. | |||
677 | */ | |||
678 | void | |||
679 | ufs2_blksout(daddr_t *blkp, int frags, ino_t ino) | |||
680 | { | |||
681 | daddr_t *bp; | |||
682 | int i, j, count, blks, tbperdb; | |||
683 | ||||
684 | blks = howmany(frags * sblock->fs_fsize, TP_BSIZE)(((frags * sblock->fs_fsize) + ((1024) - 1)) / (1024)); | |||
685 | tbperdb = sblock->fs_bsize >> tp_bshift; | |||
686 | for (i = 0; i < blks; i += TP_NINDIR(1024/2)) { | |||
687 | if (i + TP_NINDIR(1024/2) > blks) | |||
688 | count = blks; | |||
689 | else | |||
690 | count = i + TP_NINDIR(1024/2); | |||
691 | for (j = i; j < count; j++) | |||
692 | if (blkp[j / tbperdb] != 0) | |||
693 | spclu_spcl.s_spcl.c_addr[j - i] = 1; | |||
694 | else | |||
695 | spclu_spcl.s_spcl.c_addr[j - i] = 0; | |||
696 | spclu_spcl.s_spcl.c_count = count - i; | |||
697 | writeheader(ino); | |||
698 | bp = &blkp[i / tbperdb]; | |||
699 | for (j = i; j < count; j += tbperdb, bp++) | |||
700 | if (*bp != 0) { | |||
701 | if (j + tbperdb <= count) | |||
702 | dumpblock(*bp, (int)sblock->fs_bsize); | |||
703 | else | |||
704 | dumpblock(*bp, (count - j) * TP_BSIZE1024); | |||
705 | } | |||
706 | spclu_spcl.s_spcl.c_type = TS_ADDR4; | |||
707 | } | |||
708 | } | |||
709 | ||||
710 | /* | |||
711 | * Dump a map to the tape. | |||
712 | */ | |||
713 | void | |||
714 | dumpmap(char *map, int type, ino_t ino) | |||
715 | { | |||
716 | int i; | |||
717 | char *cp; | |||
718 | ||||
719 | spclu_spcl.s_spcl.c_type = type; | |||
720 | spclu_spcl.s_spcl.c_count = howmany(mapsize * sizeof(char), TP_BSIZE)(((mapsize * sizeof(char)) + ((1024) - 1)) / (1024)); | |||
721 | writeheader(ino); | |||
722 | for (i = 0, cp = map; i < spclu_spcl.s_spcl.c_count; i++, cp += TP_BSIZE1024) | |||
723 | writerec(cp, 0); | |||
724 | } | |||
725 | ||||
726 | /* | |||
727 | * Write a header record to the dump tape. | |||
728 | */ | |||
729 | void | |||
730 | writeheader(ino_t ino) | |||
731 | { | |||
732 | int32_t sum, cnt, *lp; | |||
733 | ||||
734 | spclu_spcl.s_spcl.c_inumber = ino; | |||
735 | if (sblock->fs_magic == FS_UFS2_MAGIC0x19540119) { | |||
736 | spclu_spcl.s_spcl.c_magic = FS_UFS2_MAGIC0x19540119; | |||
737 | } else { | |||
738 | spclu_spcl.s_spcl.c_magic = NFS_MAGIC(int)60012; | |||
739 | spclu_spcl.s_spcl.c_old_date = (int32_t)spclu_spcl.s_spcl.c_date; | |||
740 | spclu_spcl.s_spcl.c_old_ddate = (int32_t)spclu_spcl.s_spcl.c_ddate; | |||
741 | spclu_spcl.s_spcl.c_old_tapea = (int32_t)spclu_spcl.s_spcl.c_tapea; | |||
742 | spclu_spcl.s_spcl.c_old_firstrec = (int32_t)spclu_spcl.s_spcl.c_firstrec; | |||
743 | } | |||
744 | spclu_spcl.s_spcl.c_checksum = 0; | |||
745 | lp = (int32_t *)&spclu_spcl.s_spcl; | |||
746 | sum = 0; | |||
747 | cnt = sizeof(union u_spcl) / (4 * sizeof(int32_t)); | |||
748 | while (--cnt >= 0) { | |||
749 | sum += *lp++; | |||
750 | sum += *lp++; | |||
751 | sum += *lp++; | |||
752 | sum += *lp++; | |||
753 | } | |||
754 | spclu_spcl.s_spcl.c_checksum = CHECKSUM(int)84446 - sum; | |||
755 | writerec((char *)&spclu_spcl.s_spcl, 1); | |||
756 | } | |||
757 | ||||
758 | union dinode * | |||
759 | getino(ino_t inum, int *modep) | |||
760 | { | |||
761 | static ino_t minino, maxino; | |||
762 | static void *inoblock; | |||
763 | struct ufs1_dinode *dp1; | |||
764 | struct ufs2_dinode *dp2; | |||
765 | ||||
766 | if (inoblock == NULL((void *)0) && (inoblock = malloc(sblock->fs_bsize)) == NULL((void *)0)) | |||
767 | quit("cannot allocate inode memory.\n"); | |||
768 | curino = inum; | |||
769 | if (inum >= minino && inum < maxino) | |||
770 | goto gotit; | |||
771 | bread(fsbtodb(sblock, ino_to_fsba(sblock, inum))((((daddr_t)(((((daddr_t)(sblock)->fs_fpg * (((inum) / (sblock )->fs_ipg))) + (sblock)->fs_cgoffset * ((((inum) / (sblock )->fs_ipg)) & ~((sblock)->fs_cgmask))) + (sblock)-> fs_iblkno) + ((((((inum) % (sblock)->fs_ipg) / ((sblock)-> fs_inopb))) << ((sblock))->fs_fragshift))))) << (sblock)->fs_fsbtodb), inoblock, | |||
772 | (int)sblock->fs_bsize); | |||
773 | minino = inum - (inum % INOPB(sblock)((sblock)->fs_inopb)); | |||
774 | maxino = minino + INOPB(sblock)((sblock)->fs_inopb); | |||
775 | gotit: | |||
776 | if (sblock->fs_magic == FS_UFS1_MAGIC0x011954) { | |||
777 | dp1 = &((struct ufs1_dinode *)inoblock)[inum - minino]; | |||
778 | *modep = (dp1->di_mode & IFMT0170000); | |||
779 | return ((union dinode *)dp1); | |||
780 | } | |||
781 | dp2 = &((struct ufs2_dinode *)inoblock)[inum - minino]; | |||
782 | *modep = (dp2->di_mode & IFMT0170000); | |||
783 | return ((union dinode *)dp2); | |||
784 | } | |||
785 | ||||
786 | /* | |||
787 | * Read a chunk of data from the disk. | |||
788 | * Try to recover from hard errors by reading in sector sized pieces. | |||
789 | * Error recovery is attempted at most BREADEMAX times before seeking | |||
790 | * consent from the operator to continue. | |||
791 | */ | |||
792 | int breaderrors = 0; | |||
793 | #define BREADEMAX32 32 | |||
794 | ||||
795 | void | |||
796 | bread(daddr_t blkno, char *buf, int size) | |||
797 | { | |||
798 | static char *mybuf = NULL((void *)0); | |||
799 | char *mybufp, *bufp, *np; | |||
800 | static size_t mybufsz = 0; | |||
801 | off_t offset; | |||
802 | int cnt, i; | |||
803 | u_int64_t secno, seccount; | |||
804 | u_int32_t secoff, secsize = lab.d_secsize; | |||
805 | ||||
806 | /* | |||
807 | * We must read an integral number of sectors large enough to contain | |||
808 | * all the requested data. The read must begin at a sector. | |||
809 | */ | |||
810 | if (DL_BLKOFFSET(&lab, blkno)(((blkno) % ((&lab)->d_secsize / (1 << 9))) * (1 << 9)) == 0 && size % secsize == 0) { | |||
811 | secno = DL_BLKTOSEC(&lab, blkno)((blkno) / ((&lab)->d_secsize / (1 << 9))); | |||
812 | secoff = 0; | |||
813 | seccount = size / secsize; | |||
814 | bufp = buf; | |||
815 | } else { | |||
816 | secno = DL_BLKTOSEC(&lab, blkno)((blkno) / ((&lab)->d_secsize / (1 << 9))); | |||
817 | secoff = DL_BLKOFFSET(&lab, blkno)(((blkno) % ((&lab)->d_secsize / (1 << 9))) * (1 << 9)); | |||
818 | seccount = DL_BLKTOSEC(&lab, (size + secoff) / DEV_BSIZE)(((size + secoff) / (1 << 9)) / ((&lab)->d_secsize / (1 << 9))); | |||
819 | if (seccount * secsize < (size + secoff)) | |||
820 | seccount++; | |||
821 | if (mybufsz < seccount * secsize) { | |||
822 | np = reallocarray(mybuf, seccount, secsize); | |||
823 | if (np == NULL((void *)0)) { | |||
824 | msg("No memory to read %llu %u-byte sectors", | |||
825 | seccount, secsize); | |||
826 | dumpabort(0); | |||
827 | } | |||
828 | mybufsz = seccount * secsize; | |||
829 | mybuf = np; | |||
830 | } | |||
831 | bufp = mybuf; | |||
832 | } | |||
833 | ||||
834 | offset = secno * secsize; | |||
835 | ||||
836 | loop: | |||
837 | if ((cnt = pread(diskfd, bufp, seccount * secsize, offset)) == | |||
838 | seccount * secsize) | |||
839 | goto done; | |||
840 | if (blkno + (size / DEV_BSIZE(1 << 9)) > | |||
841 | fsbtodb(sblock, sblock->fs_ffs1_size)((sblock->fs_ffs1_size) << (sblock)->fs_fsbtodb)) { | |||
842 | /* | |||
843 | * Trying to read the final fragment. | |||
844 | * | |||
845 | * NB - dump only works in TP_BSIZE blocks, hence | |||
846 | * rounds `DEV_BSIZE' fragments up to TP_BSIZE pieces. | |||
847 | * It should be smarter about not actually trying to | |||
848 | * read more than it can get, but for the time being | |||
849 | * we punt and scale back the read only when it gets | |||
850 | * us into trouble. (mkm 9/25/83) | |||
851 | */ | |||
852 | size -= secsize; | |||
853 | seccount--; | |||
854 | goto loop; | |||
855 | } | |||
856 | if (cnt == -1) | |||
857 | msg("read error from %s: %s: [block %lld]: count=%d\n", | |||
858 | disk, strerror(errno(*__errno())), (long long)blkno, size); | |||
859 | else | |||
860 | msg("short read error from %s: [block %lld]: count=%d, " | |||
861 | "got=%d\n", disk, (long long)blkno, size, cnt); | |||
862 | if (++breaderrors > BREADEMAX32) { | |||
863 | msg("More than %d block read errors from %s\n", | |||
864 | BREADEMAX32, disk); | |||
865 | broadcast("DUMP IS AILING!\n"); | |||
866 | msg("This is an unrecoverable error.\n"); | |||
867 | if (!query("Do you want to attempt to continue?")){ | |||
868 | dumpabort(0); | |||
869 | /*NOTREACHED*/ | |||
870 | } else | |||
871 | breaderrors = 0; | |||
872 | } | |||
873 | /* | |||
874 | * Zero buffer, then try to read each sector of buffer separately. | |||
875 | */ | |||
876 | if (bufp == mybuf) | |||
877 | memset(bufp, 0, mybufsz); | |||
878 | else | |||
879 | memset(bufp, 0, size); | |||
880 | for (i = 0, mybufp = bufp; i < size; i += secsize, mybufp += secsize) { | |||
881 | if ((cnt = pread(diskfd, mybufp, secsize, offset + i)) == | |||
882 | secsize) | |||
883 | continue; | |||
884 | if (cnt == -1) { | |||
885 | msg("read error from %s: %s: [block %lld]: " | |||
886 | "count=%u\n", disk, strerror(errno(*__errno())), | |||
887 | (long long)(offset + i) / DEV_BSIZE(1 << 9), secsize); | |||
888 | continue; | |||
889 | } | |||
890 | msg("short read error from %s: [block %lld]: count=%u, " | |||
891 | "got=%d\n", disk, (long long)(offset + i) / DEV_BSIZE(1 << 9), | |||
892 | secsize, cnt); | |||
893 | } | |||
894 | ||||
895 | done: | |||
896 | /* If necessary, copy out data that was read. */ | |||
897 | if (bufp
| |||
898 | memcpy(buf, bufp + secoff, size); | |||
| ||||
899 | } |