Home | History | Annotate | Line # | Download | only in fsck_ext2fs
inode.c revision 1.21.8.2
      1  1.21.8.1       mjf /*	$NetBSD: inode.c,v 1.21.8.2 2009/01/17 13:48:52 mjf Exp $	*/
      2       1.1    bouyer 
      3       1.1    bouyer /*
      4       1.1    bouyer  * Copyright (c) 1980, 1986, 1993
      5       1.1    bouyer  *	The Regents of the University of California.  All rights reserved.
      6       1.1    bouyer  *
      7       1.1    bouyer  * Redistribution and use in source and binary forms, with or without
      8       1.1    bouyer  * modification, are permitted provided that the following conditions
      9       1.1    bouyer  * are met:
     10       1.1    bouyer  * 1. Redistributions of source code must retain the above copyright
     11       1.1    bouyer  *    notice, this list of conditions and the following disclaimer.
     12       1.1    bouyer  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1    bouyer  *    notice, this list of conditions and the following disclaimer in the
     14       1.1    bouyer  *    documentation and/or other materials provided with the distribution.
     15      1.11       agc  * 3. Neither the name of the University nor the names of its contributors
     16      1.11       agc  *    may be used to endorse or promote products derived from this software
     17      1.11       agc  *    without specific prior written permission.
     18      1.11       agc  *
     19      1.11       agc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20      1.11       agc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21      1.11       agc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22      1.11       agc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23      1.11       agc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24      1.11       agc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25      1.11       agc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26      1.11       agc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27      1.11       agc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28      1.11       agc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29      1.11       agc  * SUCH DAMAGE.
     30      1.11       agc  */
     31      1.11       agc 
     32      1.11       agc /*
     33      1.11       agc  * Copyright (c) 1997 Manuel Bouyer.
     34      1.11       agc  *
     35      1.11       agc  * Redistribution and use in source and binary forms, with or without
     36      1.11       agc  * modification, are permitted provided that the following conditions
     37      1.11       agc  * are met:
     38      1.11       agc  * 1. Redistributions of source code must retain the above copyright
     39      1.11       agc  *    notice, this list of conditions and the following disclaimer.
     40      1.11       agc  * 2. Redistributions in binary form must reproduce the above copyright
     41      1.11       agc  *    notice, this list of conditions and the following disclaimer in the
     42      1.11       agc  *    documentation and/or other materials provided with the distribution.
     43       1.1    bouyer  * 3. All advertising materials mentioning features or use of this software
     44       1.1    bouyer  *    must display the following acknowledgement:
     45      1.12    bouyer  *	This product includes software developed by Manuel Bouyer.
     46      1.12    bouyer  * 4. The name of the author may not be used to endorse or promote products
     47      1.12    bouyer  *    derived from this software without specific prior written permission.
     48       1.1    bouyer  *
     49      1.14    bouyer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     50      1.14    bouyer  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     51      1.14    bouyer  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     52      1.14    bouyer  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     53      1.14    bouyer  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     54      1.14    bouyer  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     55      1.14    bouyer  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     56      1.14    bouyer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     57      1.14    bouyer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     58      1.14    bouyer  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     59       1.1    bouyer  */
     60       1.1    bouyer 
     61       1.2     lukem #include <sys/cdefs.h>
     62       1.1    bouyer #ifndef lint
     63       1.1    bouyer #if 0
     64       1.1    bouyer static char sccsid[] = "@(#)inode.c	8.5 (Berkeley) 2/8/95";
     65       1.1    bouyer #else
     66  1.21.8.1       mjf __RCSID("$NetBSD: inode.c,v 1.21.8.2 2009/01/17 13:48:52 mjf Exp $");
     67       1.1    bouyer #endif
     68       1.1    bouyer #endif /* not lint */
     69       1.1    bouyer 
     70       1.1    bouyer #include <sys/param.h>
     71       1.1    bouyer #include <sys/time.h>
     72       1.1    bouyer #include <ufs/ext2fs/ext2fs_dinode.h>
     73       1.1    bouyer #include <ufs/ext2fs/ext2fs_dir.h>
     74       1.1    bouyer #include <ufs/ext2fs/ext2fs.h>
     75       1.1    bouyer 
     76       1.1    bouyer #include <ufs/ufs/dinode.h> /* for IFMT & friends */
     77       1.1    bouyer #ifndef SMALL
     78       1.1    bouyer #include <pwd.h>
     79       1.1    bouyer #endif
     80       1.1    bouyer #include <stdio.h>
     81       1.1    bouyer #include <stdlib.h>
     82       1.1    bouyer #include <string.h>
     83       1.4    kleink #include <time.h>
     84       1.1    bouyer 
     85       1.1    bouyer #include "fsck.h"
     86       1.1    bouyer #include "fsutil.h"
     87       1.1    bouyer #include "extern.h"
     88       1.1    bouyer 
     89       1.3    bouyer /*
     90       1.3    bouyer  * CG is stored in fs byte order in memory, so we can't use ino_to_fsba
     91       1.3    bouyer  * here.
     92       1.3    bouyer  */
     93       1.3    bouyer 
     94       1.3    bouyer #define fsck_ino_to_fsba(fs, x)                      \
     95       1.3    bouyer 	(fs2h32((fs)->e2fs_gd[ino_to_cg(fs, x)].ext2bgd_i_tables) + \
     96       1.3    bouyer 	(((x)-1) % (fs)->e2fs.e2fs_ipg)/(fs)->e2fs_ipb)
     97       1.3    bouyer 
     98       1.3    bouyer 
     99       1.1    bouyer static ino_t startinum;
    100       1.1    bouyer 
    101      1.15   xtraeme static int iblock(struct inodesc *, long, u_int64_t);
    102       1.1    bouyer 
    103      1.17        ws static int setlarge(void);
    104      1.17        ws 
    105      1.17        ws static int
    106      1.17        ws setlarge(void)
    107      1.17        ws {
    108      1.17        ws 	if (sblock.e2fs.e2fs_rev < E2FS_REV1) {
    109      1.17        ws 		pfatal("LARGE FILES UNSUPPORTED ON REVISION 0 FILESYSTEMS");
    110      1.17        ws 		return 0;
    111      1.17        ws 	}
    112      1.17        ws 	if (!(sblock.e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_LARGEFILE)) {
    113      1.17        ws 		if (preen)
    114      1.17        ws 			pwarn("SETTING LARGE FILE INDICATOR\n");
    115      1.17        ws 		else if (!reply("SET LARGE FILE INDICATOR"))
    116      1.17        ws 			return 0;
    117      1.17        ws 		sblock.e2fs.e2fs_features_rocompat |= EXT2F_ROCOMPAT_LARGEFILE;
    118      1.17        ws 		sbdirty();
    119      1.17        ws 	}
    120      1.17        ws 	return 1;
    121      1.17        ws }
    122      1.17        ws 
    123      1.17        ws u_int64_t
    124      1.17        ws inosize(struct ext2fs_dinode *dp)
    125      1.17        ws {
    126      1.17        ws 	u_int64_t size = fs2h32(dp->e2di_size);
    127      1.17        ws 
    128      1.17        ws 	if ((fs2h16(dp->e2di_mode) & IFMT) == IFREG)
    129      1.17        ws 		size |= (u_int64_t)fs2h32(dp->e2di_dacl) << 32;
    130  1.21.8.2       mjf 	if (size > INT32_MAX)
    131      1.17        ws 		(void)setlarge();
    132      1.17        ws 	return size;
    133      1.17        ws }
    134      1.17        ws 
    135      1.17        ws void
    136      1.17        ws inossize(struct ext2fs_dinode *dp, u_int64_t size)
    137      1.17        ws {
    138      1.17        ws 	if ((fs2h16(dp->e2di_mode) & IFMT) == IFREG) {
    139      1.17        ws 		dp->e2di_dacl = h2fs32(size >> 32);
    140  1.21.8.2       mjf 		if (size > INT32_MAX)
    141      1.17        ws 			if (!setlarge())
    142      1.17        ws 				return;
    143  1.21.8.2       mjf 	} else if (size > INT32_MAX) {
    144      1.17        ws 		pfatal("TRYING TO SET FILESIZE TO %llu ON MODE %x FILE\n",
    145      1.17        ws 		    (unsigned long long)size, fs2h16(dp->e2di_mode) & IFMT);
    146      1.17        ws 		return;
    147      1.17        ws 	}
    148      1.17        ws 	dp->e2di_size = h2fs32(size);
    149      1.17        ws }
    150      1.17        ws 
    151       1.1    bouyer int
    152      1.15   xtraeme ckinode(struct ext2fs_dinode *dp, struct inodesc *idesc)
    153       1.1    bouyer {
    154       1.2     lukem 	u_int32_t *ap;
    155       1.2     lukem 	long ret, n, ndb;
    156       1.1    bouyer 	struct ext2fs_dinode dino;
    157       1.1    bouyer 	u_int64_t remsize, sizepb;
    158       1.1    bouyer 	mode_t mode;
    159       1.1    bouyer 	char pathbuf[MAXPATHLEN + 1];
    160       1.1    bouyer 
    161       1.1    bouyer 	if (idesc->id_fix != IGNORE)
    162       1.1    bouyer 		idesc->id_fix = DONTKNOW;
    163       1.1    bouyer 	idesc->id_entryno = 0;
    164      1.17        ws 	idesc->id_filesize = inosize(dp);
    165       1.3    bouyer 	mode = fs2h16(dp->e2di_mode) & IFMT;
    166       1.6    bouyer 	if (mode == IFBLK || mode == IFCHR || mode == IFIFO ||
    167      1.17        ws 	    (mode == IFLNK && (inosize(dp) < EXT2_MAXSYMLINKLEN)))
    168       1.1    bouyer 		return (KEEPON);
    169       1.1    bouyer 	dino = *dp;
    170      1.17        ws 	ndb = howmany(inosize(&dino), sblock.e2fs_bsize);
    171       1.1    bouyer 	for (ap = &dino.e2di_blocks[0]; ap < &dino.e2di_blocks[NDADDR];
    172  1.21.8.2       mjf 	    ap++,ndb--) {
    173       1.1    bouyer 		idesc->id_numfrags = 1;
    174       1.1    bouyer 		if (*ap == 0) {
    175       1.1    bouyer 			if (idesc->id_type == DATA && ndb > 0) {
    176       1.1    bouyer 				/* An empty block in a directory XXX */
    177      1.10    itojun 				getpathname(pathbuf, sizeof(pathbuf),
    178      1.10    itojun 				    idesc->id_number, idesc->id_number);
    179       1.1    bouyer 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
    180       1.1    bouyer 				    pathbuf);
    181       1.1    bouyer 				if (reply("ADJUST LENGTH") == 1) {
    182       1.1    bouyer 					dp = ginode(idesc->id_number);
    183      1.17        ws 					inossize(dp,
    184      1.17        ws 					    (ap - &dino.e2di_blocks[0]) *
    185       1.3    bouyer 					    sblock.e2fs_bsize);
    186       1.1    bouyer 					printf(
    187       1.1    bouyer 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
    188       1.1    bouyer 					rerun = 1;
    189       1.1    bouyer 					inodirty();
    190       1.1    bouyer 				}
    191       1.1    bouyer 			}
    192       1.1    bouyer 			continue;
    193       1.1    bouyer 		}
    194       1.3    bouyer 		idesc->id_blkno = fs2h32(*ap);
    195       1.1    bouyer 		if (idesc->id_type == ADDR)
    196       1.1    bouyer 			ret = (*idesc->id_func)(idesc);
    197       1.1    bouyer 		else
    198       1.1    bouyer 			ret = dirscan(idesc);
    199       1.1    bouyer 		if (ret & STOP)
    200       1.1    bouyer 			return (ret);
    201       1.1    bouyer 	}
    202       1.1    bouyer 	idesc->id_numfrags = 1;
    203      1.17        ws 	remsize = inosize(&dino) - sblock.e2fs_bsize * NDADDR;
    204       1.1    bouyer 	sizepb = sblock.e2fs_bsize;
    205       1.1    bouyer 	for (ap = &dino.e2di_blocks[NDADDR], n = 1; n <= NIADDR; ap++, n++) {
    206       1.1    bouyer 		if (*ap) {
    207       1.3    bouyer 			idesc->id_blkno = fs2h32(*ap);
    208       1.1    bouyer 			ret = iblock(idesc, n, remsize);
    209       1.1    bouyer 			if (ret & STOP)
    210       1.1    bouyer 				return (ret);
    211       1.1    bouyer 		} else {
    212       1.1    bouyer 			if (idesc->id_type == DATA && remsize > 0) {
    213       1.1    bouyer 				/* An empty block in a directory XXX */
    214      1.10    itojun 				getpathname(pathbuf, sizeof(pathbuf),
    215      1.10    itojun 				    idesc->id_number, idesc->id_number);
    216       1.1    bouyer 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
    217       1.1    bouyer 				    pathbuf);
    218       1.1    bouyer 				if (reply("ADJUST LENGTH") == 1) {
    219       1.1    bouyer 					dp = ginode(idesc->id_number);
    220      1.17        ws 					inossize(dp, inosize(dp) - remsize);
    221       1.1    bouyer 					remsize = 0;
    222       1.1    bouyer 					printf(
    223       1.1    bouyer 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
    224       1.1    bouyer 					rerun = 1;
    225       1.1    bouyer 					inodirty();
    226       1.1    bouyer 					break;
    227       1.1    bouyer 				}
    228       1.1    bouyer 			}
    229       1.1    bouyer 		}
    230       1.1    bouyer 		sizepb *= NINDIR(&sblock);
    231       1.1    bouyer 		remsize -= sizepb;
    232       1.1    bouyer 	}
    233       1.1    bouyer 	return (KEEPON);
    234       1.1    bouyer }
    235       1.1    bouyer 
    236       1.1    bouyer static int
    237      1.15   xtraeme iblock(struct inodesc *idesc, long ilevel, u_int64_t isize)
    238       1.1    bouyer {
    239       1.9      fvdl 	/* XXX ondisk32 */
    240       1.9      fvdl 	int32_t *ap;
    241       1.9      fvdl 	int32_t *aplim;
    242       1.2     lukem 	struct bufarea *bp;
    243      1.16   xtraeme 	int i, n, (*func)(struct inodesc *), nif;
    244       1.1    bouyer 	u_int64_t sizepb;
    245       1.1    bouyer 	char buf[BUFSIZ];
    246       1.1    bouyer 	char pathbuf[MAXPATHLEN + 1];
    247       1.1    bouyer 	struct ext2fs_dinode *dp;
    248       1.1    bouyer 
    249       1.1    bouyer 	if (idesc->id_type == ADDR) {
    250       1.1    bouyer 		func = idesc->id_func;
    251       1.1    bouyer 		if (((n = (*func)(idesc)) & KEEPON) == 0)
    252       1.1    bouyer 			return (n);
    253       1.1    bouyer 	} else
    254       1.1    bouyer 		func = dirscan;
    255       1.1    bouyer 	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
    256       1.1    bouyer 		return (SKIP);
    257       1.1    bouyer 	bp = getdatablk(idesc->id_blkno, sblock.e2fs_bsize);
    258       1.1    bouyer 	ilevel--;
    259       1.1    bouyer 	for (sizepb = sblock.e2fs_bsize, i = 0; i < ilevel; i++)
    260       1.1    bouyer 		sizepb *= NINDIR(&sblock);
    261       1.1    bouyer 	if (isize > sizepb * NINDIR(&sblock))
    262       1.1    bouyer 		nif = NINDIR(&sblock);
    263       1.1    bouyer 	else
    264       1.1    bouyer 		nif = howmany(isize, sizepb);
    265       1.1    bouyer 	if (idesc->id_func == pass1check &&
    266       1.1    bouyer 		nif < NINDIR(&sblock)) {
    267       1.1    bouyer 		aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
    268       1.1    bouyer 		for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
    269       1.1    bouyer 			if (*ap == 0)
    270       1.1    bouyer 				continue;
    271       1.5   mycroft 			(void)snprintf(buf, sizeof(buf),
    272      1.20  christos 			    "PARTIALLY TRUNCATED INODE I=%llu",
    273      1.20  christos 			    (unsigned long long)idesc->id_number);
    274       1.1    bouyer 			if (dofix(idesc, buf)) {
    275       1.1    bouyer 				*ap = 0;
    276       1.1    bouyer 				dirty(bp);
    277       1.1    bouyer 			}
    278       1.1    bouyer 		}
    279       1.1    bouyer 		flush(fswritefd, bp);
    280       1.1    bouyer 	}
    281       1.1    bouyer 	aplim = &bp->b_un.b_indir[nif];
    282       1.1    bouyer 	for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
    283       1.1    bouyer 		if (*ap) {
    284       1.3    bouyer 			idesc->id_blkno = fs2h32(*ap);
    285       1.1    bouyer 			if (ilevel == 0)
    286       1.1    bouyer 				n = (*func)(idesc);
    287       1.1    bouyer 			else
    288       1.1    bouyer 				n = iblock(idesc, ilevel, isize);
    289       1.1    bouyer 			if (n & STOP) {
    290       1.1    bouyer 				bp->b_flags &= ~B_INUSE;
    291       1.1    bouyer 				return (n);
    292       1.1    bouyer 			}
    293       1.1    bouyer 		} else {
    294       1.1    bouyer 			if (idesc->id_type == DATA && isize > 0) {
    295       1.1    bouyer 				/* An empty block in a directory XXX */
    296      1.10    itojun 				getpathname(pathbuf, sizeof(pathbuf),
    297      1.10    itojun 				    idesc->id_number, idesc->id_number);
    298       1.1    bouyer 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
    299       1.1    bouyer 				    pathbuf);
    300       1.1    bouyer 				if (reply("ADJUST LENGTH") == 1) {
    301       1.1    bouyer 					dp = ginode(idesc->id_number);
    302      1.17        ws 					inossize(dp, inosize(dp) - isize);
    303       1.1    bouyer 					isize = 0;
    304       1.1    bouyer 					printf(
    305       1.1    bouyer 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
    306       1.1    bouyer 					rerun = 1;
    307       1.1    bouyer 					inodirty();
    308       1.1    bouyer 					bp->b_flags &= ~B_INUSE;
    309       1.1    bouyer 					return(STOP);
    310       1.1    bouyer 				}
    311       1.1    bouyer 			}
    312       1.1    bouyer 		}
    313       1.1    bouyer 		isize -= sizepb;
    314       1.1    bouyer 	}
    315       1.1    bouyer 	bp->b_flags &= ~B_INUSE;
    316       1.1    bouyer 	return (KEEPON);
    317       1.1    bouyer }
    318       1.1    bouyer 
    319       1.1    bouyer /*
    320       1.1    bouyer  * Check that a block in a legal block number.
    321       1.1    bouyer  * Return 0 if in range, 1 if out of range.
    322       1.1    bouyer  */
    323       1.1    bouyer int
    324      1.15   xtraeme chkrange(daddr_t blk, int cnt)
    325       1.1    bouyer {
    326       1.8    bouyer 	int c, overh;
    327       1.1    bouyer 
    328  1.21.8.2       mjf 	if ((unsigned int)(blk + cnt) > maxfsblock)
    329       1.1    bouyer 		return (1);
    330       1.1    bouyer 	c = dtog(&sblock, blk);
    331       1.8    bouyer 	overh = cgoverhead(c);
    332       1.8    bouyer 	if (blk < sblock.e2fs.e2fs_bpg * c + overh +
    333       1.8    bouyer 	    sblock.e2fs.e2fs_first_dblock) {
    334       1.8    bouyer 		if ((blk + cnt) > sblock.e2fs.e2fs_bpg * c + overh +
    335       1.8    bouyer 		    sblock.e2fs.e2fs_first_dblock) {
    336       1.1    bouyer 			if (debug) {
    337       1.9      fvdl 				printf("blk %lld < cgdmin %d;",
    338       1.9      fvdl 				    (long long)blk,
    339       1.9      fvdl 				    sblock.e2fs.e2fs_bpg * c + overh +
    340       1.8    bouyer 				    sblock.e2fs.e2fs_first_dblock);
    341       1.9      fvdl 				printf(" blk + cnt %lld > cgsbase %d\n",
    342       1.9      fvdl 				    (long long)(blk + cnt),
    343       1.9      fvdl 				    sblock.e2fs.e2fs_bpg * c +
    344       1.8    bouyer 				    overh + sblock.e2fs.e2fs_first_dblock);
    345       1.1    bouyer 			}
    346       1.1    bouyer 			return (1);
    347       1.1    bouyer 		}
    348       1.1    bouyer 	} else {
    349       1.8    bouyer 		if ((blk + cnt) > sblock.e2fs.e2fs_bpg * (c + 1) + overh +
    350       1.8    bouyer 		    sblock.e2fs.e2fs_first_dblock) {
    351       1.1    bouyer 			if (debug)  {
    352       1.9      fvdl 				printf("blk %lld >= cgdmin %d;",
    353       1.9      fvdl 				    (long long)blk,
    354       1.9      fvdl 				    sblock.e2fs.e2fs_bpg * c + overh +
    355       1.8    bouyer 				    sblock.e2fs.e2fs_first_dblock);
    356       1.9      fvdl 				printf(" blk + cnt %lld > cgdmax %d\n",
    357       1.9      fvdl 				    (long long)(blk+cnt),
    358       1.9      fvdl 				    sblock.e2fs.e2fs_bpg * (c + 1) +
    359       1.8    bouyer 				    overh + sblock.e2fs.e2fs_first_dblock);
    360       1.1    bouyer 			}
    361       1.1    bouyer 			return (1);
    362       1.1    bouyer 		}
    363       1.1    bouyer 	}
    364       1.1    bouyer 	return (0);
    365       1.1    bouyer }
    366       1.1    bouyer 
    367       1.1    bouyer /*
    368       1.1    bouyer  * General purpose interface for reading inodes.
    369       1.1    bouyer  */
    370       1.1    bouyer struct ext2fs_dinode *
    371      1.15   xtraeme ginode(ino_t inumber)
    372       1.1    bouyer {
    373       1.1    bouyer 	daddr_t iblk;
    374       1.1    bouyer 
    375      1.21   tsutsui 	if ((inumber < EXT2_FIRSTINO &&
    376      1.21   tsutsui 	     inumber != EXT2_ROOTINO &&
    377      1.21   tsutsui 	     !(inumber == EXT2_RESIZEINO &&
    378      1.21   tsutsui 	       (sblock.e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE) != 0))
    379       1.1    bouyer 		|| inumber > maxino)
    380  1.21.8.1       mjf 		errexit("bad inode number %llu to ginode",
    381      1.20  christos 		    (unsigned long long)inumber);
    382       1.1    bouyer 	if (startinum == 0 ||
    383       1.1    bouyer 	    inumber < startinum || inumber >= startinum + sblock.e2fs_ipb) {
    384       1.3    bouyer 		iblk = fsck_ino_to_fsba(&sblock, inumber);
    385       1.1    bouyer 		if (pbp != 0)
    386       1.1    bouyer 			pbp->b_flags &= ~B_INUSE;
    387       1.1    bouyer 		pbp = getdatablk(iblk, sblock.e2fs_bsize);
    388       1.1    bouyer 		startinum = ((inumber -1) / sblock.e2fs_ipb) * sblock.e2fs_ipb + 1;
    389       1.1    bouyer 	}
    390       1.1    bouyer 	return (&pbp->b_un.b_dinode[(inumber-1) % sblock.e2fs_ipb]);
    391       1.1    bouyer }
    392       1.1    bouyer 
    393       1.1    bouyer /*
    394       1.1    bouyer  * Special purpose version of ginode used to optimize first pass
    395       1.1    bouyer  * over all the inodes in numerical order.
    396       1.1    bouyer  */
    397       1.1    bouyer ino_t nextino, lastinum;
    398       1.1    bouyer long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
    399       1.1    bouyer struct ext2fs_dinode *inodebuf;
    400       1.1    bouyer 
    401       1.1    bouyer struct ext2fs_dinode *
    402      1.15   xtraeme getnextinode(ino_t inumber)
    403       1.1    bouyer {
    404       1.1    bouyer 	long size;
    405       1.1    bouyer 	daddr_t dblk;
    406       1.1    bouyer 	static struct ext2fs_dinode *dp;
    407       1.1    bouyer 
    408       1.1    bouyer 	if (inumber != nextino++ || inumber > maxino)
    409  1.21.8.1       mjf 		errexit("bad inode number %llu to nextinode",
    410      1.20  christos 		    (unsigned long long)inumber);
    411       1.1    bouyer 	if (inumber >= lastinum) {
    412       1.1    bouyer 		readcnt++;
    413       1.3    bouyer 		dblk = fsbtodb(&sblock, fsck_ino_to_fsba(&sblock, lastinum));
    414       1.1    bouyer 		if (readcnt % readpercg == 0) {
    415       1.1    bouyer 			size = partialsize;
    416       1.1    bouyer 			lastinum += partialcnt;
    417       1.1    bouyer 		} else {
    418       1.1    bouyer 			size = inobufsize;
    419       1.1    bouyer 			lastinum += fullcnt;
    420       1.1    bouyer 		}
    421       1.1    bouyer 		(void)bread(fsreadfd, (char *)inodebuf, dblk, size);
    422       1.1    bouyer 		dp = inodebuf;
    423       1.1    bouyer 	}
    424       1.1    bouyer 	return (dp++);
    425       1.1    bouyer }
    426       1.1    bouyer 
    427       1.1    bouyer void
    428      1.15   xtraeme resetinodebuf(void)
    429       1.1    bouyer {
    430       1.1    bouyer 
    431       1.1    bouyer 	startinum = 0;
    432       1.1    bouyer 	nextino = 1;
    433       1.1    bouyer 	lastinum = 1;
    434       1.1    bouyer 	readcnt = 0;
    435       1.1    bouyer 	inobufsize = blkroundup(&sblock, INOBUFSIZE);
    436       1.1    bouyer 	fullcnt = inobufsize / sizeof(struct ext2fs_dinode);
    437       1.1    bouyer 	readpercg = sblock.e2fs.e2fs_ipg / fullcnt;
    438       1.1    bouyer 	partialcnt = sblock.e2fs.e2fs_ipg % fullcnt;
    439       1.1    bouyer 	partialsize = partialcnt * sizeof(struct ext2fs_dinode);
    440       1.1    bouyer 	if (partialcnt != 0) {
    441       1.1    bouyer 		readpercg++;
    442       1.1    bouyer 	} else {
    443       1.1    bouyer 		partialcnt = fullcnt;
    444       1.1    bouyer 		partialsize = inobufsize;
    445       1.1    bouyer 	}
    446       1.1    bouyer 	if (inodebuf == NULL &&
    447  1.21.8.2       mjf 	    (inodebuf = malloc((unsigned int)inobufsize)) == NULL)
    448  1.21.8.1       mjf 		errexit("Cannot allocate space for inode buffer");
    449       1.1    bouyer 	while (nextino < EXT2_ROOTINO)
    450       1.1    bouyer 		(void)getnextinode(nextino);
    451       1.1    bouyer }
    452       1.1    bouyer 
    453       1.1    bouyer void
    454      1.15   xtraeme freeinodebuf(void)
    455       1.1    bouyer {
    456       1.1    bouyer 
    457       1.1    bouyer 	if (inodebuf != NULL)
    458  1.21.8.2       mjf 		free(inodebuf);
    459       1.1    bouyer 	inodebuf = NULL;
    460       1.1    bouyer }
    461       1.1    bouyer 
    462       1.1    bouyer /*
    463       1.1    bouyer  * Routines to maintain information about directory inodes.
    464       1.1    bouyer  * This is built during the first pass and used during the
    465       1.1    bouyer  * second and third passes.
    466       1.1    bouyer  *
    467       1.1    bouyer  * Enter inodes into the cache.
    468       1.1    bouyer  */
    469       1.1    bouyer void
    470      1.15   xtraeme cacheino(struct ext2fs_dinode *dp, ino_t inumber)
    471       1.1    bouyer {
    472       1.2     lukem 	struct inoinfo *inp;
    473       1.1    bouyer 	struct inoinfo **inpp;
    474       1.1    bouyer 	unsigned int blks;
    475       1.1    bouyer 
    476      1.17        ws 	blks = howmany(inosize(dp), sblock.e2fs_bsize);
    477       1.1    bouyer 	if (blks > NDADDR)
    478       1.1    bouyer 		blks = NDADDR + NIADDR;
    479       1.9      fvdl 	/* XXX ondisk32 */
    480  1.21.8.2       mjf 	inp = malloc(sizeof(*inp) + (blks - 1) * sizeof(int32_t));
    481       1.1    bouyer 	if (inp == NULL)
    482       1.1    bouyer 		return;
    483       1.1    bouyer 	inpp = &inphead[inumber % numdirs];
    484       1.1    bouyer 	inp->i_nexthash = *inpp;
    485       1.1    bouyer 	*inpp = inp;
    486       1.1    bouyer 	inp->i_child = inp->i_sibling = inp->i_parentp = 0;
    487       1.1    bouyer 	if (inumber == EXT2_ROOTINO)
    488       1.1    bouyer 		inp->i_parent = EXT2_ROOTINO;
    489       1.1    bouyer 	else
    490       1.1    bouyer 		inp->i_parent = (ino_t)0;
    491       1.1    bouyer 	inp->i_dotdot = (ino_t)0;
    492       1.1    bouyer 	inp->i_number = inumber;
    493      1.17        ws 	inp->i_isize = inosize(dp);
    494       1.9      fvdl 	/* XXX ondisk32 */
    495       1.9      fvdl 	inp->i_numblks = blks * sizeof(int32_t);
    496       1.1    bouyer 	memcpy(&inp->i_blks[0], &dp->e2di_blocks[0], (size_t)inp->i_numblks);
    497       1.1    bouyer 	if (inplast == listmax) {
    498       1.1    bouyer 		listmax += 100;
    499       1.1    bouyer 		inpsort = (struct inoinfo **)realloc((char *)inpsort,
    500  1.21.8.2       mjf 		    (unsigned int)listmax * sizeof(struct inoinfo *));
    501       1.1    bouyer 		if (inpsort == NULL)
    502  1.21.8.1       mjf 			errexit("cannot increase directory list");
    503       1.1    bouyer 	}
    504       1.1    bouyer 	inpsort[inplast++] = inp;
    505       1.1    bouyer }
    506       1.1    bouyer 
    507       1.1    bouyer /*
    508       1.1    bouyer  * Look up an inode cache structure.
    509       1.1    bouyer  */
    510       1.1    bouyer struct inoinfo *
    511      1.15   xtraeme getinoinfo(ino_t inumber)
    512       1.1    bouyer {
    513       1.2     lukem 	struct inoinfo *inp;
    514       1.1    bouyer 
    515       1.1    bouyer 	for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
    516       1.1    bouyer 		if (inp->i_number != inumber)
    517       1.1    bouyer 			continue;
    518       1.1    bouyer 		return (inp);
    519       1.1    bouyer 	}
    520  1.21.8.1       mjf 	errexit("cannot find inode %llu", (unsigned long long)inumber);
    521       1.1    bouyer 	return ((struct inoinfo *)0);
    522       1.1    bouyer }
    523       1.1    bouyer 
    524       1.1    bouyer /*
    525       1.1    bouyer  * Clean up all the inode cache structure.
    526       1.1    bouyer  */
    527       1.1    bouyer void
    528      1.15   xtraeme inocleanup(void)
    529       1.1    bouyer {
    530       1.2     lukem 	struct inoinfo **inpp;
    531       1.1    bouyer 
    532       1.1    bouyer 	if (inphead == NULL)
    533       1.1    bouyer 		return;
    534       1.1    bouyer 	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
    535  1.21.8.2       mjf 		free(*inpp);
    536  1.21.8.2       mjf 	free(inphead);
    537  1.21.8.2       mjf 	free(inpsort);
    538       1.1    bouyer 	inphead = inpsort = NULL;
    539       1.1    bouyer }
    540       1.1    bouyer 
    541       1.1    bouyer void
    542      1.15   xtraeme inodirty(void)
    543       1.1    bouyer {
    544       1.1    bouyer 
    545       1.1    bouyer 	dirty(pbp);
    546       1.1    bouyer }
    547       1.1    bouyer 
    548       1.1    bouyer void
    549      1.18  christos clri(struct inodesc *idesc, const char *type, int flag)
    550       1.1    bouyer {
    551       1.2     lukem 	struct ext2fs_dinode *dp;
    552       1.1    bouyer 
    553       1.1    bouyer 	dp = ginode(idesc->id_number);
    554       1.1    bouyer 	if (flag == 1) {
    555       1.1    bouyer 		pwarn("%s %s", type,
    556  1.21.8.2       mjf 		    (fs2h16(dp->e2di_mode) & IFMT) == IFDIR ? "DIR" : "FILE");
    557       1.1    bouyer 		pinode(idesc->id_number);
    558       1.1    bouyer 	}
    559       1.1    bouyer 	if (preen || reply("CLEAR") == 1) {
    560       1.1    bouyer 		if (preen)
    561       1.1    bouyer 			printf(" (CLEARED)\n");
    562       1.1    bouyer 		n_files--;
    563       1.1    bouyer 		(void)ckinode(dp, idesc);
    564       1.1    bouyer 		clearinode(dp);
    565       1.1    bouyer 		statemap[idesc->id_number] = USTATE;
    566       1.1    bouyer 		inodirty();
    567       1.1    bouyer 	}
    568       1.1    bouyer }
    569       1.1    bouyer 
    570       1.1    bouyer int
    571      1.15   xtraeme findname(struct inodesc *idesc)
    572       1.1    bouyer {
    573       1.2     lukem 	struct ext2fs_direct *dirp = idesc->id_dirp;
    574       1.7    bouyer 	u_int16_t namlen = dirp->e2d_namlen;
    575      1.18  christos 	/* from utilities.c namebuf[] variable */
    576      1.18  christos 	char *buf = __UNCONST(idesc->id_name);
    577      1.18  christos 	if (namlen > MAXPATHLEN) {
    578      1.18  christos 		/* XXX: Prevent overflow but don't fix */
    579      1.18  christos 		namlen = MAXPATHLEN;
    580      1.18  christos 	}
    581       1.1    bouyer 
    582       1.3    bouyer 	if (fs2h32(dirp->e2d_ino) != idesc->id_parent)
    583       1.1    bouyer 		return (KEEPON);
    584      1.18  christos 	(void)memcpy(buf, dirp->e2d_name, (size_t)namlen);
    585      1.18  christos 	buf[namlen] = '\0';
    586       1.1    bouyer 	return (STOP|FOUND);
    587       1.1    bouyer }
    588       1.1    bouyer 
    589       1.1    bouyer int
    590      1.15   xtraeme findino(struct inodesc *idesc)
    591       1.1    bouyer {
    592       1.2     lukem 	struct ext2fs_direct *dirp = idesc->id_dirp;
    593       1.3    bouyer 	u_int32_t ino = fs2h32(dirp->e2d_ino);
    594       1.1    bouyer 
    595       1.3    bouyer 	if (ino == 0)
    596       1.1    bouyer 		return (KEEPON);
    597       1.1    bouyer 	if (strcmp(dirp->e2d_name, idesc->id_name) == 0 &&
    598       1.3    bouyer 	    (ino == EXT2_ROOTINO || ino >= EXT2_FIRSTINO)
    599       1.3    bouyer 		&& ino <= maxino) {
    600       1.3    bouyer 		idesc->id_parent = ino;
    601       1.1    bouyer 		return (STOP|FOUND);
    602       1.1    bouyer 	}
    603       1.1    bouyer 	return (KEEPON);
    604       1.1    bouyer }
    605       1.1    bouyer 
    606       1.1    bouyer void
    607      1.15   xtraeme pinode(ino_t ino)
    608       1.1    bouyer {
    609       1.2     lukem 	struct ext2fs_dinode *dp;
    610       1.2     lukem 	char *p;
    611       1.1    bouyer 	struct passwd *pw;
    612       1.1    bouyer 	time_t t;
    613  1.21.8.2       mjf 	uid_t uid;
    614       1.1    bouyer 
    615      1.20  christos 	printf(" I=%llu ", (unsigned long long)ino);
    616       1.1    bouyer 	if ((ino < EXT2_FIRSTINO && ino != EXT2_ROOTINO) || ino > maxino)
    617       1.1    bouyer 		return;
    618       1.1    bouyer 	dp = ginode(ino);
    619  1.21.8.2       mjf 	uid = fs2h16(dp->e2di_uid);
    620  1.21.8.2       mjf 	if (sblock.e2fs.e2fs_rev > E2FS_REV0)
    621  1.21.8.2       mjf 		uid |= fs2h16(dp->e2di_uid_high) << 16;
    622       1.1    bouyer 	printf(" OWNER=");
    623       1.1    bouyer #ifndef SMALL
    624  1.21.8.2       mjf 	if (Uflag && (pw = getpwuid(uid)) != 0)
    625       1.1    bouyer 		printf("%s ", pw->pw_name);
    626       1.1    bouyer 	else
    627       1.1    bouyer #endif
    628  1.21.8.2       mjf 		printf("%u ", (unsigned int)uid);
    629       1.3    bouyer 	printf("MODE=%o\n", fs2h16(dp->e2di_mode));
    630       1.1    bouyer 	if (preen)
    631       1.1    bouyer 		printf("%s: ", cdevname());
    632      1.17        ws 	printf("SIZE=%llu ", (long long)inosize(dp));
    633       1.3    bouyer 	t = fs2h32(dp->e2di_mtime);
    634       1.1    bouyer 	p = ctime(&t);
    635       1.1    bouyer 	printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
    636       1.1    bouyer }
    637       1.1    bouyer 
    638       1.1    bouyer void
    639      1.19  christos blkerror(ino_t ino, const char *type, daddr_t blk)
    640       1.1    bouyer {
    641       1.1    bouyer 
    642      1.20  christos 	pfatal("%lld %s I=%llu", (long long)blk, type, (unsigned long long)ino);
    643       1.1    bouyer 	printf("\n");
    644       1.1    bouyer 	switch (statemap[ino]) {
    645       1.1    bouyer 
    646       1.1    bouyer 	case FSTATE:
    647       1.1    bouyer 		statemap[ino] = FCLEAR;
    648       1.1    bouyer 		return;
    649       1.1    bouyer 
    650       1.1    bouyer 	case DSTATE:
    651       1.1    bouyer 		statemap[ino] = DCLEAR;
    652       1.1    bouyer 		return;
    653       1.1    bouyer 
    654       1.1    bouyer 	case FCLEAR:
    655       1.1    bouyer 	case DCLEAR:
    656       1.1    bouyer 		return;
    657       1.1    bouyer 
    658       1.1    bouyer 	default:
    659  1.21.8.1       mjf 		errexit("BAD STATE %d TO BLKERR", statemap[ino]);
    660       1.1    bouyer 		/* NOTREACHED */
    661       1.1    bouyer 	}
    662       1.1    bouyer }
    663       1.1    bouyer 
    664       1.1    bouyer /*
    665       1.1    bouyer  * allocate an unused inode
    666       1.1    bouyer  */
    667       1.1    bouyer ino_t
    668      1.15   xtraeme allocino(ino_t request, int type)
    669       1.1    bouyer {
    670       1.2     lukem 	ino_t ino;
    671       1.2     lukem 	struct ext2fs_dinode *dp;
    672       1.1    bouyer 	time_t t;
    673       1.1    bouyer 
    674       1.1    bouyer 	if (request == 0)
    675       1.1    bouyer 		request = EXT2_ROOTINO;
    676       1.1    bouyer 	else if (statemap[request] != USTATE)
    677       1.1    bouyer 		return (0);
    678       1.1    bouyer 	for (ino = request; ino < maxino; ino++) {
    679       1.1    bouyer 		if ((ino > EXT2_ROOTINO) && (ino < EXT2_FIRSTINO))
    680       1.1    bouyer 			continue;
    681       1.1    bouyer 		if (statemap[ino] == USTATE)
    682       1.1    bouyer 			break;
    683       1.1    bouyer 	}
    684       1.1    bouyer 	if (ino == maxino)
    685       1.1    bouyer 		return (0);
    686       1.1    bouyer 	switch (type & IFMT) {
    687       1.1    bouyer 	case IFDIR:
    688       1.1    bouyer 		statemap[ino] = DSTATE;
    689       1.1    bouyer 		break;
    690       1.1    bouyer 	case IFREG:
    691       1.1    bouyer 	case IFLNK:
    692       1.1    bouyer 		statemap[ino] = FSTATE;
    693       1.1    bouyer 		break;
    694       1.1    bouyer 	default:
    695       1.1    bouyer 		return (0);
    696       1.1    bouyer 	}
    697       1.1    bouyer 	dp = ginode(ino);
    698       1.3    bouyer 	dp->e2di_blocks[0] = h2fs32(allocblk());
    699       1.1    bouyer 	if (dp->e2di_blocks[0] == 0) {
    700       1.1    bouyer 		statemap[ino] = USTATE;
    701       1.1    bouyer 		return (0);
    702       1.1    bouyer 	}
    703       1.3    bouyer 	dp->e2di_mode = h2fs16(type);
    704       1.1    bouyer 	(void)time(&t);
    705       1.3    bouyer 	dp->e2di_atime = h2fs32(t);
    706       1.1    bouyer 	dp->e2di_mtime = dp->e2di_ctime = dp->e2di_atime;
    707       1.1    bouyer 	dp->e2di_dtime = 0;
    708      1.17        ws 	inossize(dp, sblock.e2fs_bsize);
    709       1.3    bouyer 	dp->e2di_nblock = h2fs32(btodb(sblock.e2fs_bsize));
    710       1.1    bouyer 	n_files++;
    711       1.1    bouyer 	inodirty();
    712       1.8    bouyer 	typemap[ino] = E2IFTODT(type);
    713       1.1    bouyer 	return (ino);
    714       1.1    bouyer }
    715       1.1    bouyer 
    716       1.1    bouyer /*
    717       1.1    bouyer  * deallocate an inode
    718       1.1    bouyer  */
    719       1.1    bouyer void
    720      1.15   xtraeme freeino(ino_t ino)
    721       1.1    bouyer {
    722       1.1    bouyer 	struct inodesc idesc;
    723       1.1    bouyer 	struct ext2fs_dinode *dp;
    724       1.1    bouyer 
    725       1.1    bouyer 	memset(&idesc, 0, sizeof(struct inodesc));
    726       1.1    bouyer 	idesc.id_type = ADDR;
    727       1.1    bouyer 	idesc.id_func = pass4check;
    728       1.1    bouyer 	idesc.id_number = ino;
    729       1.1    bouyer 	dp = ginode(ino);
    730       1.1    bouyer 	(void)ckinode(dp, &idesc);
    731       1.1    bouyer 	clearinode(dp);
    732       1.1    bouyer 	inodirty();
    733       1.1    bouyer 	statemap[ino] = USTATE;
    734       1.1    bouyer 	n_files--;
    735       1.1    bouyer }
    736