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