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