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