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