lfs_inode.c revision 1.26
1/* $NetBSD: lfs_inode.c,v 1.26 2015/09/01 06:12:04 dholland Exp $ */ 2 3/*- 4 * Copyright (c) 1980, 1991, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33#ifndef lint 34__COPYRIGHT("@(#) Copyright (c) 1980, 1991, 1993, 1994\ 35 The Regents of the University of California. All rights reserved."); 36#endif /* not lint */ 37 38#ifndef lint 39#if 0 40static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/1/95"; 41#else 42__RCSID("$NetBSD: lfs_inode.c,v 1.26 2015/09/01 06:12:04 dholland Exp $"); 43#endif 44#endif /* not lint */ 45 46#include <sys/param.h> 47#include <sys/time.h> 48#include <sys/stat.h> 49#include <sys/mount.h> 50 51#include <ctype.h> 52#include <errno.h> 53#include <fcntl.h> 54#include <fts.h> 55#include <stdio.h> 56#include <string.h> 57#include <unistd.h> 58 59#include "dump.h" 60#undef di_inumber 61 62#define HASDUMPEDFILE 0x1 63#define HASSUBDIRS 0x2 64 65struct lfs *sblock; 66 67int is_ufs2 = 0; 68 69/* 70 * Read the superblock from disk, and check its magic number. 71 * Determine whether byte-swapping needs to be done on this filesystem. 72 */ 73int 74fs_read_sblock(char *superblock) 75{ 76 union { 77 char tbuf[LFS_SBPAD]; 78 struct lfs lfss; 79 } u; 80 81 int ns = 0; 82 off_t sboff = LFS_LABELPAD; 83 84 sblock = (struct lfs *)superblock; 85 while(1) { 86 rawread(sboff, (char *) sblock, LFS_SBPAD); 87 if (sblock->lfs_dlfs_u.u_32.dlfs_magic != LFS_MAGIC) { 88#ifdef notyet 89 if (sblock->lfs_magic == bswap32(LFS_MAGIC)) { 90 lfs_sb_swap(sblock, sblock, 0); 91 ns = 1; 92 } else 93#endif 94 quit("bad sblock magic number\n"); 95 } 96 if (lfs_fsbtob(sblock, (off_t)lfs_sb_getsboff(sblock, 0)) != sboff) { 97 sboff = lfs_fsbtob(sblock, (off_t)lfs_sb_getsboff(sblock, 0)); 98 continue; 99 } 100 break; 101 } 102 103 /* 104 * Read the secondary and take the older of the two 105 */ 106 rawread(lfs_fsbtob(sblock, (off_t)lfs_sb_getsboff(sblock, 1)), u.tbuf, 107 sizeof(u.tbuf)); 108#ifdef notyet 109 if (ns) 110 lfs_sb_swap(u.tbuf, u.tbuf, 0); 111#endif 112 if (u.lfss.lfs_dlfs_u.u_32.dlfs_magic != LFS_MAGIC) { 113 msg("Warning: secondary superblock at 0x%" PRIx64 " bad magic\n", 114 LFS_FSBTODB(sblock, (off_t)lfs_sb_getsboff(sblock, 1))); 115 } else { 116 if (lfs_sb_getversion(sblock) > 1) { 117 if (lfs_sb_getserial(&u.lfss) < lfs_sb_getserial(sblock)) { 118 memcpy(sblock, u.tbuf, sizeof(u.tbuf)); 119 sboff = lfs_fsbtob(sblock, (off_t)lfs_sb_getsboff(sblock, 1)); 120 } 121 } else { 122 if (lfs_sb_getotstamp(&u.lfss) < lfs_sb_getotstamp(sblock)) { 123 memcpy(sblock, u.tbuf, sizeof(u.tbuf)); 124 sboff = lfs_fsbtob(sblock, (off_t)lfs_sb_getsboff(sblock, 1)); 125 } 126 } 127 } 128 if (sboff != LFS_SBPAD) { 129 msg("Using superblock at alternate location 0x%lx\n", 130 (unsigned long)(btodb(sboff))); 131 } 132 133 return ns; 134} 135 136/* 137 * Fill in the ufsi struct, as well as the maxino and dev_bsize global 138 * variables. 139 */ 140struct ufsi * 141fs_parametrize(void) 142{ 143 static struct ufsi ufsi; 144 145 spcl.c_flags = iswap32(iswap32(spcl.c_flags) | DR_NEWINODEFMT); 146 147 ufsi.ufs_dsize = LFS_FSBTODB(sblock, lfs_sb_getsize(sblock)); 148 if (lfs_sb_getversion(sblock) == 1) 149 ufsi.ufs_dsize = lfs_sb_getsize(sblock) >> lfs_sb_getblktodb(sblock); 150 ufsi.ufs_bsize = lfs_sb_getbsize(sblock); 151 ufsi.ufs_bshift = lfs_sb_getbshift(sblock); 152 ufsi.ufs_fsize = lfs_sb_getfsize(sblock); 153 ufsi.ufs_frag = lfs_sb_getfrag(sblock); 154 ufsi.ufs_fsatoda = lfs_sb_getfsbtodb(sblock); 155 if (lfs_sb_getversion(sblock) == 1) 156 ufsi.ufs_fsatoda = 0; 157 ufsi.ufs_nindir = lfs_sb_getnindir(sblock); 158 ufsi.ufs_inopb = lfs_sb_getinopb(sblock); 159 ufsi.ufs_maxsymlinklen = lfs_sb_getmaxsymlinklen(sblock); 160 ufsi.ufs_bmask = ~(lfs_sb_getbmask(sblock)); 161 ufsi.ufs_qbmask = lfs_sb_getbmask(sblock); 162 ufsi.ufs_fmask = ~(lfs_sb_getffmask(sblock)); 163 ufsi.ufs_qfmask = lfs_sb_getffmask(sblock); 164 165 dev_bsize = lfs_sb_getbsize(sblock) >> lfs_sb_getblktodb(sblock); 166 167 return &ufsi; 168} 169 170ino_t 171fs_maxino(void) 172{ 173 return ((getino(LFS_IFILE_INUM)->dp1.di_size 174 - (lfs_sb_getcleansz(sblock) + lfs_sb_getsegtabsz(sblock)) 175 * lfs_sb_getbsize(sblock)) 176 / lfs_sb_getbsize(sblock)) * lfs_sb_getifpb(sblock) - 1; 177} 178 179void 180fs_mapinodes(ino_t maxino, u_int64_t *tapesz, int *anydirskipped) 181{ 182 ino_t ino; 183 184 for (ino = ULFS_ROOTINO; ino < maxino; ino++) 185 mapfileino(ino, tapesz, anydirskipped); 186} 187 188/* 189 * XXX KS - I know there's a better way to do this. 190 */ 191#define BASE_SINDIR (ULFS_NDADDR) 192#define BASE_DINDIR (ULFS_NDADDR+LFS_NINDIR(fs)) 193#define BASE_TINDIR (ULFS_NDADDR+LFS_NINDIR(fs)+LFS_NINDIR(fs)*LFS_NINDIR(fs)) 194 195#define D_UNITS (LFS_NINDIR(fs)) 196#define T_UNITS (LFS_NINDIR(fs)*LFS_NINDIR(fs)) 197 198static daddr_t 199lfs_bmap(struct lfs *fs, union lfs_dinode *idinode, daddr_t lbn) 200{ 201 daddr_t residue, up; 202 int off=0; 203 char bp[MAXBSIZE]; 204 205 up = UNASSIGNED; /* XXXGCC -Wunitialized [sh3] */ 206 207 if(lbn > 0 && lbn > lfs_lblkno(fs, lfs_dino_getsize(fs, idinode))) { 208 return UNASSIGNED; 209 } 210 /* 211 * Indirect blocks: if it is a first-level indirect, pull its 212 * address from the inode; otherwise, call ourselves to find the 213 * address of the parent indirect block, and load that to find 214 * the desired address. 215 */ 216 if(lbn < 0) { 217 lbn *= -1; 218 if (lbn == ULFS_NDADDR) { 219 /* printf("lbn %d: single indir base\n", -lbn); */ 220 return lfs_dino_getib(fs, idinode, 0); /* single indirect */ 221 } else if(lbn == BASE_DINDIR+1) { 222 /* printf("lbn %d: double indir base\n", -lbn); */ 223 return lfs_dino_getib(fs, idinode, 1); /* double indirect */ 224 } else if(lbn == BASE_TINDIR+2) { 225 /* printf("lbn %d: triple indir base\n", -lbn); */ 226 return lfs_dino_getib(fs, idinode, 2); /* triple indirect */ 227 } 228 229 /* 230 * Find the immediate parent. This is essentially finding the 231 * residue of modulus, and then rounding accordingly. 232 */ 233 residue = (lbn-ULFS_NDADDR) % LFS_NINDIR(fs); 234 if(residue == 1) { 235 /* Double indirect. Parent is the triple. */ 236 up = lfs_dino_getib(fs, idinode, 2); 237 off = (lbn-2-BASE_TINDIR)/(LFS_NINDIR(fs)*LFS_NINDIR(fs)); 238 if(up == UNASSIGNED || up == LFS_UNUSED_DADDR) 239 return UNASSIGNED; 240 /* printf("lbn %d: parent is the triple\n", -lbn); */ 241 bread(LFS_FSBTODB(sblock, up), bp, lfs_sb_getbsize(sblock)); 242 /* XXX ondisk32 */ 243 return (daddr_t)((int32_t *)bp)[off]; 244 } else /* residue == 0 */ { 245 /* Single indirect. Two cases. */ 246 if(lbn < BASE_TINDIR) { 247 /* Parent is the double, simple */ 248 up = -(BASE_DINDIR) - 1; 249 off = (lbn-BASE_DINDIR) / D_UNITS; 250 /* printf("lbn %d: parent is %d/%d\n", -lbn, up,off); */ 251 } else { 252 /* Ancestor is the triple, more complex */ 253 up = ((lbn-BASE_TINDIR) / T_UNITS) 254 * T_UNITS + BASE_TINDIR + 1; 255 off = (lbn/D_UNITS) - (up/D_UNITS); 256 up = -up; 257 /* printf("lbn %d: parent is %d/%d\n", -lbn, up,off); */ 258 } 259 } 260 } else { 261 /* Direct block. Its parent must be a single indirect. */ 262 if (lbn < ULFS_NDADDR) 263 return lfs_dino_getdb(fs, idinode, lbn); 264 else { 265 /* Parent is an indirect block. */ 266 up = -(((lbn-ULFS_NDADDR) / D_UNITS) * D_UNITS + ULFS_NDADDR); 267 off = (lbn-ULFS_NDADDR) % D_UNITS; 268 /* printf("lbn %d: parent is %d/%d\n", lbn,up,off); */ 269 } 270 } 271 up = lfs_bmap(fs,idinode,up); 272 if(up == UNASSIGNED || up == LFS_UNUSED_DADDR) 273 return UNASSIGNED; 274 bread(LFS_FSBTODB(sblock, up), bp, lfs_sb_getbsize(sblock)); 275 /* XXX ondisk32 */ 276 return (daddr_t)((int32_t *)bp)[off]; 277} 278 279static IFILE * 280lfs_ientry(ino_t ino) 281{ 282 static char ifileblock[MAXBSIZE]; 283 static daddr_t ifblkno; 284 daddr_t lbn; 285 daddr_t blkno; 286 union dinode *dp; 287 union lfs_dinode *ldp; 288 unsigned index; 289 290 lbn = ino/lfs_sb_getifpb(sblock) + lfs_sb_getcleansz(sblock) + lfs_sb_getsegtabsz(sblock); 291 dp = getino(LFS_IFILE_INUM); 292 /* XXX this is foolish */ 293 if (sblock->lfs_is64) { 294 ldp = (union lfs_dinode *)&dp->dlp64; 295 } else { 296 ldp = (union lfs_dinode *)&dp->dlp32; 297 } 298 blkno = lfs_bmap(sblock, ldp, lbn); 299 if (blkno != ifblkno) 300 bread(LFS_FSBTODB(sblock, blkno), ifileblock, 301 lfs_sb_getbsize(sblock)); 302 index = ino % lfs_sb_getifpb(sblock); 303 if (sblock->lfs_is64) { 304 return (IFILE *) &((IFILE64 *)ifileblock)[index]; 305 } else if (lfs_sb_getversion(sblock) > 1) { 306 return (IFILE *) &((IFILE32 *)ifileblock)[index]; 307 } else { 308 return (IFILE *) &((IFILE_V1 *)ifileblock)[index]; 309 } 310} 311 312/* Search a block for a specific dinode. */ 313static union lfs_dinode * 314lfs_ifind(struct lfs *fs, ino_t ino, void *block) 315{ 316 union lfs_dinode *dip; 317 unsigned i, num; 318 319 num = LFS_INOPB(fs); 320 for (i = num; i-- > 0; ) { 321 dip = DINO_IN_BLOCK(fs, block, i); 322 if (lfs_dino_getinumber(fs, dip) == ino) 323 return dip; 324 } 325 return NULL; 326} 327 328union dinode * 329getino(ino_t inum) 330{ 331 static daddr_t inoblkno; 332 daddr_t blkno; 333 static union { 334 char space[MAXBSIZE]; 335 struct lfs64_dinode u_64[MAXBSIZE/sizeof(struct lfs64_dinode)]; 336 struct lfs32_dinode u_32[MAXBSIZE/sizeof(struct lfs32_dinode)]; 337 } inoblock; 338 static union dinode ifile_dinode; /* XXX fill this in */ 339 static union dinode empty_dinode; /* Always stays zeroed */ 340 union lfs_dinode *dp; 341 ino_t inum2; 342 343 if (inum == LFS_IFILE_INUM) { 344 /* Load the ifile inode if not already */ 345 inum2 = sblock->lfs_is64 ? 346 ifile_dinode.dlp64.di_inumber : 347 ifile_dinode.dlp32.di_inumber; 348 if (inum2 == 0) { 349 blkno = lfs_sb_getidaddr(sblock); 350 bread(LFS_FSBTODB(sblock, blkno), inoblock.space, 351 (int)lfs_sb_getbsize(sblock)); 352 dp = lfs_ifind(sblock, inum, inoblock.space); 353 /* Structure copy */ 354 if (sblock->lfs_is64) { 355 ifile_dinode.dlp64 = dp->u_64; 356 } else { 357 ifile_dinode.dlp32 = dp->u_32; 358 } 359 } 360 return &ifile_dinode; 361 } 362 363 curino = inum; 364 blkno = lfs_if_getdaddr(sblock, lfs_ientry(inum)); 365 if(blkno == LFS_UNUSED_DADDR) 366 return &empty_dinode; 367 368 if(blkno != inoblkno) { 369 bread(LFS_FSBTODB(sblock, blkno), inoblock.space, 370 (int)lfs_sb_getbsize(sblock)); 371 } 372 return (void *)lfs_ifind(sblock, inum, inoblock.space); 373} 374 375/* 376 * Tell the filesystem not to overwrite any currently dirty segments 377 * until we are finished. (It may still write into clean segments, of course, 378 * since we're not using those.) This is only called when dump_lfs is called 379 * with -X, i.e. we are working on a mounted filesystem. 380 */ 381static int root_fd = -1; 382char *wrap_mpname; 383 384int 385lfs_wrap_stop(char *mpname) 386{ 387 int waitfor = 0; 388 389 root_fd = open(mpname, O_RDONLY, 0); 390 if (root_fd < 0) 391 return -1; 392 wrap_mpname = mpname; 393 fcntl(root_fd, LFCNREWIND, -1); /* Ignore return value */ 394 if (fcntl(root_fd, LFCNWRAPSTOP, &waitfor) < 0) { 395 perror("LFCNWRAPSTOP"); 396 return -1; 397 } 398 msg("Disabled log wrap on %s\n", mpname); 399 return 0; 400} 401 402/* 403 * Allow the filesystem to continue normal operation. 404 * This would happen anyway when we exit; we do it explicitly here 405 * to show the message, for the user's benefit. 406 */ 407void 408lfs_wrap_go(void) 409{ 410 int waitfor = 0; 411 412 if (root_fd < 0) 413 return; 414 415 fcntl(root_fd, LFCNWRAPGO, &waitfor); 416 close(root_fd); 417 root_fd = -1; 418 msg("Re-enabled log wrap on %s\n", wrap_mpname); 419} 420