inode.c revision 6404
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.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 <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	if (inumber == ROOTINO)
315		inp->i_parent = ROOTINO;
316	else
317		inp->i_parent = (ino_t)0;
318	inp->i_dotdot = (ino_t)0;
319	inp->i_number = inumber;
320	inp->i_isize = dp->di_size;
321	inp->i_numblks = blks * sizeof(daddr_t);
322	bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0],
323	    (size_t)inp->i_numblks);
324	if (inplast == listmax) {
325		listmax += 100;
326		inpsort = (struct inoinfo **)realloc((char *)inpsort,
327		    (unsigned)listmax * sizeof(struct inoinfo *));
328		if (inpsort == NULL)
329			errexit("cannot increase directory list");
330	}
331	inpsort[inplast++] = inp;
332}
333
334/*
335 * Look up an inode cache structure.
336 */
337struct inoinfo *
338getinoinfo(inumber)
339	ino_t inumber;
340{
341	register struct inoinfo *inp;
342
343	for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
344		if (inp->i_number != inumber)
345			continue;
346		return (inp);
347	}
348	errexit("cannot find inode %d\n", inumber);
349	return ((struct inoinfo *)0);
350}
351
352/*
353 * Clean up all the inode cache structure.
354 */
355inocleanup()
356{
357	register struct inoinfo **inpp;
358
359	if (inphead == NULL)
360		return;
361	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
362		free((char *)(*inpp));
363	free((char *)inphead);
364	free((char *)inpsort);
365	inphead = inpsort = NULL;
366}
367
368inodirty()
369{
370
371	dirty(pbp);
372}
373
374clri(idesc, type, flag)
375	register struct inodesc *idesc;
376	char *type;
377	int flag;
378{
379	register struct dinode *dp;
380
381	dp = ginode(idesc->id_number);
382	if (flag == 1) {
383		pwarn("%s %s", type,
384		    (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
385		pinode(idesc->id_number);
386	}
387	if (preen || reply("CLEAR") == 1) {
388		if (preen)
389			printf(" (CLEARED)\n");
390		n_files--;
391		(void)ckinode(dp, idesc);
392		clearinode(dp);
393		statemap[idesc->id_number] = USTATE;
394		inodirty();
395	}
396}
397
398findname(idesc)
399	struct inodesc *idesc;
400{
401	register struct direct *dirp = idesc->id_dirp;
402
403	if (dirp->d_ino != idesc->id_parent)
404		return (KEEPON);
405	bcopy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1);
406	return (STOP|FOUND);
407}
408
409findino(idesc)
410	struct inodesc *idesc;
411{
412	register struct direct *dirp = idesc->id_dirp;
413
414	if (dirp->d_ino == 0)
415		return (KEEPON);
416	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
417	    dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
418		idesc->id_parent = dirp->d_ino;
419		return (STOP|FOUND);
420	}
421	return (KEEPON);
422}
423
424pinode(ino)
425	ino_t ino;
426{
427	register struct dinode *dp;
428	register char *p;
429	struct passwd *pw;
430	char *ctime();
431
432	printf(" I=%lu ", ino);
433	if (ino < ROOTINO || ino > maxino)
434		return;
435	dp = ginode(ino);
436	printf(" OWNER=");
437	if ((pw = getpwuid((int)dp->di_uid)) != 0)
438		printf("%s ", pw->pw_name);
439	else
440		printf("%u ", (unsigned)dp->di_uid);
441	printf("MODE=%o\n", dp->di_mode);
442	if (preen)
443		printf("%s: ", cdevname);
444	printf("SIZE=%qu ", dp->di_size);
445	p = ctime(&dp->di_mtime.ts_sec);
446	printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
447}
448
449blkerror(ino, type, blk)
450	ino_t ino;
451	char *type;
452	daddr_t blk;
453{
454
455	pfatal("%ld %s I=%lu", blk, type, ino);
456	printf("\n");
457	switch (statemap[ino]) {
458
459	case FSTATE:
460		statemap[ino] = FCLEAR;
461		return;
462
463	case DSTATE:
464		statemap[ino] = DCLEAR;
465		return;
466
467	case FCLEAR:
468	case DCLEAR:
469		return;
470
471	default:
472		errexit("BAD STATE %d TO BLKERR", statemap[ino]);
473		/* NOTREACHED */
474	}
475}
476
477/*
478 * allocate an unused inode
479 */
480ino_t
481allocino(request, type)
482	ino_t request;
483	int type;
484{
485	register ino_t ino;
486	register struct dinode *dp;
487
488	if (request == 0)
489		request = ROOTINO;
490	else if (statemap[request] != USTATE)
491		return (0);
492	for (ino = request; ino < maxino; ino++)
493		if (statemap[ino] == USTATE)
494			break;
495	if (ino == maxino)
496		return (0);
497	switch (type & IFMT) {
498	case IFDIR:
499		statemap[ino] = DSTATE;
500		break;
501	case IFREG:
502	case IFLNK:
503		statemap[ino] = FSTATE;
504		break;
505	default:
506		return (0);
507	}
508	dp = ginode(ino);
509	dp->di_db[0] = allocblk((long)1);
510	if (dp->di_db[0] == 0) {
511		statemap[ino] = USTATE;
512		return (0);
513	}
514	dp->di_mode = type;
515	(void)time(&dp->di_atime.ts_sec);
516	dp->di_mtime = dp->di_ctime = dp->di_atime;
517	dp->di_size = sblock.fs_fsize;
518	dp->di_blocks = btodb(sblock.fs_fsize);
519	n_files++;
520	inodirty();
521	if (newinofmt)
522		typemap[ino] = IFTODT(type);
523	return (ino);
524}
525
526/*
527 * deallocate an inode
528 */
529freeino(ino)
530	ino_t ino;
531{
532	struct inodesc idesc;
533	extern int pass4check();
534	struct dinode *dp;
535
536	bzero((char *)&idesc, sizeof(struct inodesc));
537	idesc.id_type = ADDR;
538	idesc.id_func = pass4check;
539	idesc.id_number = ino;
540	dp = ginode(ino);
541	(void)ckinode(dp, &idesc);
542	clearinode(dp);
543	inodirty();
544	statemap[ino] = USTATE;
545	n_files--;
546}
547