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