lfs_inode.c revision 1.20
1/* $NetBSD: lfs_inode.c,v 1.20 2015/07/24 06:56:41 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.20 2015/07/24 06:56:41 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 MAXIFPB (MAXBSIZE / sizeof(IFILE)) 63 64#define HASDUMPEDFILE 0x1 65#define HASSUBDIRS 0x2 66 67struct lfs *sblock; 68 69int is_ufs2 = 0; 70 71/* 72 * Read the superblock from disk, and check its magic number. 73 * Determine whether byte-swapping needs to be done on this filesystem. 74 */ 75int 76fs_read_sblock(char *superblock) 77{ 78 union { 79 char tbuf[LFS_SBPAD]; 80 struct lfs lfss; 81 } u; 82 83 int ns = 0; 84 off_t sboff = LFS_LABELPAD; 85 86 sblock = (struct lfs *)superblock; 87 while(1) { 88 rawread(sboff, (char *) sblock, LFS_SBPAD); 89 if (sblock->lfs_magic != LFS_MAGIC) { 90#ifdef notyet 91 if (sblock->lfs_magic == bswap32(LFS_MAGIC)) { 92 lfs_sb_swap(sblock, sblock, 0); 93 ns = 1; 94 } else 95#endif 96 quit("bad sblock magic number\n"); 97 } 98 if (lfs_fsbtob(sblock, (off_t)sblock->lfs_sboffs[0]) != sboff) { 99 sboff = lfs_fsbtob(sblock, (off_t)sblock->lfs_sboffs[0]); 100 continue; 101 } 102 break; 103 } 104 105 /* 106 * Read the secondary and take the older of the two 107 */ 108 rawread(lfs_fsbtob(sblock, (off_t)sblock->lfs_sboffs[1]), u.tbuf, 109 sizeof(u.tbuf)); 110#ifdef notyet 111 if (ns) 112 lfs_sb_swap(u.tbuf, u.tbuf, 0); 113#endif 114 if (u.lfss.lfs_magic != LFS_MAGIC) { 115 msg("Warning: secondary superblock at 0x%" PRIx64 " bad magic\n", 116 LFS_FSBTODB(sblock, (off_t)sblock->lfs_sboffs[1])); 117 } else { 118 if (sblock->lfs_version > 1) { 119 if (lfs_sb_getserial(&u.lfss) < lfs_sb_getserial(sblock)) { 120 memcpy(sblock, u.tbuf, sizeof(u.tbuf)); 121 sboff = lfs_fsbtob(sblock, (off_t)sblock->lfs_sboffs[1]); 122 } 123 } else { 124 if (lfs_sb_getotstamp(&u.lfss) < lfs_sb_getotstamp(sblock)) { 125 memcpy(sblock, u.tbuf, sizeof(u.tbuf)); 126 sboff = lfs_fsbtob(sblock, (off_t)sblock->lfs_sboffs[1]); 127 } 128 } 129 } 130 if (sboff != LFS_SBPAD) { 131 msg("Using superblock at alternate location 0x%lx\n", 132 (unsigned long)(btodb(sboff))); 133 } 134 135 return ns; 136} 137 138/* 139 * Fill in the ufsi struct, as well as the maxino and dev_bsize global 140 * variables. 141 */ 142struct ufsi * 143fs_parametrize(void) 144{ 145 static struct ufsi ufsi; 146 147 spcl.c_flags = iswap32(iswap32(spcl.c_flags) | DR_NEWINODEFMT); 148 149 ufsi.ufs_dsize = LFS_FSBTODB(sblock, lfs_sb_getsize(sblock)); 150 if (sblock->lfs_version == 1) 151 ufsi.ufs_dsize = lfs_sb_getsize(sblock) >> sblock->lfs_blktodb; 152 ufsi.ufs_bsize = lfs_sb_getbsize(sblock); 153 ufsi.ufs_bshift = sblock->lfs_bshift; 154 ufsi.ufs_fsize = lfs_sb_getfsize(sblock); 155 ufsi.ufs_frag = lfs_sb_getfrag(sblock); 156 ufsi.ufs_fsatoda = sblock->lfs_fsbtodb; 157 if (sblock->lfs_version == 1) 158 ufsi.ufs_fsatoda = 0; 159 ufsi.ufs_nindir = sblock->lfs_nindir; 160 ufsi.ufs_inopb = sblock->lfs_inopb; 161 ufsi.ufs_maxsymlinklen = sblock->lfs_maxsymlinklen; 162 ufsi.ufs_bmask = ~(sblock->lfs_bmask); 163 ufsi.ufs_qbmask = sblock->lfs_bmask; 164 ufsi.ufs_fmask = ~(sblock->lfs_ffmask); 165 ufsi.ufs_qfmask = sblock->lfs_ffmask; 166 167 dev_bsize = lfs_sb_getbsize(sblock) >> sblock->lfs_blktodb; 168 169 return &ufsi; 170} 171 172ino_t 173fs_maxino(void) 174{ 175 return ((getino(lfs_sb_getifile(sblock))->dp1.di_size 176 - (lfs_sb_getcleansz(sblock) + lfs_sb_getsegtabsz(sblock)) 177 * lfs_sb_getbsize(sblock)) 178 / lfs_sb_getbsize(sblock)) * lfs_sb_getifpb(sblock) - 1; 179} 180 181void 182fs_mapinodes(ino_t maxino, u_int64_t *tapesz, int *anydirskipped) 183{ 184 ino_t ino; 185 186 for (ino = ULFS_ROOTINO; ino < maxino; ino++) 187 mapfileino(ino, tapesz, anydirskipped); 188} 189 190/* 191 * XXX KS - I know there's a better way to do this. 192 */ 193#define BASE_SINDIR (ULFS_NDADDR) 194#define BASE_DINDIR (ULFS_NDADDR+LFS_NINDIR(fs)) 195#define BASE_TINDIR (ULFS_NDADDR+LFS_NINDIR(fs)+LFS_NINDIR(fs)*LFS_NINDIR(fs)) 196 197#define D_UNITS (LFS_NINDIR(fs)) 198#define T_UNITS (LFS_NINDIR(fs)*LFS_NINDIR(fs)) 199 200static daddr_t 201lfs_bmap(struct lfs *fs, struct ulfs1_dinode *idinode, daddr_t lbn) 202{ 203 daddr_t residue, up; 204 int off=0; 205 char bp[MAXBSIZE]; 206 207 up = UNASSIGNED; /* XXXGCC -Wunitialized [sh3] */ 208 209 if(lbn > 0 && lbn > lfs_lblkno(fs, idinode->di_size)) { 210 return UNASSIGNED; 211 } 212 /* 213 * Indirect blocks: if it is a first-level indirect, pull its 214 * address from the inode; otherwise, call ourselves to find the 215 * address of the parent indirect block, and load that to find 216 * the desired address. 217 */ 218 if(lbn < 0) { 219 lbn *= -1; 220 if (lbn == ULFS_NDADDR) { 221 /* printf("lbn %d: single indir base\n", -lbn); */ 222 return idinode->di_ib[0]; /* single indirect */ 223 } else if(lbn == BASE_DINDIR+1) { 224 /* printf("lbn %d: double indir base\n", -lbn); */ 225 return idinode->di_ib[1]; /* double indirect */ 226 } else if(lbn == BASE_TINDIR+2) { 227 /* printf("lbn %d: triple indir base\n", -lbn); */ 228 return idinode->di_ib[2]; /* triple indirect */ 229 } 230 231 /* 232 * Find the immediate parent. This is essentially finding the 233 * residue of modulus, and then rounding accordingly. 234 */ 235 residue = (lbn-ULFS_NDADDR) % LFS_NINDIR(fs); 236 if(residue == 1) { 237 /* Double indirect. Parent is the triple. */ 238 up = idinode->di_ib[2]; 239 off = (lbn-2-BASE_TINDIR)/(LFS_NINDIR(fs)*LFS_NINDIR(fs)); 240 if(up == UNASSIGNED || up == LFS_UNUSED_DADDR) 241 return UNASSIGNED; 242 /* printf("lbn %d: parent is the triple\n", -lbn); */ 243 bread(LFS_FSBTODB(sblock, up), bp, lfs_sb_getbsize(sblock)); 244 /* XXX ondisk32 */ 245 return (daddr_t)((int32_t *)bp)[off]; 246 } else /* residue == 0 */ { 247 /* Single indirect. Two cases. */ 248 if(lbn < BASE_TINDIR) { 249 /* Parent is the double, simple */ 250 up = -(BASE_DINDIR) - 1; 251 off = (lbn-BASE_DINDIR) / D_UNITS; 252 /* printf("lbn %d: parent is %d/%d\n", -lbn, up,off); */ 253 } else { 254 /* Ancestor is the triple, more complex */ 255 up = ((lbn-BASE_TINDIR) / T_UNITS) 256 * T_UNITS + BASE_TINDIR + 1; 257 off = (lbn/D_UNITS) - (up/D_UNITS); 258 up = -up; 259 /* printf("lbn %d: parent is %d/%d\n", -lbn, up,off); */ 260 } 261 } 262 } else { 263 /* Direct block. Its parent must be a single indirect. */ 264 if (lbn < ULFS_NDADDR) 265 return idinode->di_db[lbn]; 266 else { 267 /* Parent is an indirect block. */ 268 up = -(((lbn-ULFS_NDADDR) / D_UNITS) * D_UNITS + ULFS_NDADDR); 269 off = (lbn-ULFS_NDADDR) % D_UNITS; 270 /* printf("lbn %d: parent is %d/%d\n", lbn,up,off); */ 271 } 272 } 273 up = lfs_bmap(fs,idinode,up); 274 if(up == UNASSIGNED || up == LFS_UNUSED_DADDR) 275 return UNASSIGNED; 276 bread(LFS_FSBTODB(sblock, up), bp, lfs_sb_getbsize(sblock)); 277 /* XXX ondisk32 */ 278 return (daddr_t)((int32_t *)bp)[off]; 279} 280 281static struct ifile * 282lfs_ientry(ino_t ino) 283{ 284 static struct ifile ifileblock[MAXIFPB]; 285 static daddr_t ifblkno; 286 daddr_t lbn; 287 daddr_t blkno; 288 union dinode *dp; 289 struct ulfs1_dinode *ldp; 290 291 lbn = ino/lfs_sb_getifpb(sblock) + lfs_sb_getcleansz(sblock) + lfs_sb_getsegtabsz(sblock); 292 dp = getino(lfs_sb_getifile(sblock)); 293 /* XXX XXX this is horribly unsafe */ 294 ldp = (struct ulfs1_dinode *)dp; 295 blkno = lfs_bmap(sblock, ldp ,lbn); 296 if (blkno != ifblkno) 297 bread(LFS_FSBTODB(sblock, blkno), (char *)ifileblock, 298 lfs_sb_getbsize(sblock)); 299 return ifileblock + (ino % lfs_sb_getifpb(sblock)); 300} 301 302/* Search a block for a specific dinode. */ 303static struct ulfs1_dinode * 304lfs_ifind(struct lfs *fs, ino_t ino, struct ulfs1_dinode *dip) 305{ 306 int cnt; 307 308 for (cnt = 0; cnt < LFS_INOPB(fs); cnt++) 309 if(dip[cnt].di_inumber == ino) 310 return &(dip[cnt]); 311 return NULL; 312} 313 314union dinode * 315getino(ino_t inum) 316{ 317 static daddr_t inoblkno; 318 daddr_t blkno; 319 static struct ulfs1_dinode inoblock[MAXBSIZE / sizeof (struct ulfs1_dinode)]; 320 static union dinode ifile_dinode; /* XXX fill this in */ 321 static union dinode empty_dinode; /* Always stays zeroed */ 322 struct ulfs1_dinode *dp; 323 324 if(inum == lfs_sb_getifile(sblock)) { 325 /* Load the ifile inode if not already */ 326 if(ifile_dinode.dlp1.di_inumber == 0) { 327 blkno = lfs_sb_getidaddr(sblock); 328 bread(LFS_FSBTODB(sblock, blkno), (char *)inoblock, 329 (int)lfs_sb_getbsize(sblock)); 330 dp = lfs_ifind(sblock, inum, inoblock); 331 ifile_dinode.dlp1 = *dp; /* Structure copy */ 332 } 333 return &ifile_dinode; 334 } 335 336 curino = inum; 337 blkno = lfs_ientry(inum)->if_daddr; 338 if(blkno == LFS_UNUSED_DADDR) 339 return &empty_dinode; 340 341 if(blkno != inoblkno) { 342 bread(LFS_FSBTODB(sblock, blkno), (char *)inoblock, 343 (int)lfs_sb_getbsize(sblock)); 344#ifdef notyet 345 if (needswap) 346 for (i = 0; i < MAXINOPB; i++) 347 ffs_dinode_swap(&inoblock[i], &inoblock[i]); 348#endif 349 } 350 return (void *)lfs_ifind(sblock, inum, inoblock); 351} 352 353/* 354 * Tell the filesystem not to overwrite any currently dirty segments 355 * until we are finished. (It may still write into clean segments, of course, 356 * since we're not using those.) This is only called when dump_lfs is called 357 * with -X, i.e. we are working on a mounted filesystem. 358 */ 359static int root_fd = -1; 360char *wrap_mpname; 361 362int 363lfs_wrap_stop(char *mpname) 364{ 365 int waitfor = 0; 366 367 root_fd = open(mpname, O_RDONLY, 0); 368 if (root_fd < 0) 369 return -1; 370 wrap_mpname = mpname; 371 fcntl(root_fd, LFCNREWIND, -1); /* Ignore return value */ 372 if (fcntl(root_fd, LFCNWRAPSTOP, &waitfor) < 0) { 373 perror("LFCNWRAPSTOP"); 374 return -1; 375 } 376 msg("Disabled log wrap on %s\n", mpname); 377 return 0; 378} 379 380/* 381 * Allow the filesystem to continue normal operation. 382 * This would happen anyway when we exit; we do it explicitly here 383 * to show the message, for the user's benefit. 384 */ 385void 386lfs_wrap_go(void) 387{ 388 int waitfor = 0; 389 390 if (root_fd < 0) 391 return; 392 393 fcntl(root_fd, LFCNWRAPGO, &waitfor); 394 close(root_fd); 395 root_fd = -1; 396 msg("Re-enabled log wrap on %s\n", wrap_mpname); 397} 398