1*55fd1169Sdholland /* $NetBSD: inode.c,v 1.47 2013/06/08 02:11:11 dholland 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 * 195aaab72dSperseant * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 205aaab72dSperseant * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 215aaab72dSperseant * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 225aaab72dSperseant * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 235aaab72dSperseant * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 245aaab72dSperseant * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 255aaab72dSperseant * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 265aaab72dSperseant * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 275aaab72dSperseant * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 285aaab72dSperseant * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 295aaab72dSperseant * POSSIBILITY OF SUCH DAMAGE. 305aaab72dSperseant */ 31276d62f6Sagc 32276d62f6Sagc /* 33276d62f6Sagc * Copyright (c) 1980, 1986, 1993 34276d62f6Sagc * The Regents of the University of California. All rights reserved. 35276d62f6Sagc * 36276d62f6Sagc * Redistribution and use in source and binary forms, with or without 37276d62f6Sagc * modification, are permitted provided that the following conditions 38276d62f6Sagc * are met: 39276d62f6Sagc * 1. Redistributions of source code must retain the above copyright 40276d62f6Sagc * notice, this list of conditions and the following disclaimer. 41276d62f6Sagc * 2. Redistributions in binary form must reproduce the above copyright 42276d62f6Sagc * notice, this list of conditions and the following disclaimer in the 43276d62f6Sagc * documentation and/or other materials provided with the distribution. 44276d62f6Sagc * 3. Neither the name of the University nor the names of its contributors 45276d62f6Sagc * may be used to endorse or promote products derived from this software 46276d62f6Sagc * without specific prior written permission. 47276d62f6Sagc * 48276d62f6Sagc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49276d62f6Sagc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50276d62f6Sagc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51276d62f6Sagc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52276d62f6Sagc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53276d62f6Sagc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54276d62f6Sagc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55276d62f6Sagc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56276d62f6Sagc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57276d62f6Sagc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58276d62f6Sagc * SUCH DAMAGE. 59276d62f6Sagc */ 60369e9cadSperseant 61ba10361aSperseant #include <sys/types.h> 62369e9cadSperseant #include <sys/param.h> 63369e9cadSperseant #include <sys/time.h> 64ba10361aSperseant #include <sys/buf.h> 65ba10361aSperseant #include <sys/mount.h> 66ba10361aSperseant 67f5ac0b5fSdholland #define vnode uvnode 68f5ac0b5fSdholland #define _SYS_VNODE_H_ /* XXX */ 694f8bc7f7Sdholland #include <ufs/lfs/ulfs_inode.h> 704f8bc7f7Sdholland #include <ufs/lfs/ulfs_dir.h> 71369e9cadSperseant #include <ufs/lfs/lfs.h> 72ba10361aSperseant #undef vnode 73ba10361aSperseant 74ba10361aSperseant #include <err.h> 75369e9cadSperseant #ifndef SMALL 76369e9cadSperseant #include <pwd.h> 77369e9cadSperseant #endif 78369e9cadSperseant #include <stdio.h> 79369e9cadSperseant #include <stdlib.h> 80369e9cadSperseant #include <string.h> 81b6479e9fSchristos #include <util.h> 82369e9cadSperseant 83ba10361aSperseant #include "bufcache.h" 84ba10361aSperseant #include "vnode.h" 85100801edSchristos #include "lfs_user.h" 86ba10361aSperseant 87369e9cadSperseant #include "fsck.h" 88369e9cadSperseant #include "fsutil.h" 89369e9cadSperseant #include "extern.h" 90369e9cadSperseant 91369e9cadSperseant extern SEGUSE *seg_table; 924f8bc7f7Sdholland extern ulfs_daddr_t *din_table; 93369e9cadSperseant 941d259671Sperseant static int iblock(struct inodesc *, long, u_int64_t); 95369e9cadSperseant int blksreqd(struct lfs *, int); 96369e9cadSperseant int lfs_maxino(void); 97369e9cadSperseant 98ba10361aSperseant /* 99ba10361aSperseant * Get a dinode of a given inum. 100ba10361aSperseant * XXX combine this function with vget. 101ba10361aSperseant */ 1024f8bc7f7Sdholland struct ulfs1_dinode * 103ba10361aSperseant ginode(ino_t ino) 104369e9cadSperseant { 105ba10361aSperseant struct uvnode *vp; 106ba10361aSperseant struct ubuf *bp; 1074e3fced9Sperseant IFILE *ifp; 108369e9cadSperseant 109ba10361aSperseant vp = vget(fs, ino); 110ba10361aSperseant if (vp == NULL) 111e6c70652Sperseant return NULL; 112e6c70652Sperseant 113ba10361aSperseant if (din_table[ino] == 0x0) { 114ba10361aSperseant LFS_IENTRY(ifp, fs, ino, bp); 115ba10361aSperseant din_table[ino] = ifp->if_daddr; 116ad6712b5Sdholland seg_table[dtosn(fs, ifp->if_daddr)].su_nbytes += LFS_DINODE1_SIZE; 117fe44973fSad brelse(bp, 0); 118e6c70652Sperseant } 11942614ed3Sfvdl return (VTOI(vp)->i_din.ffs1_din); 120369e9cadSperseant } 121369e9cadSperseant 122369e9cadSperseant /* 123ba10361aSperseant * Check validity of held blocks in an inode, recursing through all blocks. 124369e9cadSperseant */ 125369e9cadSperseant int 1264f8bc7f7Sdholland ckinode(struct ulfs1_dinode *dp, struct inodesc *idesc) 127369e9cadSperseant { 1284f8bc7f7Sdholland ulfs_daddr_t *ap, lbn; 129369e9cadSperseant long ret, n, ndb, offset; 1304f8bc7f7Sdholland struct ulfs1_dinode dino; 131369e9cadSperseant u_int64_t remsize, sizepb; 132369e9cadSperseant mode_t mode; 133369e9cadSperseant char pathbuf[MAXPATHLEN + 1]; 134ba10361aSperseant struct uvnode *vp, *thisvp; 135369e9cadSperseant 136369e9cadSperseant if (idesc->id_fix != IGNORE) 137369e9cadSperseant idesc->id_fix = DONTKNOW; 138369e9cadSperseant idesc->id_entryno = 0; 139369e9cadSperseant idesc->id_filesize = dp->di_size; 140*55fd1169Sdholland mode = dp->di_mode & LFS_IFMT; 141*55fd1169Sdholland if (mode == LFS_IFBLK || mode == LFS_IFCHR || 142*55fd1169Sdholland (mode == LFS_IFLNK && (dp->di_size < fs->lfs_maxsymlinklen || 143ba10361aSperseant (fs->lfs_maxsymlinklen == 0 && 1441d259671Sperseant dp->di_blocks == 0)))) 145369e9cadSperseant return (KEEPON); 146369e9cadSperseant dino = *dp; 147ba10361aSperseant ndb = howmany(dino.di_size, fs->lfs_bsize); 148369e9cadSperseant 149884f970fSyamt thisvp = vget(fs, idesc->id_number); 1504f8bc7f7Sdholland for (lbn = 0; lbn < ULFS_NDADDR; lbn++) { 151ba10361aSperseant ap = dino.di_db + lbn; 152ba10361aSperseant if (thisvp) 153369e9cadSperseant idesc->id_numfrags = 154ba10361aSperseant numfrags(fs, VTOI(thisvp)->i_lfs_fragsize[lbn]); 155ba10361aSperseant else { 156ba10361aSperseant if (--ndb == 0 && (offset = blkoff(fs, dino.di_size)) != 0) { 157ba10361aSperseant idesc->id_numfrags = 158ba10361aSperseant numfrags(fs, fragroundup(fs, offset)); 159369e9cadSperseant } else 160ba10361aSperseant idesc->id_numfrags = fs->lfs_frag; 161ba10361aSperseant } 162369e9cadSperseant if (*ap == 0) { 163369e9cadSperseant if (idesc->id_type == DATA && ndb >= 0) { 164369e9cadSperseant /* An empty block in a directory XXX */ 1658883e1fbSitojun getpathname(pathbuf, sizeof(pathbuf), 1668883e1fbSitojun idesc->id_number, idesc->id_number); 16729f1062bSperseant pfatal("DIRECTORY %s INO %lld: CONTAINS EMPTY BLOCKS [1]", 16829f1062bSperseant pathbuf, (long long)idesc->id_number); 169369e9cadSperseant if (reply("ADJUST LENGTH") == 1) { 170ba10361aSperseant vp = vget(fs, idesc->id_number); 171ba10361aSperseant dp = VTOD(vp); 172369e9cadSperseant dp->di_size = (ap - &dino.di_db[0]) * 173ba10361aSperseant fs->lfs_bsize; 174369e9cadSperseant printf( 175369e9cadSperseant "YOU MUST RERUN FSCK AFTERWARDS\n"); 176369e9cadSperseant rerun = 1; 177ba10361aSperseant inodirty(VTOI(vp)); 17829f1062bSperseant } else 17929f1062bSperseant break; 180369e9cadSperseant } 181369e9cadSperseant continue; 182369e9cadSperseant } 183369e9cadSperseant idesc->id_blkno = *ap; 184369e9cadSperseant idesc->id_lblkno = ap - &dino.di_db[0]; 185369e9cadSperseant if (idesc->id_type == ADDR) { 186369e9cadSperseant ret = (*idesc->id_func) (idesc); 1871d259671Sperseant } else 188369e9cadSperseant ret = dirscan(idesc); 189369e9cadSperseant if (ret & STOP) 190369e9cadSperseant return (ret); 191369e9cadSperseant } 192ba10361aSperseant idesc->id_numfrags = fs->lfs_frag; 1934f8bc7f7Sdholland remsize = dino.di_size - fs->lfs_bsize * ULFS_NDADDR; 194ba10361aSperseant sizepb = fs->lfs_bsize; 1954f8bc7f7Sdholland for (ap = &dino.di_ib[0], n = 1; n <= ULFS_NIADDR; ap++, n++) { 196369e9cadSperseant if (*ap) { 197369e9cadSperseant idesc->id_blkno = *ap; 198369e9cadSperseant ret = iblock(idesc, n, remsize); 199369e9cadSperseant if (ret & STOP) 200369e9cadSperseant return (ret); 201369e9cadSperseant } else { 202369e9cadSperseant if (idesc->id_type == DATA && remsize > 0) { 203369e9cadSperseant /* An empty block in a directory XXX */ 2048883e1fbSitojun getpathname(pathbuf, sizeof(pathbuf), 2058883e1fbSitojun idesc->id_number, idesc->id_number); 20629f1062bSperseant pfatal("DIRECTORY %s INO %lld: CONTAINS EMPTY BLOCKS [2]", 20729f1062bSperseant pathbuf, (long long)idesc->id_number); 208369e9cadSperseant if (reply("ADJUST LENGTH") == 1) { 209ba10361aSperseant vp = vget(fs, idesc->id_number); 210ba10361aSperseant dp = VTOD(vp); 211369e9cadSperseant dp->di_size -= remsize; 212369e9cadSperseant remsize = 0; 213369e9cadSperseant printf( 214369e9cadSperseant "YOU MUST RERUN FSCK AFTERWARDS\n"); 215369e9cadSperseant rerun = 1; 216ba10361aSperseant inodirty(VTOI(vp)); 217369e9cadSperseant break; 21829f1062bSperseant } else 21929f1062bSperseant break; 220369e9cadSperseant } 221369e9cadSperseant } 222ba10361aSperseant sizepb *= NINDIR(fs); 223369e9cadSperseant remsize -= sizepb; 224369e9cadSperseant } 225369e9cadSperseant return (KEEPON); 226369e9cadSperseant } 227369e9cadSperseant 228369e9cadSperseant static int 2291d259671Sperseant iblock(struct inodesc *idesc, long ilevel, u_int64_t isize) 230369e9cadSperseant { 2314f8bc7f7Sdholland ulfs_daddr_t *ap, *aplim; 232ba10361aSperseant struct ubuf *bp; 2331d259671Sperseant int i, n, (*func) (struct inodesc *), nif; 234369e9cadSperseant u_int64_t sizepb; 235369e9cadSperseant char pathbuf[MAXPATHLEN + 1], buf[BUFSIZ]; 236ba10361aSperseant struct uvnode *devvp, *vp; 237ba10361aSperseant int diddirty = 0; 238369e9cadSperseant 239369e9cadSperseant if (idesc->id_type == ADDR) { 240369e9cadSperseant func = idesc->id_func; 241369e9cadSperseant n = (*func) (idesc); 242369e9cadSperseant if ((n & KEEPON) == 0) 243369e9cadSperseant return (n); 244369e9cadSperseant } else 245369e9cadSperseant func = dirscan; 24679748725Smlelstv if (chkrange(idesc->id_blkno, idesc->id_numfrags)) 247369e9cadSperseant return (SKIP); 248ba10361aSperseant 249dcba0206Sperseant devvp = fs->lfs_devvp; 2505d2bff06Shannken bread(devvp, fsbtodb(fs, idesc->id_blkno), fs->lfs_bsize, 2515d2bff06Shannken NOCRED, 0, &bp); 252369e9cadSperseant ilevel--; 253ba10361aSperseant for (sizepb = fs->lfs_bsize, i = 0; i < ilevel; i++) 254ba10361aSperseant sizepb *= NINDIR(fs); 255ba10361aSperseant if (isize > sizepb * NINDIR(fs)) 256ba10361aSperseant nif = NINDIR(fs); 257369e9cadSperseant else 258369e9cadSperseant nif = howmany(isize, sizepb); 259ba10361aSperseant if (idesc->id_func == pass1check && nif < NINDIR(fs)) { 2604f8bc7f7Sdholland aplim = ((ulfs_daddr_t *) bp->b_data) + NINDIR(fs); 2614f8bc7f7Sdholland for (ap = ((ulfs_daddr_t *) bp->b_data) + nif; ap < aplim; ap++) { 262369e9cadSperseant if (*ap == 0) 263369e9cadSperseant continue; 264c4ee9f6dSchristos (void) sprintf(buf, "PARTIALLY TRUNCATED INODE I=%llu", 265c4ee9f6dSchristos (unsigned long long)idesc->id_number); 266369e9cadSperseant if (dofix(idesc, buf)) { 267369e9cadSperseant *ap = 0; 268ba10361aSperseant ++diddirty; 269369e9cadSperseant } 270369e9cadSperseant } 271369e9cadSperseant } 2724f8bc7f7Sdholland aplim = ((ulfs_daddr_t *) bp->b_data) + nif; 2734f8bc7f7Sdholland for (ap = ((ulfs_daddr_t *) bp->b_data); ap < aplim; ap++) { 274369e9cadSperseant if (*ap) { 275369e9cadSperseant idesc->id_blkno = *ap; 2766e547a61Syamt if (ilevel == 0) { 2776e547a61Syamt /* 2786e547a61Syamt * dirscan needs lblkno. 2796e547a61Syamt */ 2806e547a61Syamt idesc->id_lblkno++; 281369e9cadSperseant n = (*func) (idesc); 2826e547a61Syamt } else { 283369e9cadSperseant n = iblock(idesc, ilevel, isize); 2846e547a61Syamt } 285369e9cadSperseant if (n & STOP) { 286ba10361aSperseant if (diddirty) 287ba10361aSperseant VOP_BWRITE(bp); 288ba10361aSperseant else 289fe44973fSad brelse(bp, 0); 290369e9cadSperseant return (n); 291369e9cadSperseant } 292369e9cadSperseant } else { 293369e9cadSperseant if (idesc->id_type == DATA && isize > 0) { 294369e9cadSperseant /* An empty block in a directory XXX */ 2958883e1fbSitojun getpathname(pathbuf, sizeof(pathbuf), 2968883e1fbSitojun idesc->id_number, idesc->id_number); 29729f1062bSperseant pfatal("DIRECTORY %s INO %lld: CONTAINS EMPTY BLOCKS [3]", 29829f1062bSperseant pathbuf, (long long)idesc->id_number); 299369e9cadSperseant if (reply("ADJUST LENGTH") == 1) { 300ba10361aSperseant vp = vget(fs, idesc->id_number); 30142614ed3Sfvdl VTOI(vp)->i_ffs1_size -= isize; 302369e9cadSperseant isize = 0; 303369e9cadSperseant printf( 304369e9cadSperseant "YOU MUST RERUN FSCK AFTERWARDS\n"); 305369e9cadSperseant rerun = 1; 306ba10361aSperseant inodirty(VTOI(vp)); 307ba10361aSperseant if (diddirty) 308ba10361aSperseant VOP_BWRITE(bp); 309ba10361aSperseant else 310fe44973fSad brelse(bp, 0); 311369e9cadSperseant return (STOP); 312369e9cadSperseant } 313369e9cadSperseant } 314369e9cadSperseant } 315369e9cadSperseant isize -= sizepb; 316369e9cadSperseant } 317ba10361aSperseant if (diddirty) 318ba10361aSperseant VOP_BWRITE(bp); 319ba10361aSperseant else 320fe44973fSad brelse(bp, 0); 321369e9cadSperseant return (KEEPON); 322369e9cadSperseant } 3234b8db838Sperseant 324369e9cadSperseant /* 325369e9cadSperseant * Check that a block in a legal block number. 326369e9cadSperseant * Return 0 if in range, 1 if out of range. 327369e9cadSperseant */ 328369e9cadSperseant int 3291d259671Sperseant chkrange(daddr_t blk, int cnt) 330369e9cadSperseant { 331ba10361aSperseant if (blk < sntod(fs, 0)) { 33275453f28Sperseant return (1); 33375453f28Sperseant } 3344e3fced9Sperseant if (blk > maxfsblock) { 3354e3fced9Sperseant return (1); 3364e3fced9Sperseant } 337ba10361aSperseant if (blk + cnt < sntod(fs, 0)) { 3384e3fced9Sperseant return (1); 3394e3fced9Sperseant } 3404e3fced9Sperseant if (blk + cnt > maxfsblock) { 341369e9cadSperseant return (1); 342369e9cadSperseant } 343369e9cadSperseant return (0); 344369e9cadSperseant } 3454b8db838Sperseant 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 3544f8bc7f7Sdholland cacheino(struct ulfs1_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); 3614f8bc7f7Sdholland if (blks > ULFS_NDADDR) 3624f8bc7f7Sdholland blks = ULFS_NDADDR + ULFS_NIADDR; 3634f8bc7f7Sdholland inp = emalloc(sizeof(*inp) + (blks - 1) * sizeof(ulfs_daddr_t)); 364369e9cadSperseant inpp = &inphead[inumber % numdirs]; 365369e9cadSperseant inp->i_nexthash = *inpp; 366369e9cadSperseant *inpp = inp; 367369e9cadSperseant inp->i_child = inp->i_sibling = inp->i_parentp = 0; 3684f8bc7f7Sdholland if (inumber == ULFS_ROOTINO) 3694f8bc7f7Sdholland inp->i_parent = ULFS_ROOTINO; 370369e9cadSperseant else 371369e9cadSperseant inp->i_parent = (ino_t) 0; 372369e9cadSperseant inp->i_dotdot = (ino_t) 0; 373369e9cadSperseant inp->i_number = inumber; 374369e9cadSperseant inp->i_isize = dp->di_size; 375ba10361aSperseant 3764f8bc7f7Sdholland inp->i_numblks = blks * sizeof(ulfs_daddr_t); 377369e9cadSperseant memcpy(&inp->i_blks[0], &dp->di_db[0], (size_t) inp->i_numblks); 378369e9cadSperseant if (inplast == listmax) { 379b6479e9fSchristos ninpsort = erealloc(inpsort, 380b6479e9fSchristos (listmax + 100) * sizeof(struct inoinfo *)); 3816379e111Sitojun inpsort = ninpsort; 3826379e111Sitojun listmax += 100; 383369e9cadSperseant } 384369e9cadSperseant inpsort[inplast++] = inp; 385369e9cadSperseant } 386369e9cadSperseant 387369e9cadSperseant /* 388369e9cadSperseant * Look up an inode cache structure. 389369e9cadSperseant */ 390369e9cadSperseant struct inoinfo * 3911d259671Sperseant getinoinfo(ino_t inumber) 392369e9cadSperseant { 393251f7f59Sperry struct inoinfo *inp; 394369e9cadSperseant 395369e9cadSperseant for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) { 396369e9cadSperseant if (inp->i_number != inumber) 397369e9cadSperseant continue; 398369e9cadSperseant return (inp); 399369e9cadSperseant } 400b6479e9fSchristos err(EEXIT, "cannot find inode %llu\n", (unsigned long long)inumber); 401369e9cadSperseant return ((struct inoinfo *) 0); 402369e9cadSperseant } 403369e9cadSperseant 404369e9cadSperseant /* 405369e9cadSperseant * Clean up all the inode cache structure. 406369e9cadSperseant */ 407369e9cadSperseant void 408251f7f59Sperry inocleanup(void) 409369e9cadSperseant { 410251f7f59Sperry struct inoinfo **inpp; 411369e9cadSperseant 412369e9cadSperseant if (inphead == NULL) 413369e9cadSperseant return; 414369e9cadSperseant for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 415369e9cadSperseant free((char *) (*inpp)); 416369e9cadSperseant free((char *) inphead); 417369e9cadSperseant free((char *) inpsort); 418369e9cadSperseant inphead = inpsort = NULL; 419369e9cadSperseant } 420369e9cadSperseant 421369e9cadSperseant void 422ba10361aSperseant inodirty(struct inode *ip) 423369e9cadSperseant { 424ba10361aSperseant ip->i_flag |= IN_MODIFIED; 425369e9cadSperseant } 426369e9cadSperseant 427369e9cadSperseant void 428e0dd0ca2Schristos clri(struct inodesc * idesc, const char *type, int flag) 429369e9cadSperseant { 430ba10361aSperseant struct uvnode *vp; 431369e9cadSperseant 432ba10361aSperseant vp = vget(fs, idesc->id_number); 433cb2499acSperseant if (flag & 0x1) { 434369e9cadSperseant pwarn("%s %s", type, 435*55fd1169Sdholland (VTOI(vp)->i_ffs1_mode & LFS_IFMT) == LFS_IFDIR ? "DIR" : "FILE"); 436369e9cadSperseant pinode(idesc->id_number); 437369e9cadSperseant } 438cb2499acSperseant if ((flag & 0x2) || preen || reply("CLEAR") == 1) { 439ba10361aSperseant if (preen && flag != 2) 440369e9cadSperseant printf(" (CLEARED)\n"); 441369e9cadSperseant n_files--; 442ba10361aSperseant (void) ckinode(VTOD(vp), idesc); 44317d264b6Syamt clearinode(idesc->id_number); 444369e9cadSperseant statemap[idesc->id_number] = USTATE; 44517d264b6Syamt vnode_destroy(vp); 446cb2499acSperseant return; 44717d264b6Syamt } 448cb2499acSperseant return; 44917d264b6Syamt } 45017d264b6Syamt 45117d264b6Syamt void 45217d264b6Syamt clearinode(ino_t inumber) 45317d264b6Syamt { 45417d264b6Syamt struct ubuf *bp; 45517d264b6Syamt IFILE *ifp; 45617d264b6Syamt daddr_t daddr; 457e6c70652Sperseant 458e6c70652Sperseant /* Send cleared inode to the free list */ 459e6c70652Sperseant 46017d264b6Syamt LFS_IENTRY(ifp, fs, inumber, bp); 46117d264b6Syamt daddr = ifp->if_daddr; 462a37f15f0Sperseant if (daddr == LFS_UNUSED_DADDR) { 463fe44973fSad brelse(bp, 0); 464a37f15f0Sperseant return; 465a37f15f0Sperseant } 466e6c70652Sperseant ifp->if_daddr = LFS_UNUSED_DADDR; 467ba10361aSperseant ifp->if_nextfree = fs->lfs_freehd; 46817d264b6Syamt fs->lfs_freehd = inumber; 469e6c70652Sperseant sbdirty(); 470ba10361aSperseant VOP_BWRITE(bp); 47117d264b6Syamt 47217d264b6Syamt /* 47317d264b6Syamt * update segment usage. 47417d264b6Syamt */ 47517d264b6Syamt if (daddr != LFS_UNUSED_DADDR) { 47617d264b6Syamt SEGUSE *sup; 47717d264b6Syamt u_int32_t oldsn = dtosn(fs, daddr); 47817d264b6Syamt 479ad6712b5Sdholland seg_table[oldsn].su_nbytes -= LFS_DINODE1_SIZE; 48017d264b6Syamt LFS_SEGENTRY(sup, fs, oldsn, bp); 481ad6712b5Sdholland sup->su_nbytes -= LFS_DINODE1_SIZE; 48217d264b6Syamt LFS_WRITESEGENTRY(sup, fs, oldsn, bp); /* Ifile */ 483369e9cadSperseant } 484369e9cadSperseant } 485369e9cadSperseant 486369e9cadSperseant int 4871d259671Sperseant findname(struct inodesc * idesc) 488369e9cadSperseant { 489251f7f59Sperry struct direct *dirp = idesc->id_dirp; 490e0dd0ca2Schristos size_t len; 491e0dd0ca2Schristos char *buf; 492369e9cadSperseant 493369e9cadSperseant if (dirp->d_ino != idesc->id_parent) 494369e9cadSperseant return (KEEPON); 495e0dd0ca2Schristos if ((len = dirp->d_namlen + 1) > MAXPATHLEN) { 496e0dd0ca2Schristos /* Truncate it but don't overflow the buffer */ 497e0dd0ca2Schristos len = MAXPATHLEN; 498e0dd0ca2Schristos } 499e0dd0ca2Schristos /* this is namebuf with utils.h */ 500e0dd0ca2Schristos buf = __UNCONST(idesc->id_name); 501e0dd0ca2Schristos (void)memcpy(buf, dirp->d_name, len); 502369e9cadSperseant return (STOP | FOUND); 503369e9cadSperseant } 504369e9cadSperseant 505369e9cadSperseant int 5061d259671Sperseant findino(struct inodesc * idesc) 507369e9cadSperseant { 508251f7f59Sperry struct direct *dirp = idesc->id_dirp; 509369e9cadSperseant 510369e9cadSperseant if (dirp->d_ino == 0) 511369e9cadSperseant return (KEEPON); 512369e9cadSperseant if (strcmp(dirp->d_name, idesc->id_name) == 0 && 5134f8bc7f7Sdholland dirp->d_ino >= ULFS_ROOTINO && dirp->d_ino < maxino) { 514369e9cadSperseant idesc->id_parent = dirp->d_ino; 515369e9cadSperseant return (STOP | FOUND); 516369e9cadSperseant } 517369e9cadSperseant return (KEEPON); 518369e9cadSperseant } 519369e9cadSperseant 520369e9cadSperseant void 5211d259671Sperseant pinode(ino_t ino) 522369e9cadSperseant { 5234f8bc7f7Sdholland struct ulfs1_dinode *dp; 524369e9cadSperseant struct passwd *pw; 525369e9cadSperseant 526c4ee9f6dSchristos printf(" I=%llu ", (unsigned long long)ino); 5274f8bc7f7Sdholland if (ino < ULFS_ROOTINO || ino >= maxino) 528369e9cadSperseant return; 529369e9cadSperseant dp = ginode(ino); 530369e9cadSperseant if (dp) { 531369e9cadSperseant printf(" OWNER="); 532369e9cadSperseant #ifndef SMALL 53359334248Schristos if (Uflag && (pw = getpwuid((int) dp->di_uid)) != 0) 534369e9cadSperseant printf("%s ", pw->pw_name); 535369e9cadSperseant else 536369e9cadSperseant #endif 537369e9cadSperseant printf("%u ", (unsigned) dp->di_uid); 538369e9cadSperseant printf("MODE=%o\n", dp->di_mode); 539369e9cadSperseant if (preen) 540369e9cadSperseant printf("%s: ", cdevname()); 541f7650338Slukem printf("SIZE=%llu ", (unsigned long long) dp->di_size); 542c68c36a5Schristos printf("MTIME=%s ", print_mtime(dp->di_mtime)); 543369e9cadSperseant } 544369e9cadSperseant } 545369e9cadSperseant 546369e9cadSperseant void 5479be35a63Schristos blkerror(ino_t ino, const char *type, daddr_t blk) 548369e9cadSperseant { 549369e9cadSperseant 550c4ee9f6dSchristos pfatal("%lld %s I=%llu", (long long) blk, type, 551c4ee9f6dSchristos (unsigned long long)ino); 552369e9cadSperseant printf("\n"); 553369e9cadSperseant if (exitonfail) 554369e9cadSperseant exit(1); 555369e9cadSperseant switch (statemap[ino]) { 556369e9cadSperseant 557369e9cadSperseant case FSTATE: 558369e9cadSperseant statemap[ino] = FCLEAR; 559369e9cadSperseant return; 560369e9cadSperseant 561369e9cadSperseant case DSTATE: 562369e9cadSperseant statemap[ino] = DCLEAR; 563369e9cadSperseant return; 564369e9cadSperseant 565369e9cadSperseant case FCLEAR: 566369e9cadSperseant case DCLEAR: 567369e9cadSperseant return; 568369e9cadSperseant 569369e9cadSperseant default: 570b6479e9fSchristos err(EEXIT, "BAD STATE %d TO BLKERR\n", statemap[ino]); 571369e9cadSperseant /* NOTREACHED */ 572369e9cadSperseant } 573369e9cadSperseant } 5744b8db838Sperseant 575369e9cadSperseant /* 576369e9cadSperseant * allocate an unused inode 577369e9cadSperseant */ 578369e9cadSperseant ino_t 5791d259671Sperseant allocino(ino_t request, int type) 580369e9cadSperseant { 581ba10361aSperseant ino_t ino; 5824f8bc7f7Sdholland struct ulfs1_dinode *dp; 583369e9cadSperseant time_t t; 584ba10361aSperseant struct uvnode *vp; 585ba10361aSperseant struct ubuf *bp; 586369e9cadSperseant 587369e9cadSperseant if (request == 0) 5884f8bc7f7Sdholland request = ULFS_ROOTINO; 589369e9cadSperseant else if (statemap[request] != USTATE) 590369e9cadSperseant return (0); 591369e9cadSperseant for (ino = request; ino < maxino; ino++) 592369e9cadSperseant if (statemap[ino] == USTATE) 593369e9cadSperseant break; 594369e9cadSperseant if (ino == maxino) 59529f1062bSperseant extend_ifile(fs); 59629f1062bSperseant 597*55fd1169Sdholland switch (type & LFS_IFMT) { 598*55fd1169Sdholland case LFS_IFDIR: 599369e9cadSperseant statemap[ino] = DSTATE; 600369e9cadSperseant break; 601*55fd1169Sdholland case LFS_IFREG: 602*55fd1169Sdholland case LFS_IFLNK: 603369e9cadSperseant statemap[ino] = FSTATE; 604369e9cadSperseant break; 605369e9cadSperseant default: 606369e9cadSperseant return (0); 607369e9cadSperseant } 6084b8db838Sperseant vp = lfs_valloc(fs, ino); 6094b8db838Sperseant if (vp == NULL) 6104b8db838Sperseant return (0); 61142614ed3Sfvdl dp = (VTOI(vp)->i_din.ffs1_din); 612ba10361aSperseant bp = getblk(vp, 0, fs->lfs_fsize); 613ba10361aSperseant VOP_BWRITE(bp); 614369e9cadSperseant dp->di_mode = type; 615369e9cadSperseant (void) time(&t); 616369e9cadSperseant dp->di_atime = t; 617369e9cadSperseant dp->di_mtime = dp->di_ctime = dp->di_atime; 618ba10361aSperseant dp->di_size = fs->lfs_fsize; 619ba10361aSperseant dp->di_blocks = btofsb(fs, fs->lfs_fsize); 620369e9cadSperseant n_files++; 621ba10361aSperseant inodirty(VTOI(vp)); 622369e9cadSperseant typemap[ino] = IFTODT(type); 623369e9cadSperseant return (ino); 624369e9cadSperseant } 6254b8db838Sperseant 626369e9cadSperseant /* 627369e9cadSperseant * deallocate an inode 628369e9cadSperseant */ 629369e9cadSperseant void 6301d259671Sperseant freeino(ino_t ino) 631369e9cadSperseant { 632369e9cadSperseant struct inodesc idesc; 633ba10361aSperseant struct uvnode *vp; 634369e9cadSperseant 635369e9cadSperseant memset(&idesc, 0, sizeof(struct inodesc)); 636369e9cadSperseant idesc.id_type = ADDR; 637369e9cadSperseant idesc.id_func = pass4check; 638369e9cadSperseant idesc.id_number = ino; 639ba10361aSperseant vp = vget(fs, ino); 640ba10361aSperseant (void) ckinode(VTOD(vp), &idesc); 64117d264b6Syamt clearinode(ino); 642369e9cadSperseant statemap[ino] = USTATE; 64317d264b6Syamt vnode_destroy(vp); 644e6c70652Sperseant 645369e9cadSperseant n_files--; 646369e9cadSperseant } 647