inode.c revision 1.32 1 /* $NetBSD: inode.c,v 1.32 1999/11/15 19:18:24 fvdl 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.32 1999/11/15 19:18:24 fvdl 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 #include <ufs/ffs/ffs_extern.h>
52 #include <ufs/ufs/ufs_bswap.h>
53
54 #ifndef SMALL
55 #include <err.h>
56 #include <pwd.h>
57 #endif
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <time.h>
62
63 #include "fsck.h"
64 #include "fsutil.h"
65 #include "extern.h"
66
67 static ino_t startinum;
68
69 static int iblock __P((struct inodesc *, long, u_int64_t));
70
71 int
72 ckinode(dp, idesc)
73 struct dinode *dp;
74 struct inodesc *idesc;
75 {
76 ufs_daddr_t *ap;
77 long ret, n, ndb, offset;
78 struct dinode dino;
79 u_int64_t sizepb;
80 int64_t remsize;
81 mode_t mode;
82 char pathbuf[MAXPATHLEN + 1];
83
84 if (idesc->id_fix != IGNORE)
85 idesc->id_fix = DONTKNOW;
86 idesc->id_entryno = 0;
87 idesc->id_filesize = iswap64(dp->di_size);
88 mode = iswap16(dp->di_mode) & IFMT;
89 if (mode == IFBLK || mode == IFCHR || (mode == IFLNK &&
90 (idesc->id_filesize < sblock->fs_maxsymlinklen ||
91 (sblock->fs_maxsymlinklen == 0 && dp->di_blocks == 0))))
92 return (KEEPON);
93 dino = *dp;
94 ndb = howmany(iswap64(dino.di_size), sblock->fs_bsize);
95 for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
96 if (--ndb == 0 &&
97 (offset = blkoff(sblock, iswap64(dino.di_size))) != 0)
98 idesc->id_numfrags =
99 numfrags(sblock, fragroundup(sblock, offset));
100 else
101 idesc->id_numfrags = sblock->fs_frag;
102 if (*ap == 0) {
103 if (idesc->id_type == DATA && ndb >= 0) {
104 /* An empty block in a directory XXX */
105 markclean = 0;
106 getpathname(pathbuf, idesc->id_number,
107 idesc->id_number);
108 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
109 pathbuf);
110 if (reply("ADJUST LENGTH") == 1) {
111 dp = ginode(idesc->id_number);
112 dp->di_size = iswap64((ap - &dino.di_db[0]) *
113 sblock->fs_bsize);
114 printf(
115 "YOU MUST RERUN FSCK AFTERWARDS\n");
116 rerun = 1;
117 inodirty();
118 }
119 }
120 continue;
121 }
122 idesc->id_blkno = iswap32(*ap);
123 if (idesc->id_type == ADDR)
124 ret = (*idesc->id_func)(idesc);
125 else
126 ret = dirscan(idesc);
127 if (ret & STOP)
128 return (ret);
129 }
130 idesc->id_numfrags = sblock->fs_frag;
131 remsize = iswap64(dino.di_size) - sblock->fs_bsize * NDADDR;
132 sizepb = sblock->fs_bsize;
133 for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
134 if (*ap) {
135 idesc->id_blkno = iswap32(*ap);
136 ret = iblock(idesc, n, remsize);
137 if (ret & STOP)
138 return (ret);
139 } else {
140 if (idesc->id_type == DATA && remsize > 0) {
141 /* An empty block in a directory XXX */
142 markclean = 0;
143 getpathname(pathbuf, idesc->id_number,
144 idesc->id_number);
145 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
146 pathbuf);
147 if (reply("ADJUST LENGTH") == 1) {
148 dp = ginode(idesc->id_number);
149 dp->di_size = iswap64(iswap64(dp->di_size) - remsize);
150 remsize = 0;
151 printf(
152 "YOU MUST RERUN FSCK AFTERWARDS\n");
153 rerun = 1;
154 inodirty();
155 break;
156 }
157 }
158 }
159 sizepb *= NINDIR(sblock);
160 remsize -= sizepb;
161 }
162 return (KEEPON);
163 }
164
165 static int
166 iblock(idesc, ilevel, isize)
167 struct inodesc *idesc;
168 long ilevel;
169 u_int64_t isize;
170 {
171 ufs_daddr_t *ap;
172 ufs_daddr_t *aplim;
173 struct bufarea *bp;
174 int i, n, (*func) __P((struct inodesc *)), nif;
175 u_int64_t sizepb;
176 char buf[BUFSIZ];
177 char pathbuf[MAXPATHLEN + 1];
178 struct dinode *dp;
179
180 if (idesc->id_type == ADDR) {
181 func = idesc->id_func;
182 if (((n = (*func)(idesc)) & KEEPON) == 0)
183 return (n);
184 } else
185 func = dirscan;
186 if (chkrange(idesc->id_blkno, idesc->id_numfrags))
187 return (SKIP);
188 bp = getdatablk(idesc->id_blkno, sblock->fs_bsize);
189 ilevel--;
190 for (sizepb = sblock->fs_bsize, i = 0; i < ilevel; i++)
191 sizepb *= NINDIR(sblock);
192 if (isize > sizepb * NINDIR(sblock))
193 nif = NINDIR(sblock);
194 else
195 nif = howmany(isize, sizepb);
196 if (do_blkswap) { /* swap byte order of the whole blk */
197 aplim = &bp->b_un.b_indir[nif];
198 for (ap = bp->b_un.b_indir; ap < aplim; ap++)
199 *ap = bswap32(*ap);
200 dirty(bp);
201 flush(fswritefd, bp);
202 }
203 if (idesc->id_func == pass1check && nif < NINDIR(sblock)) {
204 aplim = &bp->b_un.b_indir[NINDIR(sblock)];
205 for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
206 if (*ap == 0)
207 continue;
208 (void)snprintf(buf, sizeof(buf),
209 "PARTIALLY TRUNCATED INODE I=%u", idesc->id_number);
210 if (dofix(idesc, buf)) {
211 *ap = 0;
212 dirty(bp);
213 } else
214 markclean= 0;
215 }
216 flush(fswritefd, bp);
217 }
218 aplim = &bp->b_un.b_indir[nif];
219 for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
220 if (*ap) {
221 idesc->id_blkno = iswap32(*ap);
222 if (ilevel == 0)
223 n = (*func)(idesc);
224 else
225 n = iblock(idesc, ilevel, isize);
226 if (n & STOP) {
227 bp->b_flags &= ~B_INUSE;
228 return (n);
229 }
230 } else {
231 if (idesc->id_type == DATA && isize > 0) {
232 /* An empty block in a directory XXX */
233 markclean= 0;
234 getpathname(pathbuf, idesc->id_number,
235 idesc->id_number);
236 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
237 pathbuf);
238 if (reply("ADJUST LENGTH") == 1) {
239 dp = ginode(idesc->id_number);
240 dp->di_size = iswap64(iswap64(dp->di_size) - isize);
241 isize = 0;
242 printf(
243 "YOU MUST RERUN FSCK AFTERWARDS\n");
244 rerun = 1;
245 inodirty();
246 bp->b_flags &= ~B_INUSE;
247 return(STOP);
248 }
249 }
250 }
251 isize -= sizepb;
252 }
253 bp->b_flags &= ~B_INUSE;
254 return (KEEPON);
255 }
256
257 /*
258 * Check that a block in a legal block number.
259 * Return 0 if in range, 1 if out of range.
260 */
261 int
262 chkrange(blk, cnt)
263 ufs_daddr_t blk;
264 int cnt;
265 {
266 int c;
267
268 if ((unsigned)(blk + cnt) > maxfsblock)
269 return (1);
270 c = dtog(sblock, blk);
271 if (blk < cgdmin(sblock, c)) {
272 if ((blk + cnt) > cgsblock(sblock, c)) {
273 if (debug) {
274 printf("blk %d < cgdmin %d;",
275 blk, cgdmin(sblock, c));
276 printf(" blk + cnt %d > cgsbase %d\n",
277 blk + cnt, cgsblock(sblock, c));
278 }
279 return (1);
280 }
281 } else {
282 if ((blk + cnt) > cgbase(sblock, c+1)) {
283 if (debug) {
284 printf("blk %d >= cgdmin %d;",
285 blk, cgdmin(sblock, c));
286 printf(" blk + cnt %d > sblock->fs_fpg %d\n",
287 blk+cnt, sblock->fs_fpg);
288 }
289 return (1);
290 }
291 }
292 return (0);
293 }
294
295 /*
296 * General purpose interface for reading inodes.
297 */
298 struct dinode *
299 ginode(inumber)
300 ino_t inumber;
301 {
302 ufs_daddr_t iblk;
303 int blkoff;
304
305 if (inumber < ROOTINO || inumber > maxino)
306 errx(EEXIT, "bad inode number %d to ginode", inumber);
307 if (startinum == 0 ||
308 inumber < startinum || inumber >= startinum + INOPB(sblock)) {
309 iblk = ino_to_fsba(sblock, inumber);
310 if (pbp != 0)
311 pbp->b_flags &= ~B_INUSE;
312 pbp = getdatablk(iblk, sblock->fs_bsize);
313 startinum = (inumber / INOPB(sblock)) * INOPB(sblock);
314 }
315 blkoff = (inumber % INOPB(sblock)) * DINODE_SIZE;
316 return ((struct dinode *)((caddr_t)pbp->b_un.b_buf + blkoff));
317 }
318
319 /*
320 * Special purpose version of ginode used to optimize first pass
321 * over all the inodes in numerical order.
322 */
323 ino_t nextino, lastinum;
324 long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
325 struct dinode *inodebuf;
326
327 struct dinode *
328 getnextinode(inumber)
329 ino_t inumber;
330 {
331 long size;
332 ufs_daddr_t dblk;
333 static struct dinode *dp;
334
335 if (inumber != nextino++ || inumber > maxino)
336 errx(EEXIT, "bad inode number %d to nextinode", inumber);
337 if (inumber >= lastinum) {
338 readcnt++;
339 dblk = fsbtodb(sblock, ino_to_fsba(sblock, lastinum));
340 if (readcnt % readpercg == 0) {
341 size = partialsize;
342 lastinum += partialcnt;
343 } else {
344 size = inobufsize;
345 lastinum += fullcnt;
346 }
347 (void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */
348 if (doswap) {
349 int i, j;
350 for (i = inumber, dp = inodebuf; i < lastinum; i++, dp++) {
351 ffs_dinode_swap(dp, dp);
352 /* ffs_dinode_swap() doesn't swap blocks addrs */
353 if ((iswap16(dp->di_mode) & IFMT) != IFLNK ||
354 iswap64(dp->di_size) > sblock->fs_maxsymlinklen) {
355 for (j=0; j<NDADDR + NIADDR; j++)
356 dp->di_db[j] = bswap32(dp->di_db[j]);
357 }
358 }
359 bwrite(fswritefd, (char *)inodebuf, dblk, size);
360 }
361 dp = inodebuf;
362 }
363 return (dp++);
364 }
365
366 void
367 resetinodebuf()
368 {
369
370 startinum = 0;
371 nextino = 0;
372 lastinum = 0;
373 readcnt = 0;
374 inobufsize = blkroundup(sblock, INOBUFSIZE);
375 fullcnt = inobufsize / DINODE_SIZE;
376 readpercg = sblock->fs_ipg / fullcnt;
377 partialcnt = sblock->fs_ipg % fullcnt;
378 partialsize = partialcnt * DINODE_SIZE;
379 if (partialcnt != 0) {
380 readpercg++;
381 } else {
382 partialcnt = fullcnt;
383 partialsize = inobufsize;
384 }
385 if (inodebuf == NULL &&
386 (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL)
387 errx(EEXIT, "Cannot allocate space for inode buffer");
388 while (nextino < ROOTINO)
389 (void)getnextinode(nextino);
390 }
391
392 void
393 freeinodebuf()
394 {
395
396 if (inodebuf != NULL)
397 free((char *)inodebuf);
398 inodebuf = NULL;
399 }
400
401 /*
402 * Routines to maintain information about directory inodes.
403 * This is built during the first pass and used during the
404 * second and third passes.
405 *
406 * Enter inodes into the cache.
407 */
408 void
409 cacheino(dp, inumber)
410 struct dinode *dp;
411 ino_t inumber;
412 {
413 struct inoinfo *inp;
414 struct inoinfo **inpp;
415 unsigned int blks;
416
417 blks = howmany(iswap64(dp->di_size), sblock->fs_bsize);
418 if (blks > NDADDR)
419 blks = NDADDR + NIADDR;
420 inp = (struct inoinfo *)
421 malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs_daddr_t));
422 if (inp == NULL)
423 return;
424 inpp = &inphead[inumber % numdirs];
425 inp->i_nexthash = *inpp;
426 *inpp = inp;
427 inp->i_child = inp->i_sibling = inp->i_parentp = 0;
428 if (inumber == ROOTINO)
429 inp->i_parent = ROOTINO;
430 else
431 inp->i_parent = (ino_t)0;
432 inp->i_dotdot = (ino_t)0;
433 inp->i_number = inumber;
434 inp->i_isize = iswap64(dp->di_size);
435 inp->i_numblks = blks * sizeof(ufs_daddr_t);
436 memmove(&inp->i_blks[0], &dp->di_db[0], (size_t)inp->i_numblks);
437 if (inplast == listmax) {
438 listmax += 100;
439 inpsort = (struct inoinfo **)realloc((char *)inpsort,
440 (unsigned)listmax * sizeof(struct inoinfo *));
441 if (inpsort == NULL)
442 errx(EEXIT, "cannot increase directory list");
443 }
444 inpsort[inplast++] = inp;
445 }
446
447 /*
448 * Look up an inode cache structure.
449 */
450 struct inoinfo *
451 getinoinfo(inumber)
452 ino_t inumber;
453 {
454 struct inoinfo *inp;
455
456 for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
457 if (inp->i_number != inumber)
458 continue;
459 return (inp);
460 }
461 errx(EEXIT, "cannot find inode %d", inumber);
462 return ((struct inoinfo *)0);
463 }
464
465 /*
466 * Clean up all the inode cache structure.
467 */
468 void
469 inocleanup()
470 {
471 struct inoinfo **inpp;
472
473 if (inphead == NULL)
474 return;
475 for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
476 free((char *)(*inpp));
477 free((char *)inphead);
478 free((char *)inpsort);
479 inphead = inpsort = NULL;
480 }
481
482 void
483 inodirty()
484 {
485
486 dirty(pbp);
487 }
488
489 void
490 clri(idesc, type, flag)
491 struct inodesc *idesc;
492 char *type;
493 int flag;
494 {
495 struct dinode *dp;
496
497 dp = ginode(idesc->id_number);
498 if (flag == 1) {
499 pwarn("%s %s", type,
500 (iswap16(dp->di_mode) & IFMT) == IFDIR ? "DIR" : "FILE");
501 pinode(idesc->id_number);
502 }
503 if (preen || reply("CLEAR") == 1) {
504 if (preen)
505 printf(" (CLEARED)\n");
506 n_files--;
507 (void)ckinode(dp, idesc);
508 clearinode(dp);
509 statemap[idesc->id_number] = USTATE;
510 inodirty();
511 } else
512 markclean= 0;
513 }
514
515 int
516 findname(idesc)
517 struct inodesc *idesc;
518 {
519 struct direct *dirp = idesc->id_dirp;
520
521 if (iswap32(dirp->d_ino) != idesc->id_parent)
522 return (KEEPON);
523 memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
524 return (STOP|FOUND);
525 }
526
527 int
528 findino(idesc)
529 struct inodesc *idesc;
530 {
531 struct direct *dirp = idesc->id_dirp;
532
533 if (dirp->d_ino == 0)
534 return (KEEPON);
535 if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
536 iswap32(dirp->d_ino) >= ROOTINO && iswap32(dirp->d_ino) <= maxino) {
537 idesc->id_parent = iswap32(dirp->d_ino);
538 return (STOP|FOUND);
539 }
540 return (KEEPON);
541 }
542
543 void
544 pinode(ino)
545 ino_t ino;
546 {
547 struct dinode *dp;
548 char *p;
549 struct passwd *pw;
550 time_t t;
551
552 printf(" I=%u ", ino);
553 if (ino < ROOTINO || ino > maxino)
554 return;
555 dp = ginode(ino);
556 printf(" OWNER=");
557 #ifndef SMALL
558 if ((pw = getpwuid((int)iswap32(dp->di_uid))) != 0)
559 printf("%s ", pw->pw_name);
560 else
561 #endif
562 printf("%u ", (unsigned)iswap32(dp->di_uid));
563 printf("MODE=%o\n", iswap16(dp->di_mode));
564 if (preen)
565 printf("%s: ", cdevname());
566 printf("SIZE=%qu ", (unsigned long long)iswap64(dp->di_size));
567 t = iswap32(dp->di_mtime);
568 p = ctime(&t);
569 printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
570 }
571
572 void
573 blkerror(ino, type, blk)
574 ino_t ino;
575 char *type;
576 ufs_daddr_t blk;
577 {
578
579 pfatal("%d %s I=%u", blk, type, ino);
580 printf("\n");
581 switch (statemap[ino]) {
582
583 case FSTATE:
584 statemap[ino] = FCLEAR;
585 return;
586
587 case DSTATE:
588 statemap[ino] = DCLEAR;
589 return;
590
591 case FCLEAR:
592 case DCLEAR:
593 return;
594
595 default:
596 errx(EEXIT, "BAD STATE %d TO BLKERR", statemap[ino]);
597 /* NOTREACHED */
598 }
599 }
600
601 /*
602 * allocate an unused inode
603 */
604 ino_t
605 allocino(request, type)
606 ino_t request;
607 int type;
608 {
609 ino_t ino;
610 struct dinode *dp;
611 time_t t;
612 struct cg *cgp = cgrp;
613 int cg;
614
615 if (request == 0)
616 request = ROOTINO;
617 else if (statemap[request] != USTATE)
618 return (0);
619 for (ino = request; ino < maxino; ino++)
620 if (statemap[ino] == USTATE)
621 break;
622 if (ino == maxino)
623 return (0);
624 cg = ino_to_cg(sblock, ino);
625 getblk(&cgblk, cgtod(sblock, cg), sblock->fs_cgsize);
626 memcpy(cgp, cgblk.b_un.b_cg, sblock->fs_cgsize);
627 if ((doswap && !needswap) || (!doswap && needswap))
628 swap_cg(cgblk.b_un.b_cg, cgp);
629 if (!cg_chkmagic(cgp, 0))
630 pfatal("CG %d: ALLOCINO: BAD MAGIC NUMBER\n", cg);
631 if (doswap)
632 cgdirty();
633 setbit(cg_inosused(cgp, 0), ino % sblock->fs_ipg);
634 cgp->cg_cs.cs_nifree--;
635 switch (type & IFMT) {
636 case IFDIR:
637 statemap[ino] = DSTATE;
638 cgp->cg_cs.cs_ndir++;
639 break;
640 case IFREG:
641 case IFLNK:
642 statemap[ino] = FSTATE;
643 break;
644 default:
645 return (0);
646 }
647 cgdirty();
648 dp = ginode(ino);
649 dp->di_db[0] = iswap32(allocblk((long)1));
650 if (dp->di_db[0] == 0) {
651 statemap[ino] = USTATE;
652 return (0);
653 }
654 dp->di_mode = iswap16(type);
655 dp->di_flags = 0;
656 (void)time(&t);
657 dp->di_atime = iswap32(t);
658 dp->di_mtime = dp->di_ctime = dp->di_atime;
659 dp->di_size = iswap64(sblock->fs_fsize);
660 dp->di_blocks = iswap32(btodb(sblock->fs_fsize));
661 n_files++;
662 inodirty();
663 if (newinofmt)
664 typemap[ino] = IFTODT(type);
665 return (ino);
666 }
667
668 /*
669 * deallocate an inode
670 */
671 void
672 freeino(ino)
673 ino_t ino;
674 {
675 struct inodesc idesc;
676 struct 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 statemap[ino] = USTATE;
687 n_files--;
688 }
689