break UFS up into FFS/UFS/LFS/MFS
[unix-history] / usr / src / sbin / fsck / inode.c
CommitLineData
76797561 1/*
fe32782c
KM
2 * Copyright (c) 1980, 1986 The Regents of the University of California.
3 * All rights reserved.
4 *
70ab3c27 5 * %sccs.include.redist.c%
76797561
DF
6 */
7
7026cd3f 8#ifndef lint
558b3a30 9static char sccsid[] = "@(#)inode.c 5.19 (Berkeley) %G%";
fe32782c 10#endif /* not lint */
7026cd3f
KM
11
12#include <sys/param.h>
558b3a30
KB
13#include <ufs/ufs/dinode.h>
14#include <ufs/ufs/dir.h>
15#include <ufs/ffs/fs.h>
0086a7e5 16#include <pwd.h>
d72e970b
KM
17#include <stdlib.h>
18#include <string.h>
7026cd3f
KM
19#include "fsck.h"
20
68a34947 21static ino_t startinum;
adc5a10c 22
7026cd3f 23ckinode(dp, idesc)
569ec282 24 struct dinode *dp;
7026cd3f
KM
25 register struct inodesc *idesc;
26{
27 register daddr_t *ap;
569ec282
KM
28 long ret, n, ndb, offset;
29 struct dinode dino;
7026cd3f 30
20c974e6
KM
31 if (idesc->id_fix != IGNORE)
32 idesc->id_fix = DONTKNOW;
7026cd3f 33 idesc->id_entryno = 0;
f0ed004a 34 idesc->id_filesize = dp->di_size;
569ec282 35 if ((dp->di_mode & IFMT) == IFBLK || (dp->di_mode & IFMT) == IFCHR)
f8a97eea
KM
36 return (KEEPON);
37 dino = *dp;
7026cd3f
KM
38 ndb = howmany(dino.di_size, sblock.fs_bsize);
39 for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
40 if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
41 idesc->id_numfrags =
42 numfrags(&sblock, fragroundup(&sblock, offset));
43 else
44 idesc->id_numfrags = sblock.fs_frag;
45 if (*ap == 0)
46 continue;
47 idesc->id_blkno = *ap;
48 if (idesc->id_type == ADDR)
49 ret = (*idesc->id_func)(idesc);
50 else
51 ret = dirscan(idesc);
52 if (ret & STOP)
53 return (ret);
54 }
55 idesc->id_numfrags = sblock.fs_frag;
7718c0e6 56 for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
7026cd3f
KM
57 if (*ap) {
58 idesc->id_blkno = *ap;
59 ret = iblock(idesc, n,
60 dino.di_size - sblock.fs_bsize * NDADDR);
61 if (ret & STOP)
62 return (ret);
63 }
64 }
65 return (KEEPON);
66}
67
68iblock(idesc, ilevel, isize)
69 struct inodesc *idesc;
569ec282 70 register long ilevel;
d72e970b 71 u_long isize;
7026cd3f
KM
72{
73 register daddr_t *ap;
74 register daddr_t *aplim;
7718c0e6 75 int i, n, (*func)(), nif, sizepb;
569ec282 76 register struct bufarea *bp;
8f7c3c7e 77 char buf[BUFSIZ];
f10a0ae9 78 extern int dirscan(), pass1check();
7026cd3f
KM
79
80 if (idesc->id_type == ADDR) {
81 func = idesc->id_func;
82 if (((n = (*func)(idesc)) & KEEPON) == 0)
83 return (n);
84 } else
85 func = dirscan;
569ec282 86 if (chkrange(idesc->id_blkno, idesc->id_numfrags))
7026cd3f 87 return (SKIP);
adc5a10c 88 bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
7026cd3f 89 ilevel--;
7718c0e6
KM
90 for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
91 sizepb *= NINDIR(&sblock);
92 nif = isize / sizepb + 1;
7026cd3f
KM
93 if (nif > NINDIR(&sblock))
94 nif = NINDIR(&sblock);
48a66bfb 95 if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
adc5a10c
KM
96 aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
97 for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
48a66bfb
KM
98 if (*ap == 0)
99 continue;
d72e970b 100 (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu",
8f7c3c7e
KM
101 idesc->id_number);
102 if (dofix(idesc, buf)) {
48a66bfb 103 *ap = 0;
adc5a10c 104 dirty(bp);
48a66bfb
KM
105 }
106 }
569ec282 107 flush(fswritefd, bp);
48a66bfb 108 }
adc5a10c
KM
109 aplim = &bp->b_un.b_indir[nif];
110 for (ap = bp->b_un.b_indir, i = 1; ap < aplim; ap++, i++) {
7026cd3f
KM
111 if (*ap) {
112 idesc->id_blkno = *ap;
113 if (ilevel > 0)
7718c0e6 114 n = iblock(idesc, ilevel, isize - i * sizepb);
7026cd3f
KM
115 else
116 n = (*func)(idesc);
adc5a10c
KM
117 if (n & STOP) {
118 bp->b_flags &= ~B_INUSE;
7026cd3f 119 return (n);
adc5a10c 120 }
7026cd3f 121 }
adc5a10c
KM
122 }
123 bp->b_flags &= ~B_INUSE;
7026cd3f
KM
124 return (KEEPON);
125}
126
569ec282
KM
127/*
128 * Check that a block in a legal block number.
129 * Return 0 if in range, 1 if out of range.
130 */
131chkrange(blk, cnt)
7026cd3f
KM
132 daddr_t blk;
133 int cnt;
134{
135 register int c;
136
569ec282 137 if ((unsigned)(blk + cnt) > maxfsblock)
7026cd3f
KM
138 return (1);
139 c = dtog(&sblock, blk);
140 if (blk < cgdmin(&sblock, c)) {
569ec282 141 if ((blk + cnt) > cgsblock(&sblock, c)) {
7026cd3f 142 if (debug) {
d72e970b 143 printf("blk %ld < cgdmin %ld;",
7026cd3f 144 blk, cgdmin(&sblock, c));
d72e970b 145 printf(" blk + cnt %ld > cgsbase %ld\n",
569ec282 146 blk + cnt, cgsblock(&sblock, c));
7026cd3f
KM
147 }
148 return (1);
149 }
150 } else {
569ec282 151 if ((blk + cnt) > cgbase(&sblock, c+1)) {
7026cd3f 152 if (debug) {
d72e970b 153 printf("blk %ld >= cgdmin %ld;",
7026cd3f 154 blk, cgdmin(&sblock, c));
d72e970b 155 printf(" blk + cnt %ld > sblock.fs_fpg %ld\n",
7026cd3f
KM
156 blk+cnt, sblock.fs_fpg);
157 }
158 return (1);
159 }
160 }
161 return (0);
162}
163
071ea3c2
KM
164/*
165 * General purpose interface for reading inodes.
166 */
569ec282 167struct dinode *
7026cd3f
KM
168ginode(inumber)
169 ino_t inumber;
170{
171 daddr_t iblk;
7026cd3f 172
569ec282 173 if (inumber < ROOTINO || inumber > maxino)
39c18287 174 errexit("bad inode number %d to ginode\n", inumber);
7026cd3f
KM
175 if (startinum == 0 ||
176 inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
177 iblk = itod(&sblock, inumber);
adc5a10c
KM
178 if (pbp != 0)
179 pbp->b_flags &= ~B_INUSE;
180 pbp = getdatablk(iblk, sblock.fs_bsize);
7026cd3f
KM
181 startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
182 }
adc5a10c
KM
183 return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]);
184}
185
071ea3c2
KM
186/*
187 * Special purpose version of ginode used to optimize first pass
188 * over all the inodes in numerical order.
189 */
190ino_t nextino, lastinum;
191long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
192struct dinode *inodebuf;
193
194struct dinode *
195getnextinode(inumber)
196 ino_t inumber;
197{
198 long size;
199 daddr_t dblk;
200 static struct dinode *dp;
201
202 if (inumber != nextino++ || inumber > maxino)
203 errexit("bad inode number %d to nextinode\n", inumber);
204 if (inumber >= lastinum) {
205 readcnt++;
206 dblk = fsbtodb(&sblock, itod(&sblock, lastinum));
207 if (readcnt % readpercg == 0) {
208 size = partialsize;
209 lastinum += partialcnt;
210 } else {
211 size = inobufsize;
212 lastinum += fullcnt;
213 }
d72e970b 214 (void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */
071ea3c2
KM
215 dp = inodebuf;
216 }
217 return (dp++);
218}
219
220resetinodebuf()
221{
222
68a34947 223 startinum = 0;
071ea3c2
KM
224 nextino = 0;
225 lastinum = 0;
226 readcnt = 0;
227 inobufsize = blkroundup(&sblock, INOBUFSIZE);
228 fullcnt = inobufsize / sizeof(struct dinode);
229 readpercg = sblock.fs_ipg / fullcnt;
230 partialcnt = sblock.fs_ipg % fullcnt;
231 partialsize = partialcnt * sizeof(struct dinode);
232 if (partialcnt != 0) {
233 readpercg++;
234 } else {
235 partialcnt = fullcnt;
236 partialsize = inobufsize;
237 }
238 if (inodebuf == NULL &&
239 (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL)
240 errexit("Cannot allocate space for inode buffer\n");
241 while (nextino < ROOTINO)
d72e970b 242 (void)getnextinode(nextino);
071ea3c2
KM
243}
244
245freeinodebuf()
246{
247
248 if (inodebuf != NULL)
249 free((char *)inodebuf);
250 inodebuf = NULL;
251}
252
253/*
254 * Routines to maintain information about directory inodes.
255 * This is built during the first pass and used during the
256 * second and third passes.
257 *
258 * Enter inodes into the cache.
259 */
57117c0f
KM
260cacheino(dp, inumber)
261 register struct dinode *dp;
262 ino_t inumber;
263{
264 register struct inoinfo *inp;
265 struct inoinfo **inpp;
266 unsigned int blks;
267
57117c0f
KM
268 blks = howmany(dp->di_size, sblock.fs_bsize);
269 if (blks > NDADDR)
270 blks = NDADDR + NIADDR;
271 inp = (struct inoinfo *)
272 malloc(sizeof(*inp) + (blks - 1) * sizeof(daddr_t));
273 if (inp == NULL)
274 return;
071ea3c2
KM
275 inpp = &inphead[inumber % numdirs];
276 inp->i_nexthash = *inpp;
57117c0f 277 *inpp = inp;
071ea3c2
KM
278 inp->i_parent = (ino_t)0;
279 inp->i_dotdot = (ino_t)0;
57117c0f 280 inp->i_number = inumber;
071ea3c2 281 inp->i_isize = dp->di_size;
57117c0f 282 inp->i_numblks = blks * sizeof(daddr_t);
071ea3c2 283 bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0],
d72e970b 284 (size_t)inp->i_numblks);
071ea3c2
KM
285 if (inplast == listmax) {
286 listmax += 100;
287 inpsort = (struct inoinfo **)realloc((char *)inpsort,
288 (unsigned)listmax * sizeof(struct inoinfo *));
289 if (inpsort == NULL)
290 errexit("cannot increase directory list");
291 }
292 inpsort[inplast++] = inp;
57117c0f
KM
293}
294
071ea3c2
KM
295/*
296 * Look up an inode cache structure.
297 */
298struct inoinfo *
299getinoinfo(inumber)
57117c0f
KM
300 ino_t inumber;
301{
302 register struct inoinfo *inp;
57117c0f 303
071ea3c2 304 for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
57117c0f
KM
305 if (inp->i_number != inumber)
306 continue;
071ea3c2 307 return (inp);
57117c0f 308 }
071ea3c2
KM
309 errexit("cannot find inode %d\n", inumber);
310 return ((struct inoinfo *)0);
57117c0f
KM
311}
312
071ea3c2
KM
313/*
314 * Clean up all the inode cache structure.
315 */
57117c0f
KM
316inocleanup()
317{
071ea3c2 318 register struct inoinfo **inpp;
57117c0f
KM
319
320 if (inphead == NULL)
321 return;
071ea3c2
KM
322 for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
323 free((char *)(*inpp));
324 free((char *)inphead);
325 free((char *)inpsort);
326 inphead = inpsort = NULL;
57117c0f
KM
327}
328
adc5a10c
KM
329inodirty()
330{
331
332 dirty(pbp);
7026cd3f
KM
333}
334
569ec282 335clri(idesc, type, flag)
7026cd3f 336 register struct inodesc *idesc;
569ec282
KM
337 char *type;
338 int flag;
7026cd3f 339{
569ec282 340 register struct dinode *dp;
7026cd3f 341
39c18287 342 dp = ginode(idesc->id_number);
569ec282
KM
343 if (flag == 1) {
344 pwarn("%s %s", type,
345 (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
7026cd3f
KM
346 pinode(idesc->id_number);
347 }
348 if (preen || reply("CLEAR") == 1) {
349 if (preen)
350 printf(" (CLEARED)\n");
351 n_files--;
352 (void)ckinode(dp, idesc);
569ec282 353 clearinode(dp);
7026cd3f
KM
354 statemap[idesc->id_number] = USTATE;
355 inodirty();
7026cd3f
KM
356 }
357}
358
3ad2f081
KM
359findname(idesc)
360 struct inodesc *idesc;
361{
569ec282 362 register struct direct *dirp = idesc->id_dirp;
3ad2f081
KM
363
364 if (dirp->d_ino != idesc->id_parent)
365 return (KEEPON);
d72e970b 366 bcopy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1);
315f1422 367 return (STOP|FOUND);
3ad2f081
KM
368}
369
7026cd3f
KM
370findino(idesc)
371 struct inodesc *idesc;
372{
569ec282 373 register struct direct *dirp = idesc->id_dirp;
7026cd3f
KM
374
375 if (dirp->d_ino == 0)
376 return (KEEPON);
3ad2f081 377 if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
569ec282 378 dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
3ad2f081 379 idesc->id_parent = dirp->d_ino;
315f1422 380 return (STOP|FOUND);
7026cd3f
KM
381 }
382 return (KEEPON);
383}
384
385pinode(ino)
386 ino_t ino;
387{
569ec282 388 register struct dinode *dp;
7026cd3f 389 register char *p;
1ccd95ec 390 struct passwd *pw;
7026cd3f
KM
391 char *ctime();
392
d72e970b 393 printf(" I=%lu ", ino);
569ec282 394 if (ino < ROOTINO || ino > maxino)
7026cd3f 395 return;
39c18287 396 dp = ginode(ino);
7026cd3f 397 printf(" OWNER=");
1ccd95ec
KM
398 if ((pw = getpwuid((int)dp->di_uid)) != 0)
399 printf("%s ", pw->pw_name);
400 else
d72e970b 401 printf("%u ", (unsigned)dp->di_uid);
7026cd3f
KM
402 printf("MODE=%o\n", dp->di_mode);
403 if (preen)
404 printf("%s: ", devname);
d72e970b 405 printf("SIZE=%lu ", dp->di_size);
7026cd3f 406 p = ctime(&dp->di_mtime);
7314222d 407 printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
7026cd3f
KM
408}
409
569ec282 410blkerror(ino, type, blk)
7026cd3f 411 ino_t ino;
569ec282 412 char *type;
7026cd3f
KM
413 daddr_t blk;
414{
415
d72e970b 416 pfatal("%ld %s I=%lu", blk, type, ino);
7026cd3f 417 printf("\n");
993a756c
KM
418 switch (statemap[ino]) {
419
420 case FSTATE:
421 statemap[ino] = FCLEAR;
422 return;
423
424 case DSTATE:
425 statemap[ino] = DCLEAR;
426 return;
427
428 case FCLEAR:
429 case DCLEAR:
430 return;
431
432 default:
433 errexit("BAD STATE %d TO BLKERR", statemap[ino]);
434 /* NOTREACHED */
435 }
7026cd3f 436}
ebd05fde
KM
437
438/*
439 * allocate an unused inode
440 */
441ino_t
442allocino(request, type)
443 ino_t request;
444 int type;
445{
446 register ino_t ino;
569ec282 447 register struct dinode *dp;
ebd05fde
KM
448
449 if (request == 0)
450 request = ROOTINO;
451 else if (statemap[request] != USTATE)
452 return (0);
569ec282 453 for (ino = request; ino < maxino; ino++)
ebd05fde
KM
454 if (statemap[ino] == USTATE)
455 break;
569ec282 456 if (ino == maxino)
ebd05fde
KM
457 return (0);
458 switch (type & IFMT) {
459 case IFDIR:
460 statemap[ino] = DSTATE;
461 break;
462 case IFREG:
463 case IFLNK:
464 statemap[ino] = FSTATE;
465 break;
466 default:
467 return (0);
468 }
469 dp = ginode(ino);
569ec282 470 dp->di_db[0] = allocblk((long)1);
ebd05fde
KM
471 if (dp->di_db[0] == 0) {
472 statemap[ino] = USTATE;
473 return (0);
474 }
475 dp->di_mode = type;
d72e970b 476 (void)time(&dp->di_atime);
ebd05fde
KM
477 dp->di_mtime = dp->di_ctime = dp->di_atime;
478 dp->di_size = sblock.fs_fsize;
479 dp->di_blocks = btodb(sblock.fs_fsize);
480 n_files++;
481 inodirty();
482 return (ino);
483}
484
485/*
486 * deallocate an inode
487 */
488freeino(ino)
489 ino_t ino;
490{
491 struct inodesc idesc;
492 extern int pass4check();
569ec282 493 struct dinode *dp;
ebd05fde
KM
494
495 bzero((char *)&idesc, sizeof(struct inodesc));
496 idesc.id_type = ADDR;
497 idesc.id_func = pass4check;
498 idesc.id_number = ino;
499 dp = ginode(ino);
500 (void)ckinode(dp, &idesc);
569ec282 501 clearinode(dp);
ebd05fde
KM
502 inodirty();
503 statemap[ino] = USTATE;
504 n_files--;
505}