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