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