1/*	$NetBSD: inode.c,v 1.64 2011/03/06 17:08:16 bouyer Exp $	*/
2
3/*
4 * Copyright (c) 1980, 1986, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33#ifndef lint
34#if 0
35static char sccsid[] = "@(#)inode.c	8.8 (Berkeley) 4/28/95";
36#else
37__RCSID("$NetBSD: inode.c,v 1.64 2011/03/06 17:08:16 bouyer Exp $");
38#endif
39#endif /* not lint */
40
41#include <sys/param.h>
42#include <sys/time.h>
43#include <sys/stat.h>
44
45#include <ufs/ufs/dinode.h>
46#include <ufs/ufs/dir.h>
47#include <ufs/ffs/fs.h>
48#include <ufs/ffs/ffs_extern.h>
49#include <ufs/ufs/ufs_bswap.h>
50
51#ifndef SMALL
52#include <err.h>
53#include <pwd.h>
54#endif
55#include <stdio.h>
56#include <stdlib.h>
57#include <string.h>
58#include <time.h>
59
60#include "fsck.h"
61#include "fsutil.h"
62#include "extern.h"
63
64static ino_t startinum;
65
66static int iblock(struct inodesc *, long, u_int64_t);
67static void swap_dinode1(union dinode *, int);
68static void swap_dinode2(union dinode *, int);
69
70int
71ckinode(union dinode *dp, struct inodesc *idesc)
72{
73	int ret, offset, i;
74	union dinode dino;
75	u_int64_t sizepb;
76	int64_t remsize;
77	daddr_t ndb;
78	mode_t mode;
79	char pathbuf[MAXPATHLEN + 1];
80
81	if (idesc->id_fix != IGNORE)
82		idesc->id_fix = DONTKNOW;
83	idesc->id_entryno = 0;
84	idesc->id_filesize = iswap64(DIP(dp, size));
85	mode = iswap16(DIP(dp, mode)) & IFMT;
86	if (mode == IFBLK || mode == IFCHR || (mode == IFLNK &&
87	    (idesc->id_filesize < sblock->fs_maxsymlinklen ||
88	    (isappleufs && (idesc->id_filesize < APPLEUFS_MAXSYMLINKLEN)) ||
89	     (sblock->fs_maxsymlinklen == 0 && DIP(dp, blocks) == 0))))
90		return (KEEPON);
91	if (is_ufs2)
92		dino.dp2 = dp->dp2;
93	else
94		dino.dp1 = dp->dp1;
95	ndb = howmany(iswap64(DIP(&dino, size)), sblock->fs_bsize);
96	for (i = 0; i < NDADDR; i++) {
97		if (--ndb == 0 &&
98		    (offset = blkoff(sblock, iswap64(DIP(&dino, size)))) != 0)
99			idesc->id_numfrags =
100				numfrags(sblock, fragroundup(sblock, offset));
101		else
102			idesc->id_numfrags = sblock->fs_frag;
103		if (DIP(&dino, db[i]) == 0) {
104			if (idesc->id_type == DATA && ndb >= 0) {
105				/* An empty block in a directory XXX */
106				markclean = 0;
107				getpathname(pathbuf, sizeof(pathbuf),
108				    idesc->id_number, idesc->id_number);
109				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
110				    pathbuf);
111				if (reply("ADJUST LENGTH") == 1) {
112					dp = ginode(idesc->id_number);
113					DIP_SET(dp, size, iswap64(i *
114					    sblock->fs_bsize));
115					printf(
116					    "YOU MUST RERUN FSCK AFTERWARDS\n");
117					rerun = 1;
118					inodirty();
119				}
120			}
121			continue;
122		}
123		if (is_ufs2)
124			idesc->id_blkno = iswap64(dino.dp2.di_db[i]);
125		else
126			idesc->id_blkno = iswap32(dino.dp1.di_db[i]);
127		if (idesc->id_type != DATA)
128			ret = (*idesc->id_func)(idesc);
129		else
130			ret = dirscan(idesc);
131		if (ret & STOP)
132			return (ret);
133	}
134	idesc->id_numfrags = sblock->fs_frag;
135	remsize = iswap64(DIP(&dino, size)) - sblock->fs_bsize * NDADDR;
136	sizepb = sblock->fs_bsize;
137	for (i = 0; i < NIADDR; i++) {
138		if (DIP(&dino, ib[i])) {
139			if (is_ufs2)
140				idesc->id_blkno = iswap64(dino.dp2.di_ib[i]);
141			else
142				idesc->id_blkno = iswap32(dino.dp1.di_ib[i]);
143			ret = iblock(idesc, i + 1, remsize);
144			if (ret & STOP)
145				return (ret);
146		} else {
147			if (idesc->id_type == DATA && remsize > 0) {
148				/* An empty block in a directory XXX */
149				markclean = 0;
150				getpathname(pathbuf, sizeof(pathbuf),
151				    idesc->id_number, idesc->id_number);
152				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
153				    pathbuf);
154				if (reply("ADJUST LENGTH") == 1) {
155					dp = ginode(idesc->id_number);
156					DIP_SET(dp, size,
157					    iswap64(iswap64(DIP(dp, size))
158						- remsize));
159					remsize = 0;
160					printf(
161					    "YOU MUST RERUN FSCK AFTERWARDS\n");
162					rerun = 1;
163					inodirty();
164					break;
165				}
166			}
167		}
168		sizepb *= NINDIR(sblock);
169		remsize -= sizepb;
170	}
171	return (KEEPON);
172}
173
174static int
175iblock(struct inodesc *idesc, long ilevel, u_int64_t isize)
176{
177	struct bufarea *bp;
178	int i, n, (*func) (struct inodesc *), nif;
179	u_int64_t sizepb;
180	char buf[BUFSIZ];
181	char pathbuf[MAXPATHLEN + 1];
182	union dinode *dp;
183
184	if (idesc->id_type != DATA) {
185		func = idesc->id_func;
186		if (((n = (*func)(idesc)) & KEEPON) == 0)
187			return (n);
188	} else
189		func = dirscan;
190	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
191		return (SKIP);
192	bp = getdatablk(idesc->id_blkno, sblock->fs_bsize);
193	ilevel--;
194	for (sizepb = sblock->fs_bsize, i = 0; i < ilevel; i++)
195		sizepb *= NINDIR(sblock);
196	if (howmany(isize, sizepb) > (size_t)NINDIR(sblock))
197		nif = NINDIR(sblock);
198	else
199		nif = howmany(isize, sizepb);
200	if (do_blkswap) { /* swap byte order of the whole blk */
201		if (is_ufs2) {
202			for (i = 0; i < nif; i++)
203				bp->b_un.b_indir2[i] =
204				    bswap64(bp->b_un.b_indir2[i]);
205		} else {
206			for (i = 0; i < nif; i++)
207				bp->b_un.b_indir1[i] =
208				    bswap32(bp->b_un.b_indir1[i]);
209		}
210		dirty(bp);
211		flush(fswritefd, bp);
212	}
213	if (idesc->id_func == pass1check && nif < NINDIR(sblock)) {
214		for (i = nif; i < NINDIR(sblock); i++) {
215			if (IBLK(bp, i) == 0)
216				continue;
217			(void)snprintf(buf, sizeof(buf),
218			    "PARTIALLY TRUNCATED INODE I=%llu",
219			    (unsigned long long)idesc->id_number);
220			if (dofix(idesc, buf)) {
221				IBLK_SET(bp, i, 0);
222				dirty(bp);
223			} else
224				markclean = 0;
225		}
226		flush(fswritefd, bp);
227	}
228	for (i = 0; i < nif; i++) {
229		if (IBLK(bp, i)) {
230			if (is_ufs2)
231				idesc->id_blkno = iswap64(bp->b_un.b_indir2[i]);
232			else
233				idesc->id_blkno = iswap32(bp->b_un.b_indir1[i]);
234			if (ilevel == 0)
235				n = (*func)(idesc);
236			else
237				n = iblock(idesc, ilevel, isize);
238			if (n & STOP) {
239				bp->b_flags &= ~B_INUSE;
240				return (n);
241			}
242		} else {
243			if (idesc->id_type == DATA && isize > 0) {
244				/* An empty block in a directory XXX */
245				markclean = 0;
246				getpathname(pathbuf, sizeof(pathbuf),
247				    idesc->id_number, idesc->id_number);
248				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
249				    pathbuf);
250				if (reply("ADJUST LENGTH") == 1) {
251					dp = ginode(idesc->id_number);
252					DIP_SET(dp, size,
253					    iswap64(iswap64(DIP(dp, size))
254						- isize));
255					isize = 0;
256					printf(
257					    "YOU MUST RERUN FSCK AFTERWARDS\n");
258					rerun = 1;
259					inodirty();
260					bp->b_flags &= ~B_INUSE;
261					return(STOP);
262				}
263			}
264		}
265		isize -= sizepb;
266	}
267	bp->b_flags &= ~B_INUSE;
268	return (KEEPON);
269}
270
271/*
272 * Check that a block in a legal block number.
273 * Return 0 if in range, 1 if out of range.
274 */
275int
276chkrange(daddr_t blk, int cnt)
277{
278	int c;
279
280	if (cnt <= 0 || blk <= 0 || blk > maxfsblock ||
281	    cnt - 1 > maxfsblock - blk)
282		return (1);
283	if (cnt > sblock->fs_frag ||
284	    fragnum(sblock, blk) + cnt > sblock->fs_frag) {
285		if (debug)
286			printf("bad size: blk %lld, offset %d, size %d\n",
287			    (long long)blk, (int)fragnum(sblock, blk), cnt);
288	}
289	c = dtog(sblock, blk);
290	if (blk < cgdmin(sblock, c)) {
291		if ((blk + cnt) > cgsblock(sblock, c)) {
292			if (debug) {
293				printf("blk %lld < cgdmin %lld;",
294				    (long long)blk,
295				    (long long)cgdmin(sblock, c));
296				printf(" blk + cnt %lld > cgsbase %lld\n",
297				    (long long)(blk + cnt),
298				    (long long)cgsblock(sblock, c));
299			}
300			return (1);
301		}
302	} else {
303		if ((blk + cnt) > cgbase(sblock, c+1)) {
304			if (debug)  {
305				printf("blk %lld >= cgdmin %lld;",
306				    (long long)blk,
307				    (long long)cgdmin(sblock, c));
308				printf(" blk + cnt %lld > sblock->fs_fpg %d\n",
309				    (long long)(blk+cnt), sblock->fs_fpg);
310			}
311			return (1);
312		}
313	}
314	return (0);
315}
316
317/*
318 * General purpose interface for reading inodes.
319 */
320union dinode *
321ginode(ino_t inumber)
322{
323	daddr_t iblk;
324	int blkoff;
325
326	if (inumber < ROOTINO || inumber > maxino)
327		errexit("bad inode number %llu to ginode",
328		    (unsigned long long)inumber);
329	if (startinum == 0 ||
330	    inumber < startinum || inumber >= startinum + INOPB(sblock)) {
331		iblk = ino_to_fsba(sblock, inumber);
332		if (pbp != 0)
333			pbp->b_flags &= ~B_INUSE;
334		pbp = getdatablk(iblk, sblock->fs_bsize);
335		startinum = (inumber / INOPB(sblock)) * INOPB(sblock);
336	}
337	if (is_ufs2) {
338		blkoff = (inumber % INOPB(sblock)) * DINODE2_SIZE;
339		return ((union dinode *)((caddr_t)pbp->b_un.b_buf + blkoff));
340	}
341	blkoff = (inumber % INOPB(sblock)) * DINODE1_SIZE;
342	return ((union dinode *)((caddr_t)pbp->b_un.b_buf + blkoff));
343}
344
345static void
346swap_dinode1(union dinode *dp, int n)
347{
348	int i, j;
349	struct ufs1_dinode *dp1;
350	int32_t maxsymlinklen = sblock->fs_maxsymlinklen;
351	if (isappleufs)
352		maxsymlinklen = APPLEUFS_MAXSYMLINKLEN;
353
354	dp1 = (struct ufs1_dinode *)&dp->dp1;
355	for (i = 0; i < n; i++, dp1++) {
356		ffs_dinode1_swap(dp1, dp1);
357		if (((iswap16(dp1->di_mode) & IFMT) != IFLNK) ||
358		    doinglevel2 ||
359		    (maxsymlinklen < 0) ||
360		    (iswap64(dp1->di_size) > (uint64_t)maxsymlinklen)) {
361			for (j = 0; j < (NDADDR + NIADDR); j++)
362			    dp1->di_db[j] = bswap32(dp1->di_db[j]);
363		}
364	}
365}
366
367static void
368swap_dinode2(union dinode *dp, int n)
369{
370	int i, j;
371	struct ufs2_dinode *dp2;
372
373	dp2 = (struct ufs2_dinode *)&dp->dp2;
374	for (i = 0; i < n; i++, dp2++) {
375		ffs_dinode2_swap(dp2, dp2);
376		if ((iswap16(dp2->di_mode) & IFMT) != IFLNK) {
377			for (j = 0; j < (NDADDR + NIADDR + NXADDR); j++)
378				dp2->di_extb[j] = bswap64(dp2->di_extb[j]);
379		}
380	}
381}
382
383/*
384 * Special purpose version of ginode used to optimize first pass
385 * over all the inodes in numerical order.
386 */
387ino_t nextino, lastinum, lastvalidinum;
388long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
389union dinode *inodebuf;
390
391union dinode *
392getnextinode(ino_t inumber)
393{
394	long size;
395	daddr_t dblk;
396	static union dinode *dp;
397	union dinode *ret;
398
399	if (inumber != nextino++ || inumber > lastvalidinum)
400		errexit("bad inode number %llu to nextinode",
401		    (unsigned long long)inumber);
402
403	if (inumber >= lastinum) {
404		readcnt++;
405		dblk = fsbtodb(sblock, ino_to_fsba(sblock, lastinum));
406		if (readcnt % readpercg == 0) {
407			size = partialsize;
408			lastinum += partialcnt;
409		} else {
410			size = inobufsize;
411			lastinum += fullcnt;
412		}
413		(void)bread(fsreadfd, (caddr_t)inodebuf, dblk, size);
414		if (doswap) {
415			if (is_ufs2)
416				swap_dinode2(inodebuf, lastinum - inumber);
417			else
418				swap_dinode1(inodebuf, lastinum - inumber);
419			bwrite(fswritefd, (char *)inodebuf, dblk, size);
420		}
421		dp = (union dinode *)inodebuf;
422	}
423	ret = dp;
424	dp = (union dinode *)
425	    ((char *)dp + (is_ufs2 ? DINODE2_SIZE : DINODE1_SIZE));
426	return ret;
427}
428
429void
430setinodebuf(ino_t inum)
431{
432
433	if (inum % sblock->fs_ipg != 0)
434		errexit("bad inode number %llu to setinodebuf",
435		    (unsigned long long)inum);
436
437	lastvalidinum = inum + sblock->fs_ipg - 1;
438	startinum = 0;
439	nextino = inum;
440	lastinum = inum;
441	readcnt = 0;
442	if (inodebuf != NULL)
443		return;
444	inobufsize = blkroundup(sblock, INOBUFSIZE);
445	fullcnt = inobufsize / (is_ufs2 ? DINODE2_SIZE : DINODE1_SIZE);
446	readpercg = sblock->fs_ipg / fullcnt;
447	partialcnt = sblock->fs_ipg % fullcnt;
448	partialsize = partialcnt * (is_ufs2 ? DINODE2_SIZE : DINODE1_SIZE);
449	if (partialcnt != 0) {
450		readpercg++;
451	} else {
452		partialcnt = fullcnt;
453		partialsize = inobufsize;
454	}
455	if (inodebuf == NULL &&
456	    (inodebuf = malloc((unsigned)inobufsize)) == NULL)
457		errexit("Cannot allocate space for inode buffer");
458}
459
460void
461freeinodebuf(void)
462{
463
464	if (inodebuf != NULL)
465		free((char *)inodebuf);
466	inodebuf = NULL;
467}
468
469/*
470 * Routines to maintain information about directory inodes.
471 * This is built during the first pass and used during the
472 * second and third passes.
473 *
474 * Enter inodes into the cache.
475 */
476void
477cacheino(union dinode *dp, ino_t inumber)
478{
479	struct inoinfo *inp;
480	struct inoinfo **inpp, **ninpsort;
481	unsigned int i, blks, extra;
482	int64_t size;
483
484	size = iswap64(DIP(dp, size));
485	blks = howmany(size, sblock->fs_bsize);
486	if (blks > NDADDR)
487		blks = NDADDR + NIADDR;
488	if (blks > 0)
489		extra = (blks - 1) * sizeof (int64_t);
490	else
491		extra = 0;
492	inp = malloc(sizeof(*inp) + extra);
493	if (inp == NULL)
494		return;
495	inpp = &inphead[inumber % dirhash];
496	inp->i_nexthash = *inpp;
497	*inpp = inp;
498	inp->i_child = inp->i_sibling = 0;
499	if (inumber == ROOTINO)
500		inp->i_parent = ROOTINO;
501	else
502		inp->i_parent = (ino_t)0;
503	inp->i_dotdot = (ino_t)0;
504	inp->i_number = inumber;
505	inp->i_isize = size;
506	inp->i_numblks = blks;
507	for (i = 0; i < (blks < NDADDR ? blks : NDADDR); i++)
508		inp->i_blks[i] = DIP(dp, db[i]);
509	if (blks > NDADDR)
510		for (i = 0; i < NIADDR; i++)
511			inp->i_blks[NDADDR + i] = DIP(dp, ib[i]);
512	if (inplast == listmax) {
513		ninpsort = (struct inoinfo **)realloc((char *)inpsort,
514		    (unsigned)(listmax + 100) * sizeof(struct inoinfo *));
515		if (inpsort == NULL)
516			errexit("cannot increase directory list");
517		inpsort = ninpsort;
518		listmax += 100;
519	}
520	inpsort[inplast++] = inp;
521}
522
523/*
524 * Look up an inode cache structure.
525 */
526struct inoinfo *
527getinoinfo(ino_t inumber)
528{
529	struct inoinfo *inp;
530
531	for (inp = inphead[inumber % dirhash]; inp; inp = inp->i_nexthash) {
532		if (inp->i_number != inumber)
533			continue;
534		return (inp);
535	}
536	errexit("cannot find inode %llu", (unsigned long long)inumber);
537	return ((struct inoinfo *)0);
538}
539
540/*
541 * Clean up all the inode cache structure.
542 */
543void
544inocleanup(void)
545{
546	struct inoinfo **inpp;
547
548	if (inphead == NULL)
549		return;
550	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
551		free((char *)(*inpp));
552	free((char *)inphead);
553	free((char *)inpsort);
554	inphead = inpsort = NULL;
555}
556
557void
558inodirty(void)
559{
560
561	dirty(pbp);
562}
563
564void
565clri(struct inodesc *idesc, const char *type, int flag)
566{
567	union dinode *dp;
568
569	dp = ginode(idesc->id_number);
570	if (flag == 1) {
571		pwarn("%s %s", type,
572		    (iswap16(DIP(dp, mode)) & IFMT) == IFDIR ? "DIR" : "FILE");
573		pinode(idesc->id_number);
574	}
575	if (preen || reply("CLEAR") == 1) {
576		if (preen)
577			printf(" (CLEARED)\n");
578		n_files--;
579		/*
580		 * ckinode will call id_func (actually always pass4check)
581		 * which will update the block count
582		 */
583		if (idesc->id_type != SNAP)
584			update_uquot(idesc->id_number,
585			    idesc->id_uid, idesc->id_gid, 0, -1);
586		(void)ckinode(dp, idesc);
587		clearinode(dp);
588		inoinfo(idesc->id_number)->ino_state = USTATE;
589		inodirty();
590	} else
591		markclean = 0;
592}
593
594int
595findname(struct inodesc *idesc)
596{
597	struct direct *dirp = idesc->id_dirp;
598	size_t len;
599	char *buf;
600
601	if (iswap32(dirp->d_ino) != idesc->id_parent || idesc->id_entryno < 2) {
602		idesc->id_entryno++;
603		return (KEEPON);
604	}
605	if ((len = dirp->d_namlen + 1) > MAXPATHLEN) {
606		/* XXX: We don't fix but we ignore */
607		len = MAXPATHLEN;
608	}
609	/* this is namebuf from utilities.c */
610	buf = __UNCONST(idesc->id_name);
611	(void)memcpy(buf, dirp->d_name, (size_t)dirp->d_namlen + 1);
612	return (STOP|FOUND);
613}
614
615int
616findino(struct inodesc *idesc)
617{
618	struct direct *dirp = idesc->id_dirp;
619
620	if (dirp->d_ino == 0)
621		return (KEEPON);
622	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
623	    iswap32(dirp->d_ino) >= ROOTINO && iswap32(dirp->d_ino) <= maxino) {
624		idesc->id_parent = iswap32(dirp->d_ino);
625		return (STOP|FOUND);
626	}
627	return (KEEPON);
628}
629
630int
631clearentry(struct inodesc *idesc)
632{
633	struct direct *dirp = idesc->id_dirp;
634
635	if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) {
636		idesc->id_entryno++;
637		return (KEEPON);
638	}
639	dirp->d_ino = 0;
640	return (STOP|FOUND|ALTERED);
641}
642
643void
644pinode(ino_t ino)
645{
646	union dinode *dp;
647	struct passwd *pw;
648
649	printf(" I=%llu ", (unsigned long long)ino);
650	if (ino < ROOTINO || ino > maxino)
651		return;
652	dp = ginode(ino);
653	printf(" OWNER=");
654#ifndef SMALL
655	if (Uflag && (pw = getpwuid((int)iswap32(DIP(dp, uid)))) != 0)
656		printf("%s ", pw->pw_name);
657	else
658#endif
659		printf("%u ", (unsigned)iswap32(DIP(dp, uid)));
660	printf("MODE=%o\n", iswap16(DIP(dp, mode)));
661	if (preen)
662		printf("%s: ", cdevname());
663	printf("SIZE=%llu ", (unsigned long long)iswap64(DIP(dp, size)));
664	printf("MTIME=%s ", print_mtime(iswap32(DIP(dp, mtime))));
665}
666
667void
668blkerror(ino_t ino, const char *type, daddr_t blk)
669{
670	struct inostat *info;
671
672	pfatal("%lld %s I=%llu", (long long)blk, type, (unsigned long long)ino);
673	printf("\n");
674	info = inoinfo(ino);
675	switch (info->ino_state) {
676
677	case FSTATE:
678		info->ino_state = FCLEAR;
679		return;
680
681	case DSTATE:
682		info->ino_state = DCLEAR;
683		return;
684
685	case FCLEAR:
686	case DCLEAR:
687		return;
688
689	default:
690		errexit("BAD STATE %d TO BLKERR", info->ino_state);
691		/* NOTREACHED */
692	}
693}
694
695/*
696 * allocate an unused inode
697 */
698ino_t
699allocino(ino_t request, int type)
700{
701	ino_t ino;
702	union dinode *dp;
703	struct ufs1_dinode *dp1;
704	struct ufs2_dinode *dp2;
705	time_t t;
706	struct cg *cgp = cgrp;
707	int cg;
708	struct inostat *info = NULL;
709	int nfrags;
710
711	if (request == 0)
712		request = ROOTINO;
713	else if (inoinfo(request)->ino_state != USTATE)
714		return (0);
715	for (ino = request; ino < maxino; ino++) {
716		info = inoinfo(ino);
717		if (info->ino_state == USTATE)
718			break;
719	}
720	if (ino == maxino)
721		return (0);
722	cg = ino_to_cg(sblock, ino);
723	/* If necessary, extend the inoinfo array. grow exponentially */
724	if ((ino % sblock->fs_ipg) >= (uint64_t)inostathead[cg].il_numalloced) {
725		unsigned long newalloced, i;
726		newalloced = MIN(sblock->fs_ipg,
727			MAX(2 * inostathead[cg].il_numalloced, 10));
728		info = calloc(newalloced, sizeof(struct inostat));
729		if (info == NULL) {
730			pwarn("cannot alloc %lu bytes to extend inoinfo\n",
731				sizeof(struct inostat) * newalloced);
732			return 0;
733		}
734		memmove(info, inostathead[cg].il_stat,
735			inostathead[cg].il_numalloced * sizeof(*info));
736		for (i = inostathead[cg].il_numalloced; i < newalloced; i++) {
737			info[i].ino_state = USTATE;
738		}
739		if (inostathead[cg].il_numalloced)
740			free(inostathead[cg].il_stat);
741		inostathead[cg].il_stat = info;
742		inostathead[cg].il_numalloced = newalloced;
743		info = inoinfo(ino);
744	}
745	getblk(&cgblk, cgtod(sblock, cg), sblock->fs_cgsize);
746	memcpy(cgp, cgblk.b_un.b_cg, sblock->fs_cgsize);
747	if ((doswap && !needswap) || (!doswap && needswap))
748		ffs_cg_swap(cgblk.b_un.b_cg, cgp, sblock);
749	if (!cg_chkmagic(cgp, 0))
750		pfatal("CG %d: ALLOCINO: BAD MAGIC NUMBER\n", cg);
751	if (doswap)
752		cgdirty();
753	setbit(cg_inosused(cgp, 0), ino % sblock->fs_ipg);
754	cgp->cg_cs.cs_nifree--;
755	sblock->fs_cstotal.cs_nifree--;
756	sblock->fs_cs(fs, cg).cs_nifree--;
757	sbdirty();
758	switch (type & IFMT) {
759	case IFDIR:
760		info->ino_state = DSTATE;
761		cgp->cg_cs.cs_ndir++;
762		nfrags = 1;
763		break;
764	case IFREG:
765		info->ino_state = FSTATE;
766		nfrags = sblock->fs_frag;
767		break;
768	case IFLNK:
769		info->ino_state = FSTATE;
770		nfrags = 1;
771		break;
772	default:
773		return (0);
774	}
775	cgdirty();
776	dp = ginode(ino);
777	if (is_ufs2) {
778		dp2 = &dp->dp2;
779		dp2->di_db[0] = iswap64(allocblk(nfrags));
780		if (dp2->di_db[0] == 0) {
781			info->ino_state = USTATE;
782			return (0);
783		}
784		dp2->di_mode = iswap16(type);
785		dp2->di_flags = 0;
786		(void)time(&t);
787		dp2->di_atime = iswap64(t);
788		dp2->di_mtime = dp2->di_ctime = dp2->di_atime;
789		dp2->di_size = iswap64(lfragtosize(sblock, nfrags));
790		dp2->di_blocks = iswap64(btodb(lfragtosize(sblock, nfrags)));
791	} else {
792		dp1 = &dp->dp1;
793		dp1->di_db[0] = iswap32(allocblk(nfrags));
794		if (dp1->di_db[0] == 0) {
795			info->ino_state = USTATE;
796			return (0);
797		}
798		dp1->di_mode = iswap16(type);
799		dp1->di_flags = 0;
800		(void)time(&t);
801		dp1->di_atime = iswap32(t);
802		dp1->di_mtime = dp1->di_ctime = dp1->di_atime;
803		dp1->di_size = iswap64(lfragtosize(sblock, nfrags));
804		dp1->di_blocks = iswap32(btodb(lfragtosize(sblock, nfrags)));
805	}
806	n_files++;
807	inodirty();
808	if (newinofmt)
809		info->ino_type = IFTODT(type);
810	return (ino);
811}
812
813/*
814 * deallocate an inode
815 */
816void
817freeino(ino_t ino)
818{
819	struct inodesc idesc;
820	union dinode *dp;
821	struct cg *cgp = cgrp;
822	int cg;
823
824	cg = ino_to_cg(sblock, ino);
825	getblk(&cgblk, cgtod(sblock, cg), sblock->fs_cgsize);
826	memcpy(cgp, cgblk.b_un.b_cg, sblock->fs_cgsize);
827	if ((doswap && !needswap) || (!doswap && needswap))
828		ffs_cg_swap(cgblk.b_un.b_cg, cgp, sblock);
829	if (!cg_chkmagic(cgp, 0)) {
830		pwarn("CG %d: FREEINO: BAD MAGIC NUMBER\n", cg);
831		cgp = NULL;
832	}
833
834	memset(&idesc, 0, sizeof(struct inodesc));
835	idesc.id_func = pass4check;
836	idesc.id_number = ino;
837	dp = ginode(ino);
838	idesc.id_uid = iswap32(DIP(dp, uid));
839	idesc.id_gid = iswap32(DIP(dp, gid));
840	if (iswap32(DIP(dp, flags)) & SF_SNAPSHOT)
841		idesc.id_type = SNAP;
842	else
843		idesc.id_type = ADDR;
844	(void)ckinode(dp, &idesc);
845	clearinode(dp);
846	inodirty();
847	inoinfo(ino)->ino_state = USTATE;
848	if (idesc.id_type != SNAP)
849		update_uquot(idesc.id_number,
850		    idesc.id_uid, idesc.id_gid, 0, -1);
851	n_files--;
852	if (cgp) {
853		clrbit(cg_inosused(cgp, 0), ino % sblock->fs_ipg);
854		cgp->cg_cs.cs_nifree++;
855		sblock->fs_cstotal.cs_nifree++;
856		sblock->fs_cs(fs, cg).cs_nifree++;
857		sbdirty();
858		cgdirty();
859	}
860}
861
862/* read a data block from inode */
863ssize_t
864readblk(union dinode *dp, off_t offset, struct bufarea **bp)
865{
866	daddr_t blkno = lblkno(sblock, offset);
867	daddr_t iblkno;
868	int type = IFMT & iswap16(DIP(dp, mode));
869	ssize_t filesize = iswap64(DIP(dp, size));
870	int ilevel;
871	daddr_t nblks;
872	const daddr_t naddrperblk = sblock->fs_bsize /
873	    (is_ufs2 ? sizeof(uint64_t) : sizeof(uint32_t));
874	struct bufarea *ibp;
875
876	*bp = NULL;
877	offset &= ~(sblock->fs_bsize - 1);
878
879	if (type != IFREG)
880		return 0;
881	if (offset >= filesize)
882		return 0; /* short read */
883	if (blkno < NDADDR) {
884		blkno = is_ufs2 ? iswap64(dp->dp2.di_db[blkno]) :
885		    iswap32(dp->dp1.di_db[blkno]);
886		if (blkno == 0)
887			return 0;
888		*bp = getdatablk(blkno, sblock->fs_bsize);
889		return (bp != NULL) ? sblock->fs_bsize : 0;
890	}
891	blkno -= NDADDR;
892	/* find indir level */
893	for (ilevel = 1, nblks = naddrperblk;
894	     ilevel <= NIADDR;
895	     ilevel++, nblks *= naddrperblk) {
896		if (blkno < nblks)
897			break;
898		else
899			blkno -= nblks;
900	}
901	if (ilevel > NIADDR)
902		errexit("bad ofsset %" PRIu64 " to readblk", offset);
903
904	/* get the first indirect block */
905	iblkno = is_ufs2 ? iswap64(dp->dp2.di_ib[ilevel - 1]) :
906		    iswap32(dp->dp1.di_ib[ilevel - 1]);
907	if (iblkno == 0)
908		return 0;
909	ibp = getdatablk(iblkno, sblock->fs_bsize);
910	/* walk indirect blocks up to the data block */
911	for (; ilevel >0 ; ilevel--) {
912		nblks = nblks / naddrperblk;
913		if (is_ufs2)
914			iblkno = iswap64(ibp->b_un.b_indir2[blkno / nblks]);
915		else
916			iblkno = iswap32(ibp->b_un.b_indir1[blkno / nblks]);
917		if (iblkno == 0)
918			return 0;
919		blkno = blkno % nblks;
920		ibp->b_flags &= ~B_INUSE;
921		ibp = getdatablk(iblkno, sblock->fs_bsize);
922	}
923	*bp = ibp;
924	return sblock->fs_bsize;
925}
926
927static struct bufarea * getnewblk(daddr_t *);
928static struct bufarea *
929getnewblk(daddr_t *blkno)
930{
931	struct bufarea *bp;
932	*blkno = allocblk(sblock->fs_frag);
933	if (*blkno == 0)
934		return NULL;
935	bp = getdatablk(*blkno, sblock->fs_bsize);
936	memset(bp->b_un.b_buf, 0, sblock->fs_bsize);
937	return bp;
938}
939
940/* expand given inode by one full fs block */
941struct bufarea *
942expandfile(union dinode *dp)
943{
944	uint64_t filesize = iswap64(DIP(dp, size));
945	daddr_t newblk, blkno, iblkno, nblks;
946	daddr_t di_blocks;
947	int ilevel;
948	const daddr_t naddrperblk = sblock->fs_bsize /
949	    (is_ufs2 ? sizeof(uint64_t) : sizeof(uint32_t));
950	struct bufarea *ibp, *bp = NULL;
951
952	di_blocks = is_ufs2 ? iswap64(dp->dp2.di_blocks) :
953	    iswap32(dp->dp1.di_blocks);
954	/* compute location of new block */
955	blkno = lblkno(sblock, filesize);
956
957	if (blkno < NDADDR) {
958		/* easy way: allocate a direct block */
959		if ((bp = getnewblk(&newblk)) == NULL) {
960			return NULL;
961		}
962		di_blocks += btodb(sblock->fs_bsize);
963
964		if (is_ufs2) {
965			dp->dp2.di_db[blkno] = iswap64(newblk);
966		} else {
967			dp->dp1.di_db[blkno] = iswap32(newblk);
968		}
969		goto out;
970	}
971	blkno -= NDADDR;
972	/* find indir level */
973	for (ilevel = 1, nblks = naddrperblk;
974	     ilevel <= NIADDR;
975	     ilevel++, nblks *= naddrperblk) {
976		if (blkno < nblks)
977			break;
978		else
979			blkno -= nblks;
980	}
981	if (ilevel > NIADDR)
982		errexit("bad filesize %" PRIu64 " to expandfile", filesize);
983
984	/* get the first indirect block, allocating if needed */
985	if ((is_ufs2 ? iswap64(dp->dp2.di_ib[ilevel - 1]) :
986		iswap32(dp->dp1.di_ib[ilevel - 1])) == 0) {
987		if ((ibp = getnewblk(&newblk)) == NULL)
988			return 0;
989		di_blocks += btodb(sblock->fs_bsize);
990		if (is_ufs2)
991			dp->dp2.di_ib[ilevel - 1] = iswap64(newblk);
992		else
993			dp->dp1.di_ib[ilevel - 1] = iswap32(newblk);
994	} else {
995		ibp = getdatablk(is_ufs2 ? iswap64(dp->dp2.di_ib[ilevel - 1]) :
996		    iswap32(dp->dp1.di_ib[ilevel - 1]), sblock->fs_bsize);
997	}
998	/* walk indirect blocks up to the data block */
999	for (; ilevel >0 ; ilevel--) {
1000		nblks = nblks / naddrperblk;
1001		if (is_ufs2)
1002			iblkno = iswap64(ibp->b_un.b_indir2[blkno / nblks]);
1003		else
1004			iblkno = iswap32(ibp->b_un.b_indir1[blkno / nblks]);
1005		if (iblkno == 0) {
1006			if ((bp = getnewblk(&newblk)) == NULL)
1007				return NULL;
1008			di_blocks += btodb(sblock->fs_bsize);
1009			if (is_ufs2)
1010				ibp->b_un.b_indir2[blkno / nblks] =
1011				    iswap64(newblk);
1012			else
1013				ibp->b_un.b_indir1[blkno / nblks] =
1014				    iswap32(newblk);
1015			dirty(ibp);
1016			ibp->b_flags &= ~B_INUSE;
1017			ibp = bp;
1018		} else {
1019			ibp->b_flags &= ~B_INUSE;
1020			ibp = getdatablk(iblkno, sblock->fs_bsize);
1021			bp = NULL;
1022		}
1023		blkno = blkno % nblks;
1024	}
1025	if (bp == NULL) {
1026		errexit("INTERNAL ERROR: "
1027		    "expandfile() failed to allocate a new block\n");
1028	}
1029
1030out:
1031	filesize += sblock->fs_bsize;
1032	if (is_ufs2) {
1033		dp->dp2.di_size = iswap64(filesize);
1034		dp->dp2.di_blocks = iswap64(di_blocks);
1035	} else {
1036		dp->dp1.di_size = iswap64(filesize);
1037		dp->dp1.di_blocks = iswap32(di_blocks);
1038	}
1039	inodirty();
1040	return bp;
1041}
1042