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