1  | 
     | 
     | 
    /*	$OpenBSD: inode.c,v 1.48 2016/12/16 17:44:59 krw Exp $	*/  | 
    
    
    2  | 
     | 
     | 
    /*	$NetBSD: inode.c,v 1.23 1996/10/11 20:15:47 thorpej Exp $	*/  | 
    
    
    3  | 
     | 
     | 
     | 
    
    
    4  | 
     | 
     | 
    /*  | 
    
    
    5  | 
     | 
     | 
     * Copyright (c) 1980, 1986, 1993  | 
    
    
    6  | 
     | 
     | 
     *	The Regents of the University of California.  All rights reserved.  | 
    
    
    7  | 
     | 
     | 
     *  | 
    
    
    8  | 
     | 
     | 
     * Redistribution and use in source and binary forms, with or without  | 
    
    
    9  | 
     | 
     | 
     * modification, are permitted provided that the following conditions  | 
    
    
    10  | 
     | 
     | 
     * are met:  | 
    
    
    11  | 
     | 
     | 
     * 1. Redistributions of source code must retain the above copyright  | 
    
    
    12  | 
     | 
     | 
     *    notice, this list of conditions and the following disclaimer.  | 
    
    
    13  | 
     | 
     | 
     * 2. Redistributions in binary form must reproduce the above copyright  | 
    
    
    14  | 
     | 
     | 
     *    notice, this list of conditions and the following disclaimer in the  | 
    
    
    15  | 
     | 
     | 
     *    documentation and/or other materials provided with the distribution.  | 
    
    
    16  | 
     | 
     | 
     * 3. Neither the name of the University nor the names of its contributors  | 
    
    
    17  | 
     | 
     | 
     *    may be used to endorse or promote products derived from this software  | 
    
    
    18  | 
     | 
     | 
     *    without specific prior written permission.  | 
    
    
    19  | 
     | 
     | 
     *  | 
    
    
    20  | 
     | 
     | 
     * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND  | 
    
    
    21  | 
     | 
     | 
     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  | 
    
    
    22  | 
     | 
     | 
     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  | 
    
    
    23  | 
     | 
     | 
     * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE  | 
    
    
    24  | 
     | 
     | 
     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  | 
    
    
    25  | 
     | 
     | 
     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  | 
    
    
    26  | 
     | 
     | 
     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  | 
    
    
    27  | 
     | 
     | 
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  | 
    
    
    28  | 
     | 
     | 
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  | 
    
    
    29  | 
     | 
     | 
     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  | 
    
    
    30  | 
     | 
     | 
     * SUCH DAMAGE.  | 
    
    
    31  | 
     | 
     | 
     */  | 
    
    
    32  | 
     | 
     | 
     | 
    
    
    33  | 
     | 
     | 
    #include <sys/param.h>	/* setbit btodb */  | 
    
    
    34  | 
     | 
     | 
    #include <sys/time.h>  | 
    
    
    35  | 
     | 
     | 
    #include <ufs/ufs/dinode.h>  | 
    
    
    36  | 
     | 
     | 
    #include <ufs/ufs/dir.h>  | 
    
    
    37  | 
     | 
     | 
    #include <ufs/ffs/fs.h>  | 
    
    
    38  | 
     | 
     | 
    #ifndef SMALL  | 
    
    
    39  | 
     | 
     | 
    #include <pwd.h>  | 
    
    
    40  | 
     | 
     | 
    #endif  | 
    
    
    41  | 
     | 
     | 
    #include <stdio.h>  | 
    
    
    42  | 
     | 
     | 
    #include <stdlib.h>  | 
    
    
    43  | 
     | 
     | 
    #include <string.h>  | 
    
    
    44  | 
     | 
     | 
    #include <unistd.h>  | 
    
    
    45  | 
     | 
     | 
    #include <limits.h>  | 
    
    
    46  | 
     | 
     | 
     | 
    
    
    47  | 
     | 
     | 
    #include "fsck.h"  | 
    
    
    48  | 
     | 
     | 
    #include "fsutil.h"  | 
    
    
    49  | 
     | 
     | 
    #include "extern.h"  | 
    
    
    50  | 
     | 
     | 
     | 
    
    
    51  | 
     | 
     | 
    #define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))  | 
    
    
    52  | 
     | 
     | 
    #define MAXIMUM(a, b)	(((a) > (b)) ? (a) : (b))  | 
    
    
    53  | 
     | 
     | 
     | 
    
    
    54  | 
     | 
     | 
    static ino_t startinum;  | 
    
    
    55  | 
     | 
     | 
     | 
    
    
    56  | 
     | 
     | 
    static int iblock(struct inodesc *, long, off_t);  | 
    
    
    57  | 
     | 
     | 
     | 
    
    
    58  | 
     | 
     | 
    int  | 
    
    
    59  | 
     | 
     | 
    ckinode(union dinode *dp, struct inodesc *idesc)  | 
    
    
    60  | 
     | 
     | 
    { | 
    
    
    61  | 
     | 
     | 
    	long ret, ndb, offset;  | 
    
    
    62  | 
     | 
     | 
    	union dinode dino;  | 
    
    
    63  | 
     | 
     | 
    	off_t sizepb, remsize;  | 
    
    
    64  | 
     | 
     | 
    	mode_t mode;  | 
    
    
    65  | 
     | 
     | 
    	int i;  | 
    
    
    66  | 
     | 
     | 
    	char pathbuf[PATH_MAX + 1];  | 
    
    
    67  | 
     | 
     | 
     | 
    
    
    68  | 
     | 
     | 
    	if (idesc->id_fix != IGNORE)  | 
    
    
    69  | 
     | 
     | 
    		idesc->id_fix = DONTKNOW;  | 
    
    
    70  | 
     | 
     | 
    	idesc->id_entryno = 0;  | 
    
    
    71  | 
     | 
     | 
    	idesc->id_filesize = DIP(dp, di_size);  | 
    
    
    72  | 
     | 
     | 
    	mode = DIP(dp, di_mode) & IFMT;  | 
    
    
    73  | 
     | 
     | 
    	if (mode == IFBLK || mode == IFCHR || (mode == IFLNK &&  | 
    
    
    74  | 
     | 
     | 
    	    (DIP(dp, di_size) < sblock.fs_maxsymlinklen ||  | 
    
    
    75  | 
     | 
     | 
    	     (sblock.fs_maxsymlinklen == 0 && DIP(dp, di_blocks) == 0))))  | 
    
    
    76  | 
     | 
     | 
    		return (KEEPON);  | 
    
    
    77  | 
     | 
     | 
    	if (sblock.fs_magic == FS_UFS1_MAGIC)  | 
    
    
    78  | 
     | 
     | 
    		dino.dp1 = dp->dp1;  | 
    
    
    79  | 
     | 
     | 
    	else  | 
    
    
    80  | 
     | 
     | 
    		dino.dp2 = dp->dp2;  | 
    
    
    81  | 
     | 
     | 
    	ndb = howmany(DIP(&dino, di_size), sblock.fs_bsize);  | 
    
    
    82  | 
     | 
     | 
    	for (i = 0; i < NDADDR; i++) { | 
    
    
    83  | 
     | 
     | 
    		if (--ndb == 0 && (offset = blkoff(&sblock,  | 
    
    
    84  | 
     | 
     | 
    		    DIP(&dino, di_size))) != 0)  | 
    
    
    85  | 
     | 
     | 
    			idesc->id_numfrags =  | 
    
    
    86  | 
     | 
     | 
    				numfrags(&sblock, fragroundup(&sblock, offset));  | 
    
    
    87  | 
     | 
     | 
    		else  | 
    
    
    88  | 
     | 
     | 
    			idesc->id_numfrags = sblock.fs_frag;  | 
    
    
    89  | 
     | 
     | 
    		if (DIP(&dino, di_db[i]) == 0) { | 
    
    
    90  | 
     | 
     | 
    			if (idesc->id_type == DATA && ndb >= 0) { | 
    
    
    91  | 
     | 
     | 
    				/* An empty block in a directory XXX */  | 
    
    
    92  | 
     | 
     | 
    				getpathname(pathbuf, sizeof pathbuf,  | 
    
    
    93  | 
     | 
     | 
    				    idesc->id_number, idesc->id_number);  | 
    
    
    94  | 
     | 
     | 
    				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", | 
    
    
    95  | 
     | 
     | 
    				    pathbuf);  | 
    
    
    96  | 
     | 
     | 
    				if (reply("ADJUST LENGTH") == 1) { | 
    
    
    97  | 
     | 
     | 
    					dp = ginode(idesc->id_number);  | 
    
    
    98  | 
     | 
     | 
    					DIP_SET(dp, di_size,  | 
    
    
    99  | 
     | 
     | 
    					    i * sblock.fs_bsize);  | 
    
    
    100  | 
     | 
     | 
    					printf(  | 
    
    
    101  | 
     | 
     | 
    					    "YOU MUST RERUN FSCK AFTERWARDS\n");  | 
    
    
    102  | 
     | 
     | 
    					rerun = 1;  | 
    
    
    103  | 
     | 
     | 
    					inodirty();  | 
    
    
    104  | 
     | 
     | 
    				}  | 
    
    
    105  | 
     | 
     | 
    			}  | 
    
    
    106  | 
     | 
     | 
    			continue;  | 
    
    
    107  | 
     | 
     | 
    		}  | 
    
    
    108  | 
     | 
     | 
    		idesc->id_blkno = DIP(&dino, di_db[i]);  | 
    
    
    109  | 
     | 
     | 
    		if (idesc->id_type == ADDR)  | 
    
    
    110  | 
     | 
     | 
    			ret = (*idesc->id_func)(idesc);  | 
    
    
    111  | 
     | 
     | 
    		else  | 
    
    
    112  | 
     | 
     | 
    			ret = dirscan(idesc);  | 
    
    
    113  | 
     | 
     | 
    		if (ret & STOP)  | 
    
    
    114  | 
     | 
     | 
    			return (ret);  | 
    
    
    115  | 
     | 
     | 
    	}  | 
    
    
    116  | 
     | 
     | 
    	idesc->id_numfrags = sblock.fs_frag;  | 
    
    
    117  | 
     | 
     | 
    	remsize = DIP(&dino, di_size) - sblock.fs_bsize * NDADDR;  | 
    
    
    118  | 
     | 
     | 
    	sizepb = sblock.fs_bsize;  | 
    
    
    119  | 
     | 
     | 
    	for (i = 0; i < NIADDR; i++) { | 
    
    
    120  | 
     | 
     | 
    		if (DIP(&dino, di_ib[i])) { | 
    
    
    121  | 
     | 
     | 
    			idesc->id_blkno = DIP(&dino, di_ib[i]);  | 
    
    
    122  | 
     | 
     | 
    			ret = iblock(idesc, i + 1, remsize);  | 
    
    
    123  | 
     | 
     | 
    			if (ret & STOP)  | 
    
    
    124  | 
     | 
     | 
    				return (ret);  | 
    
    
    125  | 
     | 
     | 
    		} else { | 
    
    
    126  | 
     | 
     | 
    			if (idesc->id_type == DATA && remsize > 0) { | 
    
    
    127  | 
     | 
     | 
    				/* An empty block in a directory XXX */  | 
    
    
    128  | 
     | 
     | 
    				getpathname(pathbuf, sizeof pathbuf,  | 
    
    
    129  | 
     | 
     | 
    				    idesc->id_number, idesc->id_number);  | 
    
    
    130  | 
     | 
     | 
    				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", | 
    
    
    131  | 
     | 
     | 
    				    pathbuf);  | 
    
    
    132  | 
     | 
     | 
    				if (reply("ADJUST LENGTH") == 1) { | 
    
    
    133  | 
     | 
     | 
    					dp = ginode(idesc->id_number);  | 
    
    
    134  | 
     | 
     | 
    					DIP_SET(dp, di_size,  | 
    
    
    135  | 
     | 
     | 
    					     DIP(dp, di_size) - remsize);  | 
    
    
    136  | 
     | 
     | 
    					remsize = 0;  | 
    
    
    137  | 
     | 
     | 
    					printf(  | 
    
    
    138  | 
     | 
     | 
    					    "YOU MUST RERUN FSCK AFTERWARDS\n");  | 
    
    
    139  | 
     | 
     | 
    					rerun = 1;  | 
    
    
    140  | 
     | 
     | 
    					inodirty();  | 
    
    
    141  | 
     | 
     | 
    					break;  | 
    
    
    142  | 
     | 
     | 
    				}  | 
    
    
    143  | 
     | 
     | 
    			}  | 
    
    
    144  | 
     | 
     | 
    		}  | 
    
    
    145  | 
     | 
     | 
    		sizepb *= NINDIR(&sblock);  | 
    
    
    146  | 
     | 
     | 
    		remsize -= sizepb;  | 
    
    
    147  | 
     | 
     | 
    	}  | 
    
    
    148  | 
     | 
     | 
    	return (KEEPON);  | 
    
    
    149  | 
     | 
     | 
    }  | 
    
    
    150  | 
     | 
     | 
     | 
    
    
    151  | 
     | 
     | 
    static int  | 
    
    
    152  | 
     | 
     | 
    iblock(struct inodesc *idesc, long ilevel, off_t isize)  | 
    
    
    153  | 
     | 
     | 
    { | 
    
    
    154  | 
     | 
     | 
    	struct bufarea *bp;  | 
    
    
    155  | 
     | 
     | 
    	int i, n, (*func)(struct inodesc *), nif;  | 
    
    
    156  | 
     | 
     | 
    	off_t sizepb;  | 
    
    
    157  | 
     | 
     | 
    	char buf[BUFSIZ];  | 
    
    
    158  | 
     | 
     | 
    	char pathbuf[PATH_MAX + 1];  | 
    
    
    159  | 
     | 
     | 
    	union dinode *dp;  | 
    
    
    160  | 
     | 
     | 
     | 
    
    
    161  | 
     | 
     | 
    	if (idesc->id_type == ADDR) { | 
    
    
    162  | 
     | 
     | 
    		func = idesc->id_func;  | 
    
    
    163  | 
     | 
     | 
    		if (((n = (*func)(idesc)) & KEEPON) == 0)  | 
    
    
    164  | 
     | 
     | 
    			return (n);  | 
    
    
    165  | 
     | 
     | 
    	} else  | 
    
    
    166  | 
     | 
     | 
    		func = dirscan;  | 
    
    
    167  | 
     | 
     | 
    	if (isize < 0 || chkrange(idesc->id_blkno, idesc->id_numfrags))  | 
    
    
    168  | 
     | 
     | 
    		return (SKIP);  | 
    
    
    169  | 
     | 
     | 
    	bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);  | 
    
    
    170  | 
     | 
     | 
    	ilevel--;  | 
    
    
    171  | 
     | 
     | 
    	for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)  | 
    
    
    172  | 
     | 
     | 
    		sizepb *= NINDIR(&sblock);  | 
    
    
    173  | 
     | 
     | 
    	if (howmany(isize, sizepb) > NINDIR(&sblock))  | 
    
    
    174  | 
     | 
     | 
    		nif = NINDIR(&sblock);  | 
    
    
    175  | 
     | 
     | 
    	else  | 
    
    
    176  | 
     | 
     | 
    		nif = howmany(isize, sizepb);  | 
    
    
    177  | 
     | 
     | 
    	if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) { | 
    
    
    178  | 
     | 
     | 
    		for (i = nif; i < NINDIR(&sblock); i++) { | 
    
    
    179  | 
     | 
     | 
    			if (IBLK(bp, i) == 0)  | 
    
    
    180  | 
     | 
     | 
    				continue;  | 
    
    
    181  | 
     | 
     | 
    			(void)snprintf(buf, sizeof buf,  | 
    
    
    182  | 
     | 
     | 
    			    "PARTIALLY TRUNCATED INODE I=%llu",  | 
    
    
    183  | 
     | 
     | 
    			    (unsigned long long)idesc->id_number);  | 
    
    
    184  | 
     | 
     | 
    			if (preen)  | 
    
    
    185  | 
     | 
     | 
    				pfatal("%s", buf); | 
    
    
    186  | 
     | 
     | 
    			else if (dofix(idesc, buf)) { | 
    
    
    187  | 
     | 
     | 
    				IBLK_SET(bp, i, 0);  | 
    
    
    188  | 
     | 
     | 
    				dirty(bp);  | 
    
    
    189  | 
     | 
     | 
    			}  | 
    
    
    190  | 
     | 
     | 
    		}  | 
    
    
    191  | 
     | 
     | 
    		flush(fswritefd, bp);  | 
    
    
    192  | 
     | 
     | 
    	}  | 
    
    
    193  | 
     | 
     | 
    	for (i = 0; i < nif; i++) { | 
    
    
    194  | 
     | 
     | 
    		if (IBLK(bp, i)) { | 
    
    
    195  | 
     | 
     | 
    			idesc->id_blkno = IBLK(bp, i);  | 
    
    
    196  | 
     | 
     | 
    			if (ilevel == 0)  | 
    
    
    197  | 
     | 
     | 
    				n = (*func)(idesc);  | 
    
    
    198  | 
     | 
     | 
    			else  | 
    
    
    199  | 
     | 
     | 
    				n = iblock(idesc, ilevel, isize);  | 
    
    
    200  | 
     | 
     | 
    			if (n & STOP) { | 
    
    
    201  | 
     | 
     | 
    				bp->b_flags &= ~B_INUSE;  | 
    
    
    202  | 
     | 
     | 
    				return (n);  | 
    
    
    203  | 
     | 
     | 
    			}  | 
    
    
    204  | 
     | 
     | 
    		} else { | 
    
    
    205  | 
     | 
     | 
    			if (idesc->id_type == DATA && isize > 0) { | 
    
    
    206  | 
     | 
     | 
    				/* An empty block in a directory XXX */  | 
    
    
    207  | 
     | 
     | 
    				getpathname(pathbuf, sizeof pathbuf,  | 
    
    
    208  | 
     | 
     | 
    				    idesc->id_number, idesc->id_number);  | 
    
    
    209  | 
     | 
     | 
    				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", | 
    
    
    210  | 
     | 
     | 
    				    pathbuf);  | 
    
    
    211  | 
     | 
     | 
    				if (reply("ADJUST LENGTH") == 1) { | 
    
    
    212  | 
     | 
     | 
    					dp = ginode(idesc->id_number);  | 
    
    
    213  | 
     | 
     | 
    					DIP_SET(dp, di_size,  | 
    
    
    214  | 
     | 
     | 
    					    DIP(dp, di_size) - isize);  | 
    
    
    215  | 
     | 
     | 
    					isize = 0;  | 
    
    
    216  | 
     | 
     | 
    					printf(  | 
    
    
    217  | 
     | 
     | 
    					    "YOU MUST RERUN FSCK AFTERWARDS\n");  | 
    
    
    218  | 
     | 
     | 
    					rerun = 1;  | 
    
    
    219  | 
     | 
     | 
    					inodirty();  | 
    
    
    220  | 
     | 
     | 
    					bp->b_flags &= ~B_INUSE;  | 
    
    
    221  | 
     | 
     | 
    					return(STOP);  | 
    
    
    222  | 
     | 
     | 
    				}  | 
    
    
    223  | 
     | 
     | 
    			}  | 
    
    
    224  | 
     | 
     | 
    		}  | 
    
    
    225  | 
     | 
     | 
    		isize -= sizepb;  | 
    
    
    226  | 
     | 
     | 
    	}  | 
    
    
    227  | 
     | 
     | 
    	bp->b_flags &= ~B_INUSE;  | 
    
    
    228  | 
     | 
     | 
    	return (KEEPON);  | 
    
    
    229  | 
     | 
     | 
    }  | 
    
    
    230  | 
     | 
     | 
     | 
    
    
    231  | 
     | 
     | 
    /*  | 
    
    
    232  | 
     | 
     | 
     * Check that a block in a legal block number.  | 
    
    
    233  | 
     | 
     | 
     * Return 0 if in range, 1 if out of range.  | 
    
    
    234  | 
     | 
     | 
     */  | 
    
    
    235  | 
     | 
     | 
    int  | 
    
    
    236  | 
     | 
     | 
    chkrange(daddr_t blk, int cnt)  | 
    
    
    237  | 
     | 
     | 
    { | 
    
    
    238  | 
     | 
     | 
    	int c;  | 
    
    
    239  | 
     | 
     | 
     | 
    
    
    240  | 
     | 
     | 
    	if (cnt <= 0 || blk <= 0 || blk > maxfsblock ||  | 
    
    
    241  | 
     | 
     | 
    	    cnt - 1 > maxfsblock - blk)  | 
    
    
    242  | 
     | 
     | 
    		return (1);  | 
    
    
    243  | 
     | 
     | 
    	if (cnt > sblock.fs_frag ||  | 
    
    
    244  | 
     | 
     | 
    	    fragnum(&sblock, blk) + cnt > sblock.fs_frag) { | 
    
    
    245  | 
     | 
     | 
    		if (debug)  | 
    
    
    246  | 
     | 
     | 
    			printf("bad size: blk %lld, offset %lld, size %d\n", | 
    
    
    247  | 
     | 
     | 
    			    (long long)blk, (long long)fragnum(&sblock, blk),  | 
    
    
    248  | 
     | 
     | 
    			    cnt);  | 
    
    
    249  | 
     | 
     | 
    		return (1);  | 
    
    
    250  | 
     | 
     | 
    	}  | 
    
    
    251  | 
     | 
     | 
    	c = dtog(&sblock, blk);  | 
    
    
    252  | 
     | 
     | 
    	if (blk < cgdmin(&sblock, c)) { | 
    
    
    253  | 
     | 
     | 
    		if ((blk + cnt) > cgsblock(&sblock, c)) { | 
    
    
    254  | 
     | 
     | 
    			if (debug) { | 
    
    
    255  | 
     | 
     | 
    				printf("blk %lld < cgdmin %lld;", | 
    
    
    256  | 
     | 
     | 
    				    (long long)blk,  | 
    
    
    257  | 
     | 
     | 
    				    (long long)cgdmin(&sblock, c));  | 
    
    
    258  | 
     | 
     | 
    				printf(" blk + cnt %lld > cgsbase %lld\n", | 
    
    
    259  | 
     | 
     | 
    				    (long long)(blk + cnt),  | 
    
    
    260  | 
     | 
     | 
    				    (long long)cgsblock(&sblock, c));  | 
    
    
    261  | 
     | 
     | 
    			}  | 
    
    
    262  | 
     | 
     | 
    			return (1);  | 
    
    
    263  | 
     | 
     | 
    		}  | 
    
    
    264  | 
     | 
     | 
    	} else { | 
    
    
    265  | 
     | 
     | 
    		if ((blk + cnt) > cgbase(&sblock, c+1)) { | 
    
    
    266  | 
     | 
     | 
    			if (debug)  { | 
    
    
    267  | 
     | 
     | 
    				printf("blk %lld >= cgdmin %lld;", | 
    
    
    268  | 
     | 
     | 
    				    (long long)blk,  | 
    
    
    269  | 
     | 
     | 
    				    (long long)cgdmin(&sblock, c));  | 
    
    
    270  | 
     | 
     | 
    				printf(" blk + cnt %lld > sblock.fs_fpg %d\n", | 
    
    
    271  | 
     | 
     | 
    				    (long long)(blk+cnt), sblock.fs_fpg);  | 
    
    
    272  | 
     | 
     | 
    			}  | 
    
    
    273  | 
     | 
     | 
    			return (1);  | 
    
    
    274  | 
     | 
     | 
    		}  | 
    
    
    275  | 
     | 
     | 
    	}  | 
    
    
    276  | 
     | 
     | 
    	return (0);  | 
    
    
    277  | 
     | 
     | 
    }  | 
    
    
    278  | 
     | 
     | 
     | 
    
    
    279  | 
     | 
     | 
    /*  | 
    
    
    280  | 
     | 
     | 
     * General purpose interface for reading inodes.  | 
    
    
    281  | 
     | 
     | 
     */  | 
    
    
    282  | 
     | 
     | 
    union dinode *  | 
    
    
    283  | 
     | 
     | 
    ginode(ino_t inumber)  | 
    
    
    284  | 
     | 
     | 
    { | 
    
    
    285  | 
     | 
     | 
    	daddr_t iblk;  | 
    
    
    286  | 
     | 
     | 
     | 
    
    
    287  | 
     | 
     | 
    	if (inumber < ROOTINO || inumber > maxino)  | 
    
    
    288  | 
     | 
     | 
    		errexit("bad inode number %llu to ginode\n", | 
    
    
    289  | 
     | 
     | 
    		    (unsigned long long)inumber);  | 
    
    
    290  | 
     | 
     | 
    	if (startinum == 0 ||  | 
    
    
    291  | 
     | 
     | 
    	    inumber < startinum || inumber >= startinum + INOPB(&sblock)) { | 
    
    
    292  | 
     | 
     | 
    		iblk = ino_to_fsba(&sblock, inumber);  | 
    
    
    293  | 
     | 
     | 
    		if (pbp != 0)  | 
    
    
    294  | 
     | 
     | 
    			pbp->b_flags &= ~B_INUSE;  | 
    
    
    295  | 
     | 
     | 
    		pbp = getdatablk(iblk, sblock.fs_bsize);  | 
    
    
    296  | 
     | 
     | 
    		startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);  | 
    
    
    297  | 
     | 
     | 
    	}  | 
    
    
    298  | 
     | 
     | 
    	if (sblock.fs_magic == FS_UFS1_MAGIC)  | 
    
    
    299  | 
     | 
     | 
    		return ((union dinode *)  | 
    
    
    300  | 
     | 
     | 
    		    &pbp->b_un.b_dinode1[inumber % INOPB(&sblock)]);  | 
    
    
    301  | 
     | 
     | 
    	return ((union dinode *)&pbp->b_un.b_dinode2[inumber % INOPB(&sblock)]);  | 
    
    
    302  | 
     | 
     | 
    }  | 
    
    
    303  | 
     | 
     | 
     | 
    
    
    304  | 
     | 
     | 
    /*  | 
    
    
    305  | 
     | 
     | 
     * Special purpose version of ginode used to optimize first pass  | 
    
    
    306  | 
     | 
     | 
     * over all the inodes in numerical order.  | 
    
    
    307  | 
     | 
     | 
     */  | 
    
    
    308  | 
     | 
     | 
    ino_t nextino, lastinum;  | 
    
    
    309  | 
     | 
     | 
    long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;  | 
    
    
    310  | 
     | 
     | 
    static caddr_t inodebuf;  | 
    
    
    311  | 
     | 
     | 
     | 
    
    
    312  | 
     | 
     | 
    union dinode *  | 
    
    
    313  | 
     | 
     | 
    getnextinode(ino_t inumber)  | 
    
    
    314  | 
     | 
     | 
    { | 
    
    
    315  | 
     | 
     | 
    	long size;  | 
    
    
    316  | 
     | 
     | 
    	daddr_t dblk;  | 
    
    
    317  | 
     | 
     | 
    	union dinode *dp;  | 
    
    
    318  | 
     | 
     | 
    	static caddr_t nextinop;  | 
    
    
    319  | 
     | 
     | 
     | 
    
    
    320  | 
     | 
     | 
    	if (inumber != nextino++ || inumber > maxino)  | 
    
    
    321  | 
     | 
     | 
    		errexit("bad inode number %llu to nextinode %llu\n", | 
    
    
    322  | 
     | 
     | 
    		    (unsigned long long)inumber,  | 
    
    
    323  | 
     | 
     | 
    		    (unsigned long long)nextino);  | 
    
    
    324  | 
     | 
     | 
    	if (inumber >= lastinum) { | 
    
    
    325  | 
     | 
     | 
    		readcnt++;  | 
    
    
    326  | 
     | 
     | 
    		dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum));  | 
    
    
    327  | 
     | 
     | 
    		if (readcnt % readpercg == 0) { | 
    
    
    328  | 
     | 
     | 
    			size = partialsize;  | 
    
    
    329  | 
     | 
     | 
    			lastinum += partialcnt;  | 
    
    
    330  | 
     | 
     | 
    		} else { | 
    
    
    331  | 
     | 
     | 
    			size = inobufsize;  | 
    
    
    332  | 
     | 
     | 
    			lastinum += fullcnt;  | 
    
    
    333  | 
     | 
     | 
    		}  | 
    
    
    334  | 
     | 
     | 
    		(void)bread(fsreadfd, inodebuf, dblk, size);  | 
    
    
    335  | 
     | 
     | 
    		nextinop = inodebuf;  | 
    
    
    336  | 
     | 
     | 
    	}  | 
    
    
    337  | 
     | 
     | 
    	dp = (union dinode *)nextinop;  | 
    
    
    338  | 
     | 
     | 
    	if (sblock.fs_magic == FS_UFS1_MAGIC)  | 
    
    
    339  | 
     | 
     | 
    		nextinop += sizeof(struct ufs1_dinode);  | 
    
    
    340  | 
     | 
     | 
    	else  | 
    
    
    341  | 
     | 
     | 
    		nextinop += sizeof(struct ufs2_dinode);  | 
    
    
    342  | 
     | 
     | 
    	return (dp);  | 
    
    
    343  | 
     | 
     | 
    }  | 
    
    
    344  | 
     | 
     | 
     | 
    
    
    345  | 
     | 
     | 
    void  | 
    
    
    346  | 
     | 
     | 
    setinodebuf(ino_t inum)  | 
    
    
    347  | 
     | 
     | 
    { | 
    
    
    348  | 
     | 
     | 
     | 
    
    
    349  | 
     | 
     | 
    	startinum = 0;  | 
    
    
    350  | 
     | 
     | 
    	nextino = inum;  | 
    
    
    351  | 
     | 
     | 
    	lastinum = inum;  | 
    
    
    352  | 
     | 
     | 
    	readcnt = 0;  | 
    
    
    353  | 
     | 
     | 
    	if (inodebuf != NULL)  | 
    
    
    354  | 
     | 
     | 
    		return;  | 
    
    
    355  | 
     | 
     | 
    	inobufsize = blkroundup(&sblock, INOBUFSIZE);  | 
    
    
    356  | 
     | 
     | 
    	if (sblock.fs_magic == FS_UFS1_MAGIC)  | 
    
    
    357  | 
     | 
     | 
    		fullcnt = inobufsize / sizeof(struct ufs1_dinode);  | 
    
    
    358  | 
     | 
     | 
    	else  | 
    
    
    359  | 
     | 
     | 
    		fullcnt = inobufsize / sizeof(struct ufs2_dinode);  | 
    
    
    360  | 
     | 
     | 
    	readpercg = sblock.fs_ipg / fullcnt;  | 
    
    
    361  | 
     | 
     | 
    	partialcnt = sblock.fs_ipg % fullcnt;  | 
    
    
    362  | 
     | 
     | 
    	if (sblock.fs_magic == FS_UFS1_MAGIC)  | 
    
    
    363  | 
     | 
     | 
    		partialsize = partialcnt * sizeof(struct ufs1_dinode);  | 
    
    
    364  | 
     | 
     | 
    	else  | 
    
    
    365  | 
     | 
     | 
    		partialsize = partialcnt * sizeof(struct ufs2_dinode);  | 
    
    
    366  | 
     | 
     | 
    	if (partialcnt != 0) { | 
    
    
    367  | 
     | 
     | 
    		readpercg++;  | 
    
    
    368  | 
     | 
     | 
    	} else { | 
    
    
    369  | 
     | 
     | 
    		partialcnt = fullcnt;  | 
    
    
    370  | 
     | 
     | 
    		partialsize = inobufsize;  | 
    
    
    371  | 
     | 
     | 
    	}  | 
    
    
    372  | 
     | 
     | 
    	if (inodebuf == NULL &&  | 
    
    
    373  | 
     | 
     | 
    	    (inodebuf = malloc((unsigned)inobufsize)) == NULL)  | 
    
    
    374  | 
     | 
     | 
    		errexit("Cannot allocate space for inode buffer\n"); | 
    
    
    375  | 
     | 
     | 
    }  | 
    
    
    376  | 
     | 
     | 
     | 
    
    
    377  | 
     | 
     | 
    void  | 
    
    
    378  | 
     | 
     | 
    freeinodebuf(void)  | 
    
    
    379  | 
     | 
     | 
    { | 
    
    
    380  | 
     | 
     | 
     | 
    
    
    381  | 
     | 
     | 
    	free(inodebuf);  | 
    
    
    382  | 
     | 
     | 
    	inodebuf = NULL;  | 
    
    
    383  | 
     | 
     | 
    }  | 
    
    
    384  | 
     | 
     | 
     | 
    
    
    385  | 
     | 
     | 
    /*  | 
    
    
    386  | 
     | 
     | 
     * Routines to maintain information about directory inodes.  | 
    
    
    387  | 
     | 
     | 
     * This is built during the first pass and used during the  | 
    
    
    388  | 
     | 
     | 
     * second and third passes.  | 
    
    
    389  | 
     | 
     | 
     *  | 
    
    
    390  | 
     | 
     | 
     * Enter inodes into the cache.  | 
    
    
    391  | 
     | 
     | 
     */  | 
    
    
    392  | 
     | 
     | 
    void  | 
    
    
    393  | 
     | 
     | 
    cacheino(union dinode *dp, ino_t inumber)  | 
    
    
    394  | 
     | 
     | 
    { | 
    
    
    395  | 
     | 
     | 
    	struct inoinfo *inp;  | 
    
    
    396  | 
     | 
     | 
    	struct inoinfo **inpp, **newinpsort;  | 
    
    
    397  | 
     | 
     | 
    	unsigned int blks;  | 
    
    
    398  | 
     | 
     | 
    	long newlistmax;  | 
    
    
    399  | 
     | 
     | 
    	int i;  | 
    
    
    400  | 
     | 
     | 
     | 
    
    
    401  | 
     | 
     | 
    	blks = howmany(DIP(dp, di_size), sblock.fs_bsize);  | 
    
    
    402  | 
     | 
     | 
    	if (blks > NDADDR)  | 
    
    
    403  | 
     | 
     | 
    		blks = NDADDR + NIADDR;  | 
    
    
    404  | 
     | 
     | 
    	inp = malloc(sizeof(*inp) + (blks ? blks - 1 : 0) * sizeof(daddr_t));  | 
    
    
    405  | 
     | 
     | 
    	if (inp == NULL)  | 
    
    
    406  | 
     | 
     | 
    		errexit("cannot allocate memory for inode cache\n"); | 
    
    
    407  | 
     | 
     | 
    	inpp = &inphead[inumber % numdirs];  | 
    
    
    408  | 
     | 
     | 
    	inp->i_nexthash = *inpp;  | 
    
    
    409  | 
     | 
     | 
    	*inpp = inp;  | 
    
    
    410  | 
     | 
     | 
    	inp->i_child = inp->i_sibling = 0;  | 
    
    
    411  | 
     | 
     | 
    	if (inumber == ROOTINO)  | 
    
    
    412  | 
     | 
     | 
    		inp->i_parent = ROOTINO;  | 
    
    
    413  | 
     | 
     | 
    	else  | 
    
    
    414  | 
     | 
     | 
    		inp->i_parent = 0;  | 
    
    
    415  | 
     | 
     | 
    	inp->i_dotdot = 0;  | 
    
    
    416  | 
     | 
     | 
    	inp->i_number = inumber;  | 
    
    
    417  | 
     | 
     | 
    	inp->i_isize = DIP(dp, di_size);  | 
    
    
    418  | 
     | 
     | 
    	inp->i_numblks = blks;  | 
    
    
    419  | 
     | 
     | 
    	for (i = 0; i < (blks < NDADDR ? blks : NDADDR); i++)  | 
    
    
    420  | 
     | 
     | 
    		inp->i_blks[i] = DIP(dp, di_db[i]);  | 
    
    
    421  | 
     | 
     | 
    	if (blks > NDADDR)  | 
    
    
    422  | 
     | 
     | 
    		for (i = 0; i < NIADDR; i++)  | 
    
    
    423  | 
     | 
     | 
    			inp->i_blks[NDADDR + i] = DIP(dp, di_ib[i]);  | 
    
    
    424  | 
     | 
     | 
    	if (inplast == listmax) { | 
    
    
    425  | 
     | 
     | 
    		newlistmax = listmax + 100;  | 
    
    
    426  | 
     | 
     | 
    		newinpsort = reallocarray(inpsort,  | 
    
    
    427  | 
     | 
     | 
    		    (unsigned)newlistmax, sizeof(struct inoinfo *));  | 
    
    
    428  | 
     | 
     | 
    		if (newinpsort == NULL)  | 
    
    
    429  | 
     | 
     | 
    			errexit("cannot increase directory list"); | 
    
    
    430  | 
     | 
     | 
    		inpsort = newinpsort;  | 
    
    
    431  | 
     | 
     | 
    		listmax = newlistmax;  | 
    
    
    432  | 
     | 
     | 
    	}  | 
    
    
    433  | 
     | 
     | 
    	inpsort[inplast++] = inp;  | 
    
    
    434  | 
     | 
     | 
    }  | 
    
    
    435  | 
     | 
     | 
     | 
    
    
    436  | 
     | 
     | 
    /*  | 
    
    
    437  | 
     | 
     | 
     * Look up an inode cache structure.  | 
    
    
    438  | 
     | 
     | 
     */  | 
    
    
    439  | 
     | 
     | 
    struct inoinfo *  | 
    
    
    440  | 
     | 
     | 
    getinoinfo(ino_t inumber)  | 
    
    
    441  | 
     | 
     | 
    { | 
    
    
    442  | 
     | 
     | 
    	struct inoinfo *inp;  | 
    
    
    443  | 
     | 
     | 
     | 
    
    
    444  | 
     | 
     | 
    	for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) { | 
    
    
    445  | 
     | 
     | 
    		if (inp->i_number != inumber)  | 
    
    
    446  | 
     | 
     | 
    			continue;  | 
    
    
    447  | 
     | 
     | 
    		return (inp);  | 
    
    
    448  | 
     | 
     | 
    	}  | 
    
    
    449  | 
     | 
     | 
    	errexit("cannot find inode %llu\n", (unsigned long long)inumber); | 
    
    
    450  | 
     | 
     | 
    	return (NULL);  | 
    
    
    451  | 
     | 
     | 
    }  | 
    
    
    452  | 
     | 
     | 
     | 
    
    
    453  | 
     | 
     | 
    /*  | 
    
    
    454  | 
     | 
     | 
     * Clean up all the inode cache structure.  | 
    
    
    455  | 
     | 
     | 
     */  | 
    
    
    456  | 
     | 
     | 
    void  | 
    
    
    457  | 
     | 
     | 
    inocleanup(void)  | 
    
    
    458  | 
     | 
     | 
    { | 
    
    
    459  | 
     | 
     | 
    	struct inoinfo **inpp;  | 
    
    
    460  | 
     | 
     | 
     | 
    
    
    461  | 
     | 
     | 
    	if (inphead == NULL)  | 
    
    
    462  | 
     | 
     | 
    		return;  | 
    
    
    463  | 
     | 
     | 
    	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)  | 
    
    
    464  | 
     | 
     | 
    		free(*inpp);  | 
    
    
    465  | 
     | 
     | 
    	free(inphead);  | 
    
    
    466  | 
     | 
     | 
    	free(inpsort);  | 
    
    
    467  | 
     | 
     | 
    	inphead = inpsort = NULL;  | 
    
    
    468  | 
     | 
     | 
    }  | 
    
    
    469  | 
     | 
     | 
     | 
    
    
    470  | 
     | 
     | 
    void  | 
    
    
    471  | 
     | 
     | 
    inodirty(void)  | 
    
    
    472  | 
     | 
     | 
    { | 
    
    
    473  | 
     | 
     | 
    	dirty(pbp);  | 
    
    
    474  | 
     | 
     | 
    }  | 
    
    
    475  | 
     | 
     | 
     | 
    
    
    476  | 
     | 
     | 
    void  | 
    
    
    477  | 
     | 
     | 
    clri(struct inodesc *idesc, char *type, int flag)  | 
    
    
    478  | 
     | 
     | 
    { | 
    
    
    479  | 
     | 
     | 
    	union dinode *dp;  | 
    
    
    480  | 
     | 
     | 
     | 
    
    
    481  | 
     | 
     | 
    	dp = ginode(idesc->id_number);  | 
    
    
    482  | 
     | 
     | 
    	if (flag == 1) { | 
    
    
    483  | 
     | 
     | 
    		pwarn("%s %s", type, | 
    
    
    484  | 
     | 
     | 
    		    (DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE");  | 
    
    
    485  | 
     | 
     | 
    		pinode(idesc->id_number);  | 
    
    
    486  | 
     | 
     | 
    	}  | 
    
    
    487  | 
     | 
     | 
    	if (preen || reply("CLEAR") == 1) { | 
    
    
    488  | 
     | 
     | 
    		if (preen)  | 
    
    
    489  | 
     | 
     | 
    			printf(" (CLEARED)\n"); | 
    
    
    490  | 
     | 
     | 
    		n_files--;  | 
    
    
    491  | 
     | 
     | 
    		(void)ckinode(dp, idesc);  | 
    
    
    492  | 
     | 
     | 
    		clearinode(dp);  | 
    
    
    493  | 
     | 
     | 
    		SET_ISTATE(idesc->id_number, USTATE);  | 
    
    
    494  | 
     | 
     | 
    		inodirty();  | 
    
    
    495  | 
     | 
     | 
    	}  | 
    
    
    496  | 
     | 
     | 
    }  | 
    
    
    497  | 
     | 
     | 
     | 
    
    
    498  | 
     | 
     | 
    int  | 
    
    
    499  | 
     | 
     | 
    findname(struct inodesc *idesc)  | 
    
    
    500  | 
     | 
     | 
    { | 
    
    
    501  | 
     | 
     | 
    	struct direct *dirp = idesc->id_dirp;  | 
    
    
    502  | 
     | 
     | 
     | 
    
    
    503  | 
     | 
     | 
    	if (dirp->d_ino != idesc->id_parent)  | 
    
    
    504  | 
     | 
     | 
    		return (KEEPON);  | 
    
    
    505  | 
     | 
     | 
    	memcpy(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);  | 
    
    
    506  | 
     | 
     | 
    	return (STOP|FOUND);  | 
    
    
    507  | 
     | 
     | 
    }  | 
    
    
    508  | 
     | 
     | 
     | 
    
    
    509  | 
     | 
     | 
    int  | 
    
    
    510  | 
     | 
     | 
    findino(struct inodesc *idesc)  | 
    
    
    511  | 
     | 
     | 
    { | 
    
    
    512  | 
     | 
     | 
    	struct direct *dirp = idesc->id_dirp;  | 
    
    
    513  | 
     | 
     | 
     | 
    
    
    514  | 
     | 
     | 
    	if (dirp->d_ino == 0)  | 
    
    
    515  | 
     | 
     | 
    		return (KEEPON);  | 
    
    
    516  | 
     | 
     | 
    	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&  | 
    
    
    517  | 
     | 
     | 
    	    dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) { | 
    
    
    518  | 
     | 
     | 
    		idesc->id_parent = dirp->d_ino;  | 
    
    
    519  | 
     | 
     | 
    		return (STOP|FOUND);  | 
    
    
    520  | 
     | 
     | 
    	}  | 
    
    
    521  | 
     | 
     | 
    	return (KEEPON);  | 
    
    
    522  | 
     | 
     | 
    }  | 
    
    
    523  | 
     | 
     | 
     | 
    
    
    524  | 
     | 
     | 
    void  | 
    
    
    525  | 
     | 
     | 
    pinode(ino_t ino)  | 
    
    
    526  | 
     | 
     | 
    { | 
    
    
    527  | 
     | 
     | 
    	union dinode *dp;  | 
    
    
    528  | 
     | 
     | 
    	char *p;  | 
    
    
    529  | 
     | 
     | 
    #ifndef SMALL  | 
    
    
    530  | 
     | 
     | 
    	struct passwd *pw;  | 
    
    
    531  | 
     | 
     | 
    #endif  | 
    
    
    532  | 
     | 
     | 
    	time_t t;  | 
    
    
    533  | 
     | 
     | 
     | 
    
    
    534  | 
     | 
     | 
    	printf(" I=%llu ", (unsigned long long)ino); | 
    
    
    535  | 
     | 
     | 
    	if (ino < ROOTINO || ino > maxino)  | 
    
    
    536  | 
     | 
     | 
    		return;  | 
    
    
    537  | 
     | 
     | 
    	dp = ginode(ino);  | 
    
    
    538  | 
     | 
     | 
    	printf(" OWNER="); | 
    
    
    539  | 
     | 
     | 
    #ifndef SMALL  | 
    
    
    540  | 
     | 
     | 
    	if ((pw = getpwuid(DIP(dp, di_uid))) != 0)  | 
    
    
    541  | 
     | 
     | 
    		printf("%s ", pw->pw_name); | 
    
    
    542  | 
     | 
     | 
    	else  | 
    
    
    543  | 
     | 
     | 
    #endif  | 
    
    
    544  | 
     | 
     | 
    		printf("%u ", (unsigned)DIP(dp, di_uid)); | 
    
    
    545  | 
     | 
     | 
    	printf("MODE=%o\n", DIP(dp, di_mode)); | 
    
    
    546  | 
     | 
     | 
    	if (preen)  | 
    
    
    547  | 
     | 
     | 
    		printf("%s: ", cdevname()); | 
    
    
    548  | 
     | 
     | 
    	printf("SIZE=%llu ", (unsigned long long)DIP(dp, di_size)); | 
    
    
    549  | 
     | 
     | 
    	t = DIP(dp, di_mtime);  | 
    
    
    550  | 
     | 
     | 
    	p = ctime(&t);  | 
    
    
    551  | 
     | 
     | 
    	printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); | 
    
    
    552  | 
     | 
     | 
    }  | 
    
    
    553  | 
     | 
     | 
     | 
    
    
    554  | 
     | 
     | 
    void  | 
    
    
    555  | 
     | 
     | 
    blkerror(ino_t ino, char *type, daddr_t blk)  | 
    
    
    556  | 
     | 
     | 
    { | 
    
    
    557  | 
     | 
     | 
     | 
    
    
    558  | 
     | 
     | 
    	pfatal("%lld %s I=%llu", blk, type, (unsigned long long)ino); | 
    
    
    559  | 
     | 
     | 
    	printf("\n"); | 
    
    
    560  | 
     | 
     | 
    	switch (GET_ISTATE(ino)) { | 
    
    
    561  | 
     | 
     | 
     | 
    
    
    562  | 
     | 
     | 
    	case FSTATE:  | 
    
    
    563  | 
     | 
     | 
    		SET_ISTATE(ino, FCLEAR);  | 
    
    
    564  | 
     | 
     | 
    		return;  | 
    
    
    565  | 
     | 
     | 
     | 
    
    
    566  | 
     | 
     | 
    	case DSTATE:  | 
    
    
    567  | 
     | 
     | 
    		SET_ISTATE(ino, DCLEAR);  | 
    
    
    568  | 
     | 
     | 
    		return;  | 
    
    
    569  | 
     | 
     | 
     | 
    
    
    570  | 
     | 
     | 
    	case FCLEAR:  | 
    
    
    571  | 
     | 
     | 
    	case DCLEAR:  | 
    
    
    572  | 
     | 
     | 
    		return;  | 
    
    
    573  | 
     | 
     | 
     | 
    
    
    574  | 
     | 
     | 
    	default:  | 
    
    
    575  | 
     | 
     | 
    		errexit("BAD STATE %d TO BLKERR\n", GET_ISTATE(ino)); | 
    
    
    576  | 
     | 
     | 
    		/* NOTREACHED */  | 
    
    
    577  | 
     | 
     | 
    	}  | 
    
    
    578  | 
     | 
     | 
    }  | 
    
    
    579  | 
     | 
     | 
     | 
    
    
    580  | 
     | 
     | 
    /*  | 
    
    
    581  | 
     | 
     | 
     * allocate an unused inode  | 
    
    
    582  | 
     | 
     | 
     */  | 
    
    
    583  | 
     | 
     | 
    ino_t  | 
    
    
    584  | 
     | 
     | 
    allocino(ino_t request, int type)  | 
    
    
    585  | 
     | 
     | 
    { | 
    
    
    586  | 
     | 
     | 
    	ino_t ino;  | 
    
    
    587  | 
     | 
     | 
    	union dinode *dp;  | 
    
    
    588  | 
     | 
     | 
    	struct cg *cgp = &cgrp;  | 
    
    
    589  | 
     | 
     | 
    	int cg;  | 
    
    
    590  | 
     | 
     | 
    	time_t t;  | 
    
    
    591  | 
     | 
     | 
    	struct inostat *info;  | 
    
    
    592  | 
     | 
     | 
     | 
    
    
    593  | 
     | 
     | 
    	if (request == 0)  | 
    
    
    594  | 
     | 
     | 
    		request = ROOTINO;  | 
    
    
    595  | 
     | 
     | 
    	else if (GET_ISTATE(request) != USTATE)  | 
    
    
    596  | 
     | 
     | 
    		return (0);  | 
    
    
    597  | 
     | 
     | 
    	for (ino = request; ino < maxino; ino++)  | 
    
    
    598  | 
     | 
     | 
    		if (GET_ISTATE(ino) == USTATE)  | 
    
    
    599  | 
     | 
     | 
    			break;  | 
    
    
    600  | 
     | 
     | 
    	if (ino == maxino)  | 
    
    
    601  | 
     | 
     | 
    		return (0);  | 
    
    
    602  | 
     | 
     | 
    	cg = ino_to_cg(&sblock, ino);  | 
    
    
    603  | 
     | 
     | 
    	/* If necessary, extend the inoinfo array. grow exponentially */  | 
    
    
    604  | 
     | 
     | 
    	if ((ino % sblock.fs_ipg) >= (uint64_t)inostathead[cg].il_numalloced) { | 
    
    
    605  | 
     | 
     | 
    		unsigned long newalloced, i;  | 
    
    
    606  | 
     | 
     | 
    		newalloced = MINIMUM(sblock.fs_ipg,  | 
    
    
    607  | 
     | 
     | 
    			MAXIMUM(2 * inostathead[cg].il_numalloced, 10));  | 
    
    
    608  | 
     | 
     | 
    		info = calloc(newalloced, sizeof(struct inostat));  | 
    
    
    609  | 
     | 
     | 
    		if (info == NULL) { | 
    
    
    610  | 
     | 
     | 
    			pwarn("cannot alloc %zu bytes to extend inoinfo\n", | 
    
    
    611  | 
     | 
     | 
    				sizeof(struct inostat) * newalloced);  | 
    
    
    612  | 
     | 
     | 
    			return 0;  | 
    
    
    613  | 
     | 
     | 
    		}  | 
    
    
    614  | 
     | 
     | 
    		memmove(info, inostathead[cg].il_stat,  | 
    
    
    615  | 
     | 
     | 
    			inostathead[cg].il_numalloced * sizeof(*info));  | 
    
    
    616  | 
     | 
     | 
    		for (i = inostathead[cg].il_numalloced; i < newalloced; i++) { | 
    
    
    617  | 
     | 
     | 
    			info[i].ino_state = USTATE;  | 
    
    
    618  | 
     | 
     | 
    		}  | 
    
    
    619  | 
     | 
     | 
    		if (inostathead[cg].il_numalloced)  | 
    
    
    620  | 
     | 
     | 
    			free(inostathead[cg].il_stat);  | 
    
    
    621  | 
     | 
     | 
    		inostathead[cg].il_stat = info;  | 
    
    
    622  | 
     | 
     | 
    		inostathead[cg].il_numalloced = newalloced;  | 
    
    
    623  | 
     | 
     | 
    		info = inoinfo(ino);  | 
    
    
    624  | 
     | 
     | 
    	}  | 
    
    
    625  | 
     | 
     | 
    	getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);  | 
    
    
    626  | 
     | 
     | 
    	if (!cg_chkmagic(cgp))  | 
    
    
    627  | 
     | 
     | 
    		pfatal("CG %d: BAD MAGIC NUMBER\n", cg); | 
    
    
    628  | 
     | 
     | 
    	setbit(cg_inosused(cgp), ino % sblock.fs_ipg);  | 
    
    
    629  | 
     | 
     | 
    	cgp->cg_cs.cs_nifree--;  | 
    
    
    630  | 
     | 
     | 
     | 
    
    
    631  | 
     | 
     | 
    	switch (type & IFMT) { | 
    
    
    632  | 
     | 
     | 
    	case IFDIR:  | 
    
    
    633  | 
     | 
     | 
    		SET_ISTATE(ino, DSTATE);  | 
    
    
    634  | 
     | 
     | 
    		cgp->cg_cs.cs_ndir++;  | 
    
    
    635  | 
     | 
     | 
    		break;  | 
    
    
    636  | 
     | 
     | 
    	case IFREG:  | 
    
    
    637  | 
     | 
     | 
    	case IFLNK:  | 
    
    
    638  | 
     | 
     | 
    		SET_ISTATE(ino, FSTATE);  | 
    
    
    639  | 
     | 
     | 
    		break;  | 
    
    
    640  | 
     | 
     | 
    	default:  | 
    
    
    641  | 
     | 
     | 
    		return (0);  | 
    
    
    642  | 
     | 
     | 
    	}  | 
    
    
    643  | 
     | 
     | 
    	cgdirty();  | 
    
    
    644  | 
     | 
     | 
    	dp = ginode(ino);  | 
    
    
    645  | 
     | 
     | 
    	DIP_SET(dp, di_db[0],  allocblk(1));  | 
    
    
    646  | 
     | 
     | 
    	if (DIP(dp, di_db[0]) == 0) { | 
    
    
    647  | 
     | 
     | 
    		SET_ISTATE(ino, USTATE);  | 
    
    
    648  | 
     | 
     | 
    		return (0);  | 
    
    
    649  | 
     | 
     | 
    	}  | 
    
    
    650  | 
     | 
     | 
    	DIP_SET(dp, di_mode, type);  | 
    
    
    651  | 
     | 
     | 
    	DIP_SET(dp, di_uid, geteuid());  | 
    
    
    652  | 
     | 
     | 
    	DIP_SET(dp, di_gid, getegid());  | 
    
    
    653  | 
     | 
     | 
    	DIP_SET(dp, di_flags, 0);  | 
    
    
    654  | 
     | 
     | 
    	(void)time(&t);  | 
    
    
    655  | 
     | 
     | 
    	DIP_SET(dp, di_atime, t);  | 
    
    
    656  | 
     | 
     | 
    	DIP_SET(dp, di_atimensec, 0);  | 
    
    
    657  | 
     | 
     | 
    	DIP_SET(dp, di_mtime, t);  | 
    
    
    658  | 
     | 
     | 
    	DIP_SET(dp, di_mtimensec, 0);  | 
    
    
    659  | 
     | 
     | 
    	DIP_SET(dp, di_ctime, t);  | 
    
    
    660  | 
     | 
     | 
    	DIP_SET(dp, di_ctimensec, 0);  | 
    
    
    661  | 
     | 
     | 
    	DIP_SET(dp, di_size, sblock.fs_fsize);  | 
    
    
    662  | 
     | 
     | 
    	DIP_SET(dp, di_blocks, btodb(sblock.fs_fsize));  | 
    
    
    663  | 
     | 
     | 
    	n_files++;  | 
    
    
    664  | 
     | 
     | 
    	inodirty();  | 
    
    
    665  | 
     | 
     | 
    	SET_ITYPE(ino, IFTODT(type));  | 
    
    
    666  | 
     | 
     | 
    	return (ino);  | 
    
    
    667  | 
     | 
     | 
    }  | 
    
    
    668  | 
     | 
     | 
     | 
    
    
    669  | 
     | 
     | 
    /*  | 
    
    
    670  | 
     | 
     | 
     * deallocate an inode  | 
    
    
    671  | 
     | 
     | 
     */  | 
    
    
    672  | 
     | 
     | 
    void  | 
    
    
    673  | 
     | 
     | 
    freeino(ino_t ino)  | 
    
    
    674  | 
     | 
     | 
    { | 
    
    
    675  | 
     | 
     | 
    	struct inodesc idesc;  | 
    
    
    676  | 
     | 
     | 
    	union dinode *dp;  | 
    
    
    677  | 
     | 
     | 
     | 
    
    
    678  | 
     | 
     | 
    	memset(&idesc, 0, sizeof(struct inodesc));  | 
    
    
    679  | 
     | 
     | 
    	idesc.id_type = ADDR;  | 
    
    
    680  | 
     | 
     | 
    	idesc.id_func = pass4check;  | 
    
    
    681  | 
     | 
     | 
    	idesc.id_number = ino;  | 
    
    
    682  | 
     | 
     | 
    	dp = ginode(ino);  | 
    
    
    683  | 
     | 
     | 
    	(void)ckinode(dp, &idesc);  | 
    
    
    684  | 
     | 
     | 
    	clearinode(dp);  | 
    
    
    685  | 
     | 
     | 
    	inodirty();  | 
    
    
    686  | 
     | 
     | 
    	SET_ISTATE(ino, USTATE);  | 
    
    
    687  | 
     | 
     | 
    	n_files--;  | 
    
    
    688  | 
     | 
     | 
    }  |