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