| File: | src/sbin/dump/traverse.c |
| Warning: | line 908, 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.39 2018/04/26 17:40:48 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 | #ifdef FS_44INODEFMT2 | |||
| 551 | (DIP(dp, di_size)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_size : ( dp)->dp2.di_size) < sblock->fs_maxsymlinklen || | |||
| 552 | (sblock->fs_maxsymlinklen == 0 && | |||
| 553 | DIP(dp, di_blocks)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_blocks : (dp)->dp2.di_blocks) == 0))) { | |||
| 554 | #else | |||
| 555 | DIP(dp, di_blocks)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_blocks : (dp)->dp2.di_blocks) == 0) { | |||
| 556 | #endif | |||
| 557 | void *shortlink; | |||
| 558 | ||||
| 559 | spclu_spcl.s_spcl.c_addr[0] = 1; | |||
| 560 | spclu_spcl.s_spcl.c_count = 1; | |||
| 561 | writeheader(ino); | |||
| 562 | if (sblock->fs_magic == FS_UFS1_MAGIC0x011954) | |||
| 563 | shortlink = dp->dp1.di_shortlinkdi_db; | |||
| 564 | else | |||
| 565 | shortlink = dp->dp2.di_shortlinkdi_db; | |||
| 566 | memcpy(buf, shortlink, DIP(dp, di_size)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_size : ( dp)->dp2.di_size)); | |||
| 567 | buf[DIP(dp, di_size)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_size : ( dp)->dp2.di_size)] = '\0'; | |||
| 568 | writerec(buf, 0); | |||
| 569 | return; | |||
| 570 | } | |||
| 571 | /* FALLTHROUGH */ | |||
| 572 | ||||
| 573 | case IFDIR0040000: | |||
| 574 | case IFREG0100000: | |||
| 575 | if (DIP(dp, di_size)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_size : ( dp)->dp2.di_size) > 0) | |||
| 576 | break; | |||
| 577 | /* FALLTHROUGH */ | |||
| 578 | ||||
| 579 | case IFIFO0010000: | |||
| 580 | case IFSOCK0140000: | |||
| 581 | case IFCHR0020000: | |||
| 582 | case IFBLK0060000: | |||
| 583 | writeheader(ino); | |||
| 584 | return; | |||
| 585 | ||||
| 586 | default: | |||
| 587 | msg("Warning: undefined file type 0%o\n", | |||
| 588 | DIP(dp, di_mode)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_mode : ( dp)->dp2.di_mode) & IFMT0170000); | |||
| 589 | return; | |||
| 590 | } | |||
| 591 | if (DIP(dp, di_size)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_size : ( dp)->dp2.di_size) > NDADDR12 * sblock->fs_bsize) | |||
| 592 | cnt = NDADDR12 * sblock->fs_frag; | |||
| 593 | else | |||
| 594 | 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)); | |||
| 595 | if (sblock->fs_magic
| |||
| 596 | ufs1_blksout(&dp->dp1.di_db[0], cnt, ino); | |||
| 597 | else | |||
| 598 | ufs2_blksout(&dp->dp2.di_db[0], cnt, ino); | |||
| 599 | if ((size = DIP(dp, di_size)((sblock->fs_magic == 0x011954) ? (dp)->dp1.di_size : ( dp)->dp2.di_size) - NDADDR12 * sblock->fs_bsize) <= 0) | |||
| 600 | return; | |||
| 601 | for (ind_level = 0; ind_level < NIADDR3; ind_level++) { | |||
| 602 | 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); | |||
| 603 | if (size <= 0) | |||
| 604 | return; | |||
| 605 | } | |||
| 606 | } | |||
| 607 | ||||
| 608 | /* | |||
| 609 | * Read indirect blocks, and pass the data blocks to be dumped. | |||
| 610 | */ | |||
| 611 | static void | |||
| 612 | dmpindir(ino_t ino, daddr_t blk, int ind_level, off_t *size) | |||
| 613 | { | |||
| 614 | int i, cnt; | |||
| 615 | char idblk[MAXBSIZE(64 * 1024)]; | |||
| 616 | ||||
| 617 | if (blk != 0) | |||
| 618 | bread(fsbtodb(sblock, blk)((blk) << (sblock)->fs_fsbtodb), idblk, (int) sblock->fs_bsize); | |||
| 619 | else | |||
| 620 | memset(idblk, 0, (int)sblock->fs_bsize); | |||
| 621 | if (ind_level <= 0) { | |||
| 622 | if (*size < NINDIR(sblock)((sblock)->fs_nindir) * sblock->fs_bsize) | |||
| 623 | cnt = howmany(*size, sblock->fs_fsize)(((*size) + ((sblock->fs_fsize) - 1)) / (sblock->fs_fsize )); | |||
| 624 | else | |||
| 625 | cnt = NINDIR(sblock)((sblock)->fs_nindir) * sblock->fs_frag; | |||
| 626 | *size -= NINDIR(sblock)((sblock)->fs_nindir) * sblock->fs_bsize; | |||
| 627 | if (sblock->fs_magic == FS_UFS1_MAGIC0x011954) | |||
| 628 | ufs1_blksout((int32_t *)idblk, cnt, ino); | |||
| 629 | else | |||
| 630 | ufs2_blksout((int64_t *)idblk, cnt, ino); | |||
| 631 | return; | |||
| 632 | } | |||
| 633 | ind_level--; | |||
| 634 | for (i = 0; i < NINDIR(sblock)((sblock)->fs_nindir); i++) { | |||
| 635 | if (sblock->fs_magic == FS_UFS1_MAGIC0x011954) | |||
| 636 | dmpindir(ino, ((int32_t *)idblk)[i], ind_level, | |||
| 637 | size); | |||
| 638 | else | |||
| 639 | dmpindir(ino, ((int64_t *)idblk)[i], ind_level, | |||
| 640 | size); | |||
| 641 | if (*size <= 0) | |||
| 642 | return; | |||
| 643 | } | |||
| 644 | } | |||
| 645 | ||||
| 646 | /* | |||
| 647 | * Collect up the data into tape record sized buffers and output them. | |||
| 648 | */ | |||
| 649 | void | |||
| 650 | ufs1_blksout(int32_t *blkp, int frags, ino_t ino) | |||
| 651 | { | |||
| 652 | int32_t *bp; | |||
| 653 | int i, j, count, blks, tbperdb; | |||
| 654 | ||||
| 655 | blks = howmany(frags * sblock->fs_fsize, TP_BSIZE)(((frags * sblock->fs_fsize) + ((1024) - 1)) / (1024)); | |||
| 656 | tbperdb = sblock->fs_bsize >> tp_bshift; | |||
| 657 | for (i = 0; i < blks; i += TP_NINDIR(1024/2)) { | |||
| 658 | if (i + TP_NINDIR(1024/2) > blks) | |||
| 659 | count = blks; | |||
| 660 | else | |||
| 661 | count = i + TP_NINDIR(1024/2); | |||
| 662 | for (j = i; j < count; j++) | |||
| 663 | if (blkp[j / tbperdb] != 0) | |||
| 664 | spclu_spcl.s_spcl.c_addr[j - i] = 1; | |||
| 665 | else | |||
| 666 | spclu_spcl.s_spcl.c_addr[j - i] = 0; | |||
| 667 | spclu_spcl.s_spcl.c_count = count - i; | |||
| 668 | writeheader(ino); | |||
| 669 | bp = &blkp[i / tbperdb]; | |||
| 670 | for (j = i; j < count; j += tbperdb, bp++) | |||
| 671 | if (*bp != 0) { | |||
| 672 | if (j + tbperdb <= count) | |||
| 673 | dumpblock(*bp, (int)sblock->fs_bsize); | |||
| 674 | else | |||
| 675 | dumpblock(*bp, (count - j) * TP_BSIZE1024); | |||
| 676 | } | |||
| 677 | spclu_spcl.s_spcl.c_type = TS_ADDR4; | |||
| 678 | } | |||
| 679 | } | |||
| 680 | ||||
| 681 | /* | |||
| 682 | * Collect up the data into tape record sized buffers and output them. | |||
| 683 | */ | |||
| 684 | void | |||
| 685 | ufs2_blksout(daddr_t *blkp, int frags, ino_t ino) | |||
| 686 | { | |||
| 687 | daddr_t *bp; | |||
| 688 | int i, j, count, blks, tbperdb; | |||
| 689 | ||||
| 690 | blks = howmany(frags * sblock->fs_fsize, TP_BSIZE)(((frags * sblock->fs_fsize) + ((1024) - 1)) / (1024)); | |||
| 691 | tbperdb = sblock->fs_bsize >> tp_bshift; | |||
| 692 | for (i = 0; i < blks; i += TP_NINDIR(1024/2)) { | |||
| 693 | if (i + TP_NINDIR(1024/2) > blks) | |||
| 694 | count = blks; | |||
| 695 | else | |||
| 696 | count = i + TP_NINDIR(1024/2); | |||
| 697 | for (j = i; j < count; j++) | |||
| 698 | if (blkp[j / tbperdb] != 0) | |||
| 699 | spclu_spcl.s_spcl.c_addr[j - i] = 1; | |||
| 700 | else | |||
| 701 | spclu_spcl.s_spcl.c_addr[j - i] = 0; | |||
| 702 | spclu_spcl.s_spcl.c_count = count - i; | |||
| 703 | writeheader(ino); | |||
| 704 | bp = &blkp[i / tbperdb]; | |||
| 705 | for (j = i; j < count; j += tbperdb, bp++) | |||
| 706 | if (*bp != 0) { | |||
| 707 | if (j + tbperdb <= count) | |||
| 708 | dumpblock(*bp, (int)sblock->fs_bsize); | |||
| 709 | else | |||
| 710 | dumpblock(*bp, (count - j) * TP_BSIZE1024); | |||
| 711 | } | |||
| 712 | spclu_spcl.s_spcl.c_type = TS_ADDR4; | |||
| 713 | } | |||
| 714 | } | |||
| 715 | ||||
| 716 | /* | |||
| 717 | * Dump a map to the tape. | |||
| 718 | */ | |||
| 719 | void | |||
| 720 | dumpmap(map, type, ino) | |||
| 721 | char *map; | |||
| 722 | int type; | |||
| 723 | ino_t ino; | |||
| 724 | { | |||
| 725 | int i; | |||
| 726 | char *cp; | |||
| 727 | ||||
| 728 | spclu_spcl.s_spcl.c_type = type; | |||
| 729 | spclu_spcl.s_spcl.c_count = howmany(mapsize * sizeof(char), TP_BSIZE)(((mapsize * sizeof(char)) + ((1024) - 1)) / (1024)); | |||
| 730 | writeheader(ino); | |||
| 731 | for (i = 0, cp = map; i < spclu_spcl.s_spcl.c_count; i++, cp += TP_BSIZE1024) | |||
| 732 | writerec(cp, 0); | |||
| 733 | } | |||
| 734 | ||||
| 735 | /* | |||
| 736 | * Write a header record to the dump tape. | |||
| 737 | */ | |||
| 738 | void | |||
| 739 | writeheader(ino) | |||
| 740 | ino_t ino; | |||
| 741 | { | |||
| 742 | int32_t sum, cnt, *lp; | |||
| 743 | ||||
| 744 | spclu_spcl.s_spcl.c_inumber = ino; | |||
| 745 | if (sblock->fs_magic == FS_UFS2_MAGIC0x19540119) { | |||
| 746 | spclu_spcl.s_spcl.c_magic = FS_UFS2_MAGIC0x19540119; | |||
| 747 | } else { | |||
| 748 | spclu_spcl.s_spcl.c_magic = NFS_MAGIC(int)60012; | |||
| 749 | spclu_spcl.s_spcl.c_old_date = (int32_t)spclu_spcl.s_spcl.c_date; | |||
| 750 | spclu_spcl.s_spcl.c_old_ddate = (int32_t)spclu_spcl.s_spcl.c_ddate; | |||
| 751 | spclu_spcl.s_spcl.c_old_tapea = (int32_t)spclu_spcl.s_spcl.c_tapea; | |||
| 752 | spclu_spcl.s_spcl.c_old_firstrec = (int32_t)spclu_spcl.s_spcl.c_firstrec; | |||
| 753 | } | |||
| 754 | spclu_spcl.s_spcl.c_checksum = 0; | |||
| 755 | lp = (int32_t *)&spclu_spcl.s_spcl; | |||
| 756 | sum = 0; | |||
| 757 | cnt = sizeof(union u_spcl) / (4 * sizeof(int32_t)); | |||
| 758 | while (--cnt >= 0) { | |||
| 759 | sum += *lp++; | |||
| 760 | sum += *lp++; | |||
| 761 | sum += *lp++; | |||
| 762 | sum += *lp++; | |||
| 763 | } | |||
| 764 | spclu_spcl.s_spcl.c_checksum = CHECKSUM(int)84446 - sum; | |||
| 765 | writerec((char *)&spclu_spcl.s_spcl, 1); | |||
| 766 | } | |||
| 767 | ||||
| 768 | union dinode * | |||
| 769 | getino(ino_t inum, int *modep) | |||
| 770 | { | |||
| 771 | static ino_t minino, maxino; | |||
| 772 | static void *inoblock; | |||
| 773 | struct ufs1_dinode *dp1; | |||
| 774 | struct ufs2_dinode *dp2; | |||
| 775 | ||||
| 776 | if (inoblock == NULL((void *)0) && (inoblock = malloc(sblock->fs_bsize)) == NULL((void *)0)) | |||
| 777 | quit("cannot allocate inode memory.\n"); | |||
| 778 | curino = inum; | |||
| 779 | if (inum >= minino && inum < maxino) | |||
| 780 | goto gotit; | |||
| 781 | 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, | |||
| 782 | (int)sblock->fs_bsize); | |||
| 783 | minino = inum - (inum % INOPB(sblock)((sblock)->fs_inopb)); | |||
| 784 | maxino = minino + INOPB(sblock)((sblock)->fs_inopb); | |||
| 785 | gotit: | |||
| 786 | if (sblock->fs_magic == FS_UFS1_MAGIC0x011954) { | |||
| 787 | dp1 = &((struct ufs1_dinode *)inoblock)[inum - minino]; | |||
| 788 | *modep = (dp1->di_mode & IFMT0170000); | |||
| 789 | return ((union dinode *)dp1); | |||
| 790 | } | |||
| 791 | dp2 = &((struct ufs2_dinode *)inoblock)[inum - minino]; | |||
| 792 | *modep = (dp2->di_mode & IFMT0170000); | |||
| 793 | return ((union dinode *)dp2); | |||
| 794 | } | |||
| 795 | ||||
| 796 | /* | |||
| 797 | * Read a chunk of data from the disk. | |||
| 798 | * Try to recover from hard errors by reading in sector sized pieces. | |||
| 799 | * Error recovery is attempted at most BREADEMAX times before seeking | |||
| 800 | * consent from the operator to continue. | |||
| 801 | */ | |||
| 802 | int breaderrors = 0; | |||
| 803 | #define BREADEMAX32 32 | |||
| 804 | ||||
| 805 | void | |||
| 806 | bread(daddr_t blkno, char *buf, int size) | |||
| 807 | { | |||
| 808 | static char *mybuf = NULL((void *)0); | |||
| 809 | char *mybufp, *bufp, *np; | |||
| 810 | static size_t mybufsz = 0; | |||
| 811 | off_t offset; | |||
| 812 | int cnt, i; | |||
| 813 | u_int64_t secno, seccount; | |||
| 814 | u_int32_t secoff, secsize = lab.d_secsize; | |||
| 815 | ||||
| 816 | /* | |||
| 817 | * We must read an integral number of sectors large enough to contain | |||
| 818 | * all the requested data. The read must begin at a sector. | |||
| 819 | */ | |||
| 820 | if (DL_BLKOFFSET(&lab, blkno)(((blkno) % ((&lab)->d_secsize / (1 << 9))) * (1 << 9)) == 0 && size % secsize == 0) { | |||
| 821 | secno = DL_BLKTOSEC(&lab, blkno)((blkno) / ((&lab)->d_secsize / (1 << 9))); | |||
| 822 | secoff = 0; | |||
| 823 | seccount = size / secsize; | |||
| 824 | bufp = buf; | |||
| 825 | } else { | |||
| 826 | secno = DL_BLKTOSEC(&lab, blkno)((blkno) / ((&lab)->d_secsize / (1 << 9))); | |||
| 827 | secoff = DL_BLKOFFSET(&lab, blkno)(((blkno) % ((&lab)->d_secsize / (1 << 9))) * (1 << 9)); | |||
| 828 | seccount = DL_BLKTOSEC(&lab, (size + secoff) / DEV_BSIZE)(((size + secoff) / (1 << 9)) / ((&lab)->d_secsize / (1 << 9))); | |||
| 829 | if (seccount * secsize < (size + secoff)) | |||
| 830 | seccount++; | |||
| 831 | if (mybufsz < seccount * secsize) { | |||
| 832 | np = reallocarray(mybuf, seccount, secsize); | |||
| 833 | if (np == NULL((void *)0)) { | |||
| 834 | msg("No memory to read %llu %u-byte sectors", | |||
| 835 | seccount, secsize); | |||
| 836 | dumpabort(0); | |||
| 837 | } | |||
| 838 | mybufsz = seccount * secsize; | |||
| 839 | mybuf = np; | |||
| 840 | } | |||
| 841 | bufp = mybuf; | |||
| 842 | } | |||
| 843 | ||||
| 844 | offset = secno * secsize; | |||
| 845 | ||||
| 846 | loop: | |||
| 847 | if ((cnt = pread(diskfd, bufp, seccount * secsize, offset)) == | |||
| 848 | seccount * secsize) | |||
| 849 | goto done; | |||
| 850 | if (blkno + (size / DEV_BSIZE(1 << 9)) > | |||
| 851 | fsbtodb(sblock, sblock->fs_ffs1_size)((sblock->fs_ffs1_size) << (sblock)->fs_fsbtodb)) { | |||
| 852 | /* | |||
| 853 | * Trying to read the final fragment. | |||
| 854 | * | |||
| 855 | * NB - dump only works in TP_BSIZE blocks, hence | |||
| 856 | * rounds `DEV_BSIZE' fragments up to TP_BSIZE pieces. | |||
| 857 | * It should be smarter about not actually trying to | |||
| 858 | * read more than it can get, but for the time being | |||
| 859 | * we punt and scale back the read only when it gets | |||
| 860 | * us into trouble. (mkm 9/25/83) | |||
| 861 | */ | |||
| 862 | size -= secsize; | |||
| 863 | seccount--; | |||
| 864 | goto loop; | |||
| 865 | } | |||
| 866 | if (cnt == -1) | |||
| 867 | msg("read error from %s: %s: [block %lld]: count=%d\n", | |||
| 868 | disk, strerror(errno(*__errno())), (long long)blkno, size); | |||
| 869 | else | |||
| 870 | msg("short read error from %s: [block %lld]: count=%d, " | |||
| 871 | "got=%d\n", disk, (long long)blkno, size, cnt); | |||
| 872 | if (++breaderrors > BREADEMAX32) { | |||
| 873 | msg("More than %d block read errors from %s\n", | |||
| 874 | BREADEMAX32, disk); | |||
| 875 | broadcast("DUMP IS AILING!\n"); | |||
| 876 | msg("This is an unrecoverable error.\n"); | |||
| 877 | if (!query("Do you want to attempt to continue?")){ | |||
| 878 | dumpabort(0); | |||
| 879 | /*NOTREACHED*/ | |||
| 880 | } else | |||
| 881 | breaderrors = 0; | |||
| 882 | } | |||
| 883 | /* | |||
| 884 | * Zero buffer, then try to read each sector of buffer separately. | |||
| 885 | */ | |||
| 886 | if (bufp == mybuf) | |||
| 887 | memset(bufp, 0, mybufsz); | |||
| 888 | else | |||
| 889 | memset(bufp, 0, size); | |||
| 890 | for (i = 0, mybufp = bufp; i < size; i += secsize, mybufp += secsize) { | |||
| 891 | if ((cnt = pread(diskfd, mybufp, secsize, offset + i)) == | |||
| 892 | secsize) | |||
| 893 | continue; | |||
| 894 | if (cnt == -1) { | |||
| 895 | msg("read error from %s: %s: [block %lld]: " | |||
| 896 | "count=%u\n", disk, strerror(errno(*__errno())), | |||
| 897 | (long long)(offset + i) / DEV_BSIZE(1 << 9), secsize); | |||
| 898 | continue; | |||
| 899 | } | |||
| 900 | msg("short read error from %s: [block %lld]: count=%u, " | |||
| 901 | "got=%d\n", disk, (long long)(offset + i) / DEV_BSIZE(1 << 9), | |||
| 902 | secsize, cnt); | |||
| 903 | } | |||
| 904 | ||||
| 905 | done: | |||
| 906 | /* If necessary, copy out data that was read. */ | |||
| 907 | if (bufp
| |||
| 908 | memcpy(buf, bufp + secoff, size); | |||
| ||||
| 909 | } |