1*251f7f59Sperry /* $NetBSD: inode.c,v 1.25 2005/02/06 06:13:12 perry Exp $ */ 25aaab72dSperseant 35aaab72dSperseant /*- 45aaab72dSperseant * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. 55aaab72dSperseant * All rights reserved. 65aaab72dSperseant * 75aaab72dSperseant * This code is derived from software contributed to The NetBSD Foundation 85aaab72dSperseant * by Konrad E. Schroder <perseant@hhhh.org>. 95aaab72dSperseant * 105aaab72dSperseant * Redistribution and use in source and binary forms, with or without 115aaab72dSperseant * modification, are permitted provided that the following conditions 125aaab72dSperseant * are met: 135aaab72dSperseant * 1. Redistributions of source code must retain the above copyright 145aaab72dSperseant * notice, this list of conditions and the following disclaimer. 155aaab72dSperseant * 2. Redistributions in binary form must reproduce the above copyright 165aaab72dSperseant * notice, this list of conditions and the following disclaimer in the 175aaab72dSperseant * documentation and/or other materials provided with the distribution. 185aaab72dSperseant * 3. All advertising materials mentioning features or use of this software 195aaab72dSperseant * must display the following acknowledgement: 205aaab72dSperseant * This product includes software developed by the NetBSD 215aaab72dSperseant * Foundation, Inc. and its contributors. 225aaab72dSperseant * 4. Neither the name of The NetBSD Foundation nor the names of its 235aaab72dSperseant * contributors may be used to endorse or promote products derived 245aaab72dSperseant * from this software without specific prior written permission. 255aaab72dSperseant * 265aaab72dSperseant * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 275aaab72dSperseant * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 285aaab72dSperseant * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 295aaab72dSperseant * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 305aaab72dSperseant * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 315aaab72dSperseant * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 325aaab72dSperseant * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 335aaab72dSperseant * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 345aaab72dSperseant * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 355aaab72dSperseant * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 365aaab72dSperseant * POSSIBILITY OF SUCH DAMAGE. 375aaab72dSperseant */ 38276d62f6Sagc 39276d62f6Sagc /* 40276d62f6Sagc * Copyright (c) 1980, 1986, 1993 41276d62f6Sagc * The Regents of the University of California. All rights reserved. 42276d62f6Sagc * 43276d62f6Sagc * Redistribution and use in source and binary forms, with or without 44276d62f6Sagc * modification, are permitted provided that the following conditions 45276d62f6Sagc * are met: 46276d62f6Sagc * 1. Redistributions of source code must retain the above copyright 47276d62f6Sagc * notice, this list of conditions and the following disclaimer. 48276d62f6Sagc * 2. Redistributions in binary form must reproduce the above copyright 49276d62f6Sagc * notice, this list of conditions and the following disclaimer in the 50276d62f6Sagc * documentation and/or other materials provided with the distribution. 51276d62f6Sagc * 3. Neither the name of the University nor the names of its contributors 52276d62f6Sagc * may be used to endorse or promote products derived from this software 53276d62f6Sagc * without specific prior written permission. 54276d62f6Sagc * 55276d62f6Sagc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 56276d62f6Sagc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 57276d62f6Sagc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 58276d62f6Sagc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 59276d62f6Sagc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 60276d62f6Sagc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 61276d62f6Sagc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 62276d62f6Sagc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 63276d62f6Sagc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 64276d62f6Sagc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 65276d62f6Sagc * SUCH DAMAGE. 66276d62f6Sagc */ 67369e9cadSperseant 68ba10361aSperseant #include <sys/types.h> 69369e9cadSperseant #include <sys/param.h> 70369e9cadSperseant #include <sys/time.h> 71ba10361aSperseant #include <sys/buf.h> 72ba10361aSperseant #include <sys/mount.h> 73ba10361aSperseant 74ba10361aSperseant #include <ufs/ufs/inode.h> 75369e9cadSperseant #include <ufs/ufs/dir.h> 76ba10361aSperseant #define vnode uvnode 77369e9cadSperseant #include <ufs/lfs/lfs.h> 78ba10361aSperseant #undef vnode 79ba10361aSperseant 80ba10361aSperseant #include <err.h> 81369e9cadSperseant #ifndef SMALL 82369e9cadSperseant #include <pwd.h> 83369e9cadSperseant #endif 84369e9cadSperseant #include <stdio.h> 85369e9cadSperseant #include <stdlib.h> 86369e9cadSperseant #include <string.h> 87369e9cadSperseant 88ba10361aSperseant #include "bufcache.h" 89ba10361aSperseant #include "vnode.h" 90ba10361aSperseant #include "lfs.h" 91ba10361aSperseant 92369e9cadSperseant #include "fsck.h" 93369e9cadSperseant #include "fsutil.h" 94369e9cadSperseant #include "extern.h" 95369e9cadSperseant 96369e9cadSperseant extern SEGUSE *seg_table; 97ba10361aSperseant extern ufs_daddr_t *din_table; 98369e9cadSperseant 991d259671Sperseant static int iblock(struct inodesc *, long, u_int64_t); 100369e9cadSperseant int blksreqd(struct lfs *, int); 101369e9cadSperseant int lfs_maxino(void); 102369e9cadSperseant 103ba10361aSperseant /* 104ba10361aSperseant * Get a dinode of a given inum. 105ba10361aSperseant * XXX combine this function with vget. 106ba10361aSperseant */ 10742614ed3Sfvdl struct ufs1_dinode * 108ba10361aSperseant ginode(ino_t ino) 109369e9cadSperseant { 110ba10361aSperseant struct uvnode *vp; 111ba10361aSperseant struct ubuf *bp; 1124e3fced9Sperseant IFILE *ifp; 113369e9cadSperseant 114ba10361aSperseant vp = vget(fs, ino); 115ba10361aSperseant if (vp == NULL) 116e6c70652Sperseant return NULL; 117e6c70652Sperseant 118ba10361aSperseant if (din_table[ino] == 0x0) { 119ba10361aSperseant LFS_IENTRY(ifp, fs, ino, bp); 120ba10361aSperseant din_table[ino] = ifp->if_daddr; 12142614ed3Sfvdl seg_table[dtosn(fs, ifp->if_daddr)].su_nbytes += DINODE1_SIZE; 122ba10361aSperseant brelse(bp); 123e6c70652Sperseant } 12442614ed3Sfvdl return (VTOI(vp)->i_din.ffs1_din); 125369e9cadSperseant } 126369e9cadSperseant 127369e9cadSperseant /* 128ba10361aSperseant * Check validity of held blocks in an inode, recursing through all blocks. 129369e9cadSperseant */ 130369e9cadSperseant int 13142614ed3Sfvdl ckinode(struct ufs1_dinode *dp, struct inodesc *idesc) 132369e9cadSperseant { 133ba10361aSperseant ufs_daddr_t *ap, lbn; 134369e9cadSperseant long ret, n, ndb, offset; 13542614ed3Sfvdl struct ufs1_dinode dino; 136369e9cadSperseant u_int64_t remsize, sizepb; 137369e9cadSperseant mode_t mode; 138369e9cadSperseant char pathbuf[MAXPATHLEN + 1]; 139ba10361aSperseant struct uvnode *vp, *thisvp; 140369e9cadSperseant 141369e9cadSperseant if (idesc->id_fix != IGNORE) 142369e9cadSperseant idesc->id_fix = DONTKNOW; 143369e9cadSperseant idesc->id_entryno = 0; 144369e9cadSperseant idesc->id_filesize = dp->di_size; 145369e9cadSperseant mode = dp->di_mode & IFMT; 1461d259671Sperseant if (mode == IFBLK || mode == IFCHR || 147ba10361aSperseant (mode == IFLNK && (dp->di_size < fs->lfs_maxsymlinklen || 148ba10361aSperseant (fs->lfs_maxsymlinklen == 0 && 1491d259671Sperseant dp->di_blocks == 0)))) 150369e9cadSperseant return (KEEPON); 151369e9cadSperseant dino = *dp; 152ba10361aSperseant ndb = howmany(dino.di_size, fs->lfs_bsize); 153369e9cadSperseant 154884f970fSyamt thisvp = vget(fs, idesc->id_number); 155ba10361aSperseant for (lbn = 0; lbn < NDADDR; lbn++) { 156ba10361aSperseant ap = dino.di_db + lbn; 157ba10361aSperseant if (thisvp) 158369e9cadSperseant idesc->id_numfrags = 159ba10361aSperseant numfrags(fs, VTOI(thisvp)->i_lfs_fragsize[lbn]); 160ba10361aSperseant else { 161ba10361aSperseant if (--ndb == 0 && (offset = blkoff(fs, dino.di_size)) != 0) { 162ba10361aSperseant idesc->id_numfrags = 163ba10361aSperseant numfrags(fs, fragroundup(fs, offset)); 164369e9cadSperseant } else 165ba10361aSperseant idesc->id_numfrags = fs->lfs_frag; 166ba10361aSperseant } 167369e9cadSperseant if (*ap == 0) { 168369e9cadSperseant if (idesc->id_type == DATA && ndb >= 0) { 169369e9cadSperseant /* An empty block in a directory XXX */ 1708883e1fbSitojun getpathname(pathbuf, sizeof(pathbuf), 1718883e1fbSitojun idesc->id_number, idesc->id_number); 172369e9cadSperseant pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 173369e9cadSperseant pathbuf); 174369e9cadSperseant if (reply("ADJUST LENGTH") == 1) { 175ba10361aSperseant vp = vget(fs, idesc->id_number); 176ba10361aSperseant dp = VTOD(vp); 177369e9cadSperseant dp->di_size = (ap - &dino.di_db[0]) * 178ba10361aSperseant fs->lfs_bsize; 179369e9cadSperseant printf( 180369e9cadSperseant "YOU MUST RERUN FSCK AFTERWARDS\n"); 181369e9cadSperseant rerun = 1; 182ba10361aSperseant inodirty(VTOI(vp)); 183369e9cadSperseant } 184369e9cadSperseant } 185369e9cadSperseant continue; 186369e9cadSperseant } 187369e9cadSperseant idesc->id_blkno = *ap; 188369e9cadSperseant idesc->id_lblkno = ap - &dino.di_db[0]; 189369e9cadSperseant if (idesc->id_type == ADDR) { 190369e9cadSperseant ret = (*idesc->id_func) (idesc); 1911d259671Sperseant } else 192369e9cadSperseant ret = dirscan(idesc); 193369e9cadSperseant if (ret & STOP) 194369e9cadSperseant return (ret); 195369e9cadSperseant } 196ba10361aSperseant idesc->id_numfrags = fs->lfs_frag; 197ba10361aSperseant remsize = dino.di_size - fs->lfs_bsize * NDADDR; 198ba10361aSperseant sizepb = fs->lfs_bsize; 199369e9cadSperseant for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) { 200369e9cadSperseant if (*ap) { 201369e9cadSperseant idesc->id_blkno = *ap; 202369e9cadSperseant ret = iblock(idesc, n, remsize); 203369e9cadSperseant if (ret & STOP) 204369e9cadSperseant return (ret); 205369e9cadSperseant } else { 206369e9cadSperseant if (idesc->id_type == DATA && remsize > 0) { 207369e9cadSperseant /* An empty block in a directory XXX */ 2088883e1fbSitojun getpathname(pathbuf, sizeof(pathbuf), 2098883e1fbSitojun idesc->id_number, idesc->id_number); 210369e9cadSperseant pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 211369e9cadSperseant pathbuf); 212369e9cadSperseant if (reply("ADJUST LENGTH") == 1) { 213ba10361aSperseant vp = vget(fs, idesc->id_number); 214ba10361aSperseant dp = VTOD(vp); 215369e9cadSperseant dp->di_size -= remsize; 216369e9cadSperseant remsize = 0; 217369e9cadSperseant printf( 218369e9cadSperseant "YOU MUST RERUN FSCK AFTERWARDS\n"); 219369e9cadSperseant rerun = 1; 220ba10361aSperseant inodirty(VTOI(vp)); 221369e9cadSperseant break; 222369e9cadSperseant } 223369e9cadSperseant } 224369e9cadSperseant } 225ba10361aSperseant sizepb *= NINDIR(fs); 226369e9cadSperseant remsize -= sizepb; 227369e9cadSperseant } 228369e9cadSperseant return (KEEPON); 229369e9cadSperseant } 230369e9cadSperseant 231369e9cadSperseant static int 2321d259671Sperseant iblock(struct inodesc *idesc, long ilevel, u_int64_t isize) 233369e9cadSperseant { 234ba10361aSperseant ufs_daddr_t *ap, *aplim; 235ba10361aSperseant struct ubuf *bp; 2361d259671Sperseant int i, n, (*func) (struct inodesc *), nif; 237369e9cadSperseant u_int64_t sizepb; 238369e9cadSperseant char pathbuf[MAXPATHLEN + 1], buf[BUFSIZ]; 239ba10361aSperseant struct uvnode *devvp, *vp; 240ba10361aSperseant int diddirty = 0; 241369e9cadSperseant 242369e9cadSperseant if (idesc->id_type == ADDR) { 243369e9cadSperseant func = idesc->id_func; 244369e9cadSperseant n = (*func) (idesc); 245369e9cadSperseant if ((n & KEEPON) == 0) 246369e9cadSperseant return (n); 247369e9cadSperseant } else 248369e9cadSperseant func = dirscan; 249ba10361aSperseant if (chkrange(idesc->id_blkno, fragstofsb(fs, idesc->id_numfrags))) 250369e9cadSperseant return (SKIP); 251ba10361aSperseant 252ba10361aSperseant devvp = fs->lfs_unlockvp; 253ba10361aSperseant bread(devvp, fsbtodb(fs, idesc->id_blkno), fs->lfs_bsize, NOCRED, &bp); 254369e9cadSperseant ilevel--; 255ba10361aSperseant for (sizepb = fs->lfs_bsize, i = 0; i < ilevel; i++) 256ba10361aSperseant sizepb *= NINDIR(fs); 257ba10361aSperseant if (isize > sizepb * NINDIR(fs)) 258ba10361aSperseant nif = NINDIR(fs); 259369e9cadSperseant else 260369e9cadSperseant nif = howmany(isize, sizepb); 261ba10361aSperseant if (idesc->id_func == pass1check && nif < NINDIR(fs)) { 262ba10361aSperseant aplim = ((ufs_daddr_t *) bp->b_data) + NINDIR(fs); 263ba10361aSperseant for (ap = ((ufs_daddr_t *) bp->b_data) + nif; ap < aplim; ap++) { 264369e9cadSperseant if (*ap == 0) 265369e9cadSperseant continue; 266369e9cadSperseant (void) sprintf(buf, "PARTIALLY TRUNCATED INODE I=%u", 267369e9cadSperseant idesc->id_number); 268369e9cadSperseant if (dofix(idesc, buf)) { 269369e9cadSperseant *ap = 0; 270ba10361aSperseant ++diddirty; 271369e9cadSperseant } 272369e9cadSperseant } 273369e9cadSperseant } 274ba10361aSperseant aplim = ((ufs_daddr_t *) bp->b_data) + nif; 275ba10361aSperseant for (ap = ((ufs_daddr_t *) bp->b_data); ap < aplim; ap++) { 276369e9cadSperseant if (*ap) { 277369e9cadSperseant idesc->id_blkno = *ap; 2786e547a61Syamt if (ilevel == 0) { 2796e547a61Syamt /* 2806e547a61Syamt * dirscan needs lblkno. 2816e547a61Syamt */ 2826e547a61Syamt idesc->id_lblkno++; 283369e9cadSperseant n = (*func) (idesc); 2846e547a61Syamt } else { 285369e9cadSperseant n = iblock(idesc, ilevel, isize); 2866e547a61Syamt } 287369e9cadSperseant if (n & STOP) { 288ba10361aSperseant if (diddirty) 289ba10361aSperseant VOP_BWRITE(bp); 290ba10361aSperseant else 291ba10361aSperseant brelse(bp); 292369e9cadSperseant return (n); 293369e9cadSperseant } 294369e9cadSperseant } else { 295369e9cadSperseant if (idesc->id_type == DATA && isize > 0) { 296369e9cadSperseant /* An empty block in a directory XXX */ 2978883e1fbSitojun getpathname(pathbuf, sizeof(pathbuf), 2988883e1fbSitojun idesc->id_number, idesc->id_number); 299369e9cadSperseant pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 300369e9cadSperseant pathbuf); 301369e9cadSperseant if (reply("ADJUST LENGTH") == 1) { 302ba10361aSperseant vp = vget(fs, idesc->id_number); 30342614ed3Sfvdl VTOI(vp)->i_ffs1_size -= isize; 304369e9cadSperseant isize = 0; 305369e9cadSperseant printf( 306369e9cadSperseant "YOU MUST RERUN FSCK AFTERWARDS\n"); 307369e9cadSperseant rerun = 1; 308ba10361aSperseant inodirty(VTOI(vp)); 309ba10361aSperseant if (diddirty) 310ba10361aSperseant VOP_BWRITE(bp); 311ba10361aSperseant else 312ba10361aSperseant brelse(bp); 313369e9cadSperseant return (STOP); 314369e9cadSperseant } 315369e9cadSperseant } 316369e9cadSperseant } 317369e9cadSperseant isize -= sizepb; 318369e9cadSperseant } 319ba10361aSperseant if (diddirty) 320ba10361aSperseant VOP_BWRITE(bp); 321ba10361aSperseant else 322ba10361aSperseant brelse(bp); 323369e9cadSperseant return (KEEPON); 324369e9cadSperseant } 325369e9cadSperseant /* 326369e9cadSperseant * Check that a block in a legal block number. 327369e9cadSperseant * Return 0 if in range, 1 if out of range. 328369e9cadSperseant */ 329369e9cadSperseant int 3301d259671Sperseant chkrange(daddr_t blk, int cnt) 331369e9cadSperseant { 332ba10361aSperseant if (blk < sntod(fs, 0)) { 33375453f28Sperseant return (1); 33475453f28Sperseant } 3354e3fced9Sperseant if (blk > maxfsblock) { 3364e3fced9Sperseant return (1); 3374e3fced9Sperseant } 338ba10361aSperseant if (blk + cnt < sntod(fs, 0)) { 3394e3fced9Sperseant return (1); 3404e3fced9Sperseant } 3414e3fced9Sperseant if (blk + cnt > maxfsblock) { 342369e9cadSperseant return (1); 343369e9cadSperseant } 344369e9cadSperseant return (0); 345369e9cadSperseant } 346369e9cadSperseant /* 347369e9cadSperseant * Routines to maintain information about directory inodes. 348369e9cadSperseant * This is built during the first pass and used during the 349369e9cadSperseant * second and third passes. 350369e9cadSperseant * 351369e9cadSperseant * Enter inodes into the cache. 352369e9cadSperseant */ 353369e9cadSperseant void 35442614ed3Sfvdl cacheino(struct ufs1_dinode * dp, ino_t inumber) 355369e9cadSperseant { 356ba10361aSperseant struct inoinfo *inp; 3576379e111Sitojun struct inoinfo **inpp, **ninpsort; 358369e9cadSperseant unsigned int blks; 359369e9cadSperseant 360ba10361aSperseant blks = howmany(dp->di_size, fs->lfs_bsize); 361369e9cadSperseant if (blks > NDADDR) 362369e9cadSperseant blks = NDADDR + NIADDR; 363369e9cadSperseant inp = (struct inoinfo *) 364ba10361aSperseant malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs_daddr_t)); 365369e9cadSperseant if (inp == NULL) 366369e9cadSperseant return; 367369e9cadSperseant inpp = &inphead[inumber % numdirs]; 368369e9cadSperseant inp->i_nexthash = *inpp; 369369e9cadSperseant *inpp = inp; 370369e9cadSperseant inp->i_child = inp->i_sibling = inp->i_parentp = 0; 371369e9cadSperseant if (inumber == ROOTINO) 372369e9cadSperseant inp->i_parent = ROOTINO; 373369e9cadSperseant else 374369e9cadSperseant inp->i_parent = (ino_t) 0; 375369e9cadSperseant inp->i_dotdot = (ino_t) 0; 376369e9cadSperseant inp->i_number = inumber; 377369e9cadSperseant inp->i_isize = dp->di_size; 378ba10361aSperseant 379ba10361aSperseant inp->i_numblks = blks * sizeof(ufs_daddr_t); 380369e9cadSperseant memcpy(&inp->i_blks[0], &dp->di_db[0], (size_t) inp->i_numblks); 381369e9cadSperseant if (inplast == listmax) { 3826379e111Sitojun ninpsort = (struct inoinfo **) realloc((char *) inpsort, 3836379e111Sitojun (unsigned) (listmax + 100) * sizeof(struct inoinfo *)); 3846379e111Sitojun if (ninpsort == NULL) 385ba10361aSperseant err(8, "cannot increase directory list\n"); 3866379e111Sitojun inpsort = ninpsort; 3876379e111Sitojun listmax += 100; 388369e9cadSperseant } 389369e9cadSperseant inpsort[inplast++] = inp; 390369e9cadSperseant } 391369e9cadSperseant 392369e9cadSperseant /* 393369e9cadSperseant * Look up an inode cache structure. 394369e9cadSperseant */ 395369e9cadSperseant struct inoinfo * 3961d259671Sperseant getinoinfo(ino_t inumber) 397369e9cadSperseant { 398*251f7f59Sperry struct inoinfo *inp; 399369e9cadSperseant 400369e9cadSperseant for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) { 401369e9cadSperseant if (inp->i_number != inumber) 402369e9cadSperseant continue; 403369e9cadSperseant return (inp); 404369e9cadSperseant } 405ba10361aSperseant err(8, "cannot find inode %d\n", inumber); 406369e9cadSperseant return ((struct inoinfo *) 0); 407369e9cadSperseant } 408369e9cadSperseant 409369e9cadSperseant /* 410369e9cadSperseant * Clean up all the inode cache structure. 411369e9cadSperseant */ 412369e9cadSperseant void 413*251f7f59Sperry inocleanup(void) 414369e9cadSperseant { 415*251f7f59Sperry struct inoinfo **inpp; 416369e9cadSperseant 417369e9cadSperseant if (inphead == NULL) 418369e9cadSperseant return; 419369e9cadSperseant for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 420369e9cadSperseant free((char *) (*inpp)); 421369e9cadSperseant free((char *) inphead); 422369e9cadSperseant free((char *) inpsort); 423369e9cadSperseant inphead = inpsort = NULL; 424369e9cadSperseant } 425369e9cadSperseant 426369e9cadSperseant void 427ba10361aSperseant inodirty(struct inode *ip) 428369e9cadSperseant { 429ba10361aSperseant ip->i_flag |= IN_MODIFIED; 430369e9cadSperseant } 431369e9cadSperseant 432369e9cadSperseant void 4331d259671Sperseant clri(struct inodesc * idesc, char *type, int flag) 434369e9cadSperseant { 435ba10361aSperseant struct uvnode *vp; 436369e9cadSperseant 437ba10361aSperseant vp = vget(fs, idesc->id_number); 438369e9cadSperseant if (flag == 1) { 439369e9cadSperseant pwarn("%s %s", type, 44042614ed3Sfvdl (VTOI(vp)->i_ffs1_mode & IFMT) == IFDIR ? "DIR" : "FILE"); 441369e9cadSperseant pinode(idesc->id_number); 442369e9cadSperseant } 443ba10361aSperseant if (flag == 2 || preen || reply("CLEAR") == 1) { 444ba10361aSperseant if (preen && flag != 2) 445369e9cadSperseant printf(" (CLEARED)\n"); 446369e9cadSperseant n_files--; 447ba10361aSperseant (void) ckinode(VTOD(vp), idesc); 44817d264b6Syamt clearinode(idesc->id_number); 449369e9cadSperseant statemap[idesc->id_number] = USTATE; 45017d264b6Syamt vnode_destroy(vp); 45117d264b6Syamt } 45217d264b6Syamt } 45317d264b6Syamt 45417d264b6Syamt void 45517d264b6Syamt clearinode(ino_t inumber) 45617d264b6Syamt { 45717d264b6Syamt struct ubuf *bp; 45817d264b6Syamt IFILE *ifp; 45917d264b6Syamt daddr_t daddr; 460e6c70652Sperseant 461e6c70652Sperseant /* Send cleared inode to the free list */ 462e6c70652Sperseant 46317d264b6Syamt LFS_IENTRY(ifp, fs, inumber, bp); 46417d264b6Syamt daddr = ifp->if_daddr; 465e6c70652Sperseant ifp->if_daddr = LFS_UNUSED_DADDR; 466ba10361aSperseant ifp->if_nextfree = fs->lfs_freehd; 46717d264b6Syamt fs->lfs_freehd = inumber; 468e6c70652Sperseant sbdirty(); 469ba10361aSperseant VOP_BWRITE(bp); 47017d264b6Syamt 47117d264b6Syamt /* 47217d264b6Syamt * update segment usage. 47317d264b6Syamt */ 47417d264b6Syamt if (daddr != LFS_UNUSED_DADDR) { 47517d264b6Syamt SEGUSE *sup; 47617d264b6Syamt u_int32_t oldsn = dtosn(fs, daddr); 47717d264b6Syamt 47817d264b6Syamt LFS_SEGENTRY(sup, fs, oldsn, bp); 47917d264b6Syamt sup->su_nbytes -= DINODE1_SIZE; 48017d264b6Syamt LFS_WRITESEGENTRY(sup, fs, oldsn, bp); /* Ifile */ 481369e9cadSperseant } 482369e9cadSperseant } 483369e9cadSperseant 484369e9cadSperseant int 4851d259671Sperseant findname(struct inodesc * idesc) 486369e9cadSperseant { 487*251f7f59Sperry struct direct *dirp = idesc->id_dirp; 488369e9cadSperseant 489369e9cadSperseant if (dirp->d_ino != idesc->id_parent) 490369e9cadSperseant return (KEEPON); 491369e9cadSperseant memcpy(idesc->id_name, dirp->d_name, (size_t) dirp->d_namlen + 1); 492369e9cadSperseant return (STOP | FOUND); 493369e9cadSperseant } 494369e9cadSperseant 495369e9cadSperseant int 4961d259671Sperseant findino(struct inodesc * idesc) 497369e9cadSperseant { 498*251f7f59Sperry struct direct *dirp = idesc->id_dirp; 499369e9cadSperseant 500369e9cadSperseant if (dirp->d_ino == 0) 501369e9cadSperseant return (KEEPON); 502369e9cadSperseant if (strcmp(dirp->d_name, idesc->id_name) == 0 && 50375453f28Sperseant dirp->d_ino >= ROOTINO && dirp->d_ino < maxino) { 504369e9cadSperseant idesc->id_parent = dirp->d_ino; 505369e9cadSperseant return (STOP | FOUND); 506369e9cadSperseant } 507369e9cadSperseant return (KEEPON); 508369e9cadSperseant } 509369e9cadSperseant 510369e9cadSperseant void 5111d259671Sperseant pinode(ino_t ino) 512369e9cadSperseant { 513*251f7f59Sperry struct ufs1_dinode *dp; 514*251f7f59Sperry char *p; 515369e9cadSperseant struct passwd *pw; 516369e9cadSperseant time_t t; 517369e9cadSperseant 518369e9cadSperseant printf(" I=%u ", ino); 51975453f28Sperseant if (ino < ROOTINO || ino >= maxino) 520369e9cadSperseant return; 521369e9cadSperseant dp = ginode(ino); 522369e9cadSperseant if (dp) { 523369e9cadSperseant printf(" OWNER="); 524369e9cadSperseant #ifndef SMALL 525369e9cadSperseant if ((pw = getpwuid((int) dp->di_uid)) != 0) 526369e9cadSperseant printf("%s ", pw->pw_name); 527369e9cadSperseant else 528369e9cadSperseant #endif 529369e9cadSperseant printf("%u ", (unsigned) dp->di_uid); 530369e9cadSperseant printf("MODE=%o\n", dp->di_mode); 531369e9cadSperseant if (preen) 532369e9cadSperseant printf("%s: ", cdevname()); 533f7650338Slukem printf("SIZE=%llu ", (unsigned long long) dp->di_size); 534369e9cadSperseant t = dp->di_mtime; 535369e9cadSperseant p = ctime(&t); 536369e9cadSperseant printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); 537369e9cadSperseant } 538369e9cadSperseant } 539369e9cadSperseant 540369e9cadSperseant void 5411d259671Sperseant blkerror(ino_t ino, char *type, daddr_t blk) 542369e9cadSperseant { 543369e9cadSperseant 544a3ff3a30Sfvdl pfatal("%lld %s I=%u", (long long) blk, type, ino); 545369e9cadSperseant printf("\n"); 546369e9cadSperseant if (exitonfail) 547369e9cadSperseant exit(1); 548369e9cadSperseant switch (statemap[ino]) { 549369e9cadSperseant 550369e9cadSperseant case FSTATE: 551369e9cadSperseant statemap[ino] = FCLEAR; 552369e9cadSperseant return; 553369e9cadSperseant 554369e9cadSperseant case DSTATE: 555369e9cadSperseant statemap[ino] = DCLEAR; 556369e9cadSperseant return; 557369e9cadSperseant 558369e9cadSperseant case FCLEAR: 559369e9cadSperseant case DCLEAR: 560369e9cadSperseant return; 561369e9cadSperseant 562369e9cadSperseant default: 563ba10361aSperseant err(8, "BAD STATE %d TO BLKERR\n", statemap[ino]); 564369e9cadSperseant /* NOTREACHED */ 565369e9cadSperseant } 566369e9cadSperseant } 567369e9cadSperseant /* 568369e9cadSperseant * allocate an unused inode 569369e9cadSperseant */ 570369e9cadSperseant ino_t 5711d259671Sperseant allocino(ino_t request, int type) 572369e9cadSperseant { 573ba10361aSperseant ino_t ino; 57442614ed3Sfvdl struct ufs1_dinode *dp; 575369e9cadSperseant time_t t; 576ba10361aSperseant struct uvnode *vp; 577ba10361aSperseant struct ubuf *bp; 578369e9cadSperseant 579369e9cadSperseant if (request == 0) 580369e9cadSperseant request = ROOTINO; 581369e9cadSperseant else if (statemap[request] != USTATE) 582369e9cadSperseant return (0); 583369e9cadSperseant for (ino = request; ino < maxino; ino++) 584369e9cadSperseant if (statemap[ino] == USTATE) 585369e9cadSperseant break; 586369e9cadSperseant if (ino == maxino) 587369e9cadSperseant return (0); 588369e9cadSperseant switch (type & IFMT) { 589369e9cadSperseant case IFDIR: 590369e9cadSperseant statemap[ino] = DSTATE; 591369e9cadSperseant break; 592369e9cadSperseant case IFREG: 593369e9cadSperseant case IFLNK: 594369e9cadSperseant statemap[ino] = FSTATE; 595369e9cadSperseant break; 596369e9cadSperseant default: 597369e9cadSperseant return (0); 598369e9cadSperseant } 599ba10361aSperseant vp = vget(fs, ino); 60042614ed3Sfvdl dp = (VTOI(vp)->i_din.ffs1_din); 601ba10361aSperseant bp = getblk(vp, 0, fs->lfs_fsize); 602ba10361aSperseant VOP_BWRITE(bp); 603369e9cadSperseant dp->di_mode = type; 604369e9cadSperseant (void) time(&t); 605369e9cadSperseant dp->di_atime = t; 606369e9cadSperseant dp->di_mtime = dp->di_ctime = dp->di_atime; 607ba10361aSperseant dp->di_size = fs->lfs_fsize; 608ba10361aSperseant dp->di_blocks = btofsb(fs, fs->lfs_fsize); 609369e9cadSperseant n_files++; 610ba10361aSperseant inodirty(VTOI(vp)); 611369e9cadSperseant typemap[ino] = IFTODT(type); 612369e9cadSperseant return (ino); 613369e9cadSperseant } 614369e9cadSperseant /* 615369e9cadSperseant * deallocate an inode 616369e9cadSperseant */ 617369e9cadSperseant void 6181d259671Sperseant freeino(ino_t ino) 619369e9cadSperseant { 620369e9cadSperseant struct inodesc idesc; 621ba10361aSperseant struct uvnode *vp; 622369e9cadSperseant 623369e9cadSperseant memset(&idesc, 0, sizeof(struct inodesc)); 624369e9cadSperseant idesc.id_type = ADDR; 625369e9cadSperseant idesc.id_func = pass4check; 626369e9cadSperseant idesc.id_number = ino; 627ba10361aSperseant vp = vget(fs, ino); 628ba10361aSperseant (void) ckinode(VTOD(vp), &idesc); 62917d264b6Syamt clearinode(ino); 630369e9cadSperseant statemap[ino] = USTATE; 63117d264b6Syamt vnode_destroy(vp); 632e6c70652Sperseant 633369e9cadSperseant n_files--; 634369e9cadSperseant } 635