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