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