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