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