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