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