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