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