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