xref: /dflybsd-src/usr.sbin/makefs/ffs/ufs_bmap.c (revision 346b9dadb592a2194dd69cfeaa20cd1808df547d)
15978408cSSascha Wildner /*	$NetBSD: ufs_bmap.c,v 1.14 2004/06/20 22:20:18 jmc Exp $	*/
25978408cSSascha Wildner /* From: NetBSD: ufs_bmap.c,v 1.14 2001/11/08 05:00:51 chs Exp */
35978408cSSascha Wildner 
45978408cSSascha Wildner /*-
55978408cSSascha Wildner  * SPDX-License-Identifier: BSD-3-Clause
65978408cSSascha Wildner  *
75978408cSSascha Wildner  * Copyright (c) 1989, 1991, 1993
85978408cSSascha Wildner  *	The Regents of the University of California.  All rights reserved.
95978408cSSascha Wildner  * (c) UNIX System Laboratories, Inc.
105978408cSSascha Wildner  * All or some portions of this file are derived from material licensed
115978408cSSascha Wildner  * to the University of California by American Telephone and Telegraph
125978408cSSascha Wildner  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
135978408cSSascha Wildner  * the permission of UNIX System Laboratories, Inc.
145978408cSSascha Wildner  *
155978408cSSascha Wildner  * Redistribution and use in source and binary forms, with or without
165978408cSSascha Wildner  * modification, are permitted provided that the following conditions
175978408cSSascha Wildner  * are met:
185978408cSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
195978408cSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
205978408cSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
215978408cSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
225978408cSSascha Wildner  *    documentation and/or other materials provided with the distribution.
235978408cSSascha Wildner  * 3. Neither the name of the University nor the names of its contributors
245978408cSSascha Wildner  *    may be used to endorse or promote products derived from this software
255978408cSSascha Wildner  *    without specific prior written permission.
265978408cSSascha Wildner  *
275978408cSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
285978408cSSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
295978408cSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
305978408cSSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
315978408cSSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
325978408cSSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
335978408cSSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
345978408cSSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
355978408cSSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
365978408cSSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
375978408cSSascha Wildner  * SUCH DAMAGE.
385978408cSSascha Wildner  *
395978408cSSascha Wildner  *	@(#)ufs_bmap.c	8.8 (Berkeley) 8/11/95
40811c2036SSascha Wildner  * $FreeBSD: head/usr.sbin/makefs/ffs/ufs_bmap.c 326025 2017-11-20 19:49:47Z pfg $
415978408cSSascha Wildner  */
425978408cSSascha Wildner 
435978408cSSascha Wildner #include <sys/param.h>
445978408cSSascha Wildner #include <sys/time.h>
455978408cSSascha Wildner 
465978408cSSascha Wildner #include <assert.h>
475978408cSSascha Wildner #include <errno.h>
485978408cSSascha Wildner #include <strings.h>
495978408cSSascha Wildner 
505978408cSSascha Wildner #include "makefs.h"
515978408cSSascha Wildner 
52*346b9dadSzrj #include <vfs/ufs/dinode.h>
53*346b9dadSzrj #include <vfs/ufs/fs.h>
545978408cSSascha Wildner 
555978408cSSascha Wildner #include "ffs/ufs_bswap.h"
565978408cSSascha Wildner #include "ffs/ufs_inode.h"
575978408cSSascha Wildner #include "ffs/ffs_extern.h"
585978408cSSascha Wildner 
595978408cSSascha Wildner /*
605978408cSSascha Wildner  * Create an array of logical block number/offset pairs which represent the
615978408cSSascha Wildner  * path of indirect blocks required to access a data block.  The first "pair"
625978408cSSascha Wildner  * contains the logical block number of the appropriate single, double or
635978408cSSascha Wildner  * triple indirect block and the offset into the inode indirect block array.
645978408cSSascha Wildner  * Note, the logical block number of the inode single/double/triple indirect
655978408cSSascha Wildner  * block appears twice in the array, once with the offset into the i_ffs_ib and
665978408cSSascha Wildner  * once with the offset into the page itself.
675978408cSSascha Wildner  */
685978408cSSascha Wildner int
ufs_getlbns(struct inode * ip,makefs_daddr_t bn,struct indir * ap,int * nump)69811c2036SSascha Wildner ufs_getlbns(struct inode *ip, makefs_daddr_t bn, struct indir *ap, int *nump)
705978408cSSascha Wildner {
71811c2036SSascha Wildner 	makefs_daddr_t metalbn, realbn;
725978408cSSascha Wildner 	int64_t blockcnt;
735978408cSSascha Wildner 	int lbc;
745978408cSSascha Wildner 	int i, numlevels, off;
755978408cSSascha Wildner 	u_long lognindir;
765978408cSSascha Wildner 
775978408cSSascha Wildner 	lognindir = ffs(NINDIR(ip->i_fs)) - 1;
785978408cSSascha Wildner 	if (nump)
795978408cSSascha Wildner 		*nump = 0;
805978408cSSascha Wildner 	numlevels = 0;
815978408cSSascha Wildner 	realbn = bn;
825978408cSSascha Wildner 	if ((long)bn < 0)
835978408cSSascha Wildner 		bn = -(long)bn;
845978408cSSascha Wildner 
855978408cSSascha Wildner 	assert (bn >= UFS_NDADDR);
865978408cSSascha Wildner 
875978408cSSascha Wildner 	/*
885978408cSSascha Wildner 	 * Determine the number of levels of indirection.  After this loop
895978408cSSascha Wildner 	 * is done, blockcnt indicates the number of data blocks possible
905978408cSSascha Wildner 	 * at the given level of indirection, and UFS_NIADDR - i is the number
915978408cSSascha Wildner 	 * of levels of indirection needed to locate the requested block.
925978408cSSascha Wildner 	 */
935978408cSSascha Wildner 
945978408cSSascha Wildner 	bn -= UFS_NDADDR;
955978408cSSascha Wildner 	for (lbc = 0, i = UFS_NIADDR;; i--, bn -= blockcnt) {
965978408cSSascha Wildner 		if (i == 0)
975978408cSSascha Wildner 			return (EFBIG);
985978408cSSascha Wildner 
995978408cSSascha Wildner 		lbc += lognindir;
1005978408cSSascha Wildner 		blockcnt = (int64_t)1 << lbc;
1015978408cSSascha Wildner 
1025978408cSSascha Wildner 		if (bn < blockcnt)
1035978408cSSascha Wildner 			break;
1045978408cSSascha Wildner 	}
1055978408cSSascha Wildner 
1065978408cSSascha Wildner 	/* Calculate the address of the first meta-block. */
1075978408cSSascha Wildner 	if (realbn >= 0)
1085978408cSSascha Wildner 		metalbn = -(realbn - bn + UFS_NIADDR - i);
1095978408cSSascha Wildner 	else
1105978408cSSascha Wildner 		metalbn = -(-realbn - bn + UFS_NIADDR - i);
1115978408cSSascha Wildner 
1125978408cSSascha Wildner 	/*
1135978408cSSascha Wildner 	 * At each iteration, off is the offset into the bap array which is
1145978408cSSascha Wildner 	 * an array of disk addresses at the current level of indirection.
1155978408cSSascha Wildner 	 * The logical block number and the offset in that block are stored
1165978408cSSascha Wildner 	 * into the argument array.
1175978408cSSascha Wildner 	 */
1185978408cSSascha Wildner 	ap->in_lbn = metalbn;
1195978408cSSascha Wildner 	ap->in_off = off = UFS_NIADDR - i;
1205978408cSSascha Wildner 	ap++;
1215978408cSSascha Wildner 	for (++numlevels; i <= UFS_NIADDR; i++) {
1225978408cSSascha Wildner 		/* If searching for a meta-data block, quit when found. */
1235978408cSSascha Wildner 		if (metalbn == realbn)
1245978408cSSascha Wildner 			break;
1255978408cSSascha Wildner 
1265978408cSSascha Wildner 		lbc -= lognindir;
1275978408cSSascha Wildner 		blockcnt = (int64_t)1 << lbc;
1285978408cSSascha Wildner 		off = (bn >> lbc) & (NINDIR(ip->i_fs) - 1);
1295978408cSSascha Wildner 
1305978408cSSascha Wildner 		++numlevels;
1315978408cSSascha Wildner 		ap->in_lbn = metalbn;
1325978408cSSascha Wildner 		ap->in_off = off;
1335978408cSSascha Wildner 		++ap;
1345978408cSSascha Wildner 
1355978408cSSascha Wildner 		metalbn -= -1 + (off << lbc);
1365978408cSSascha Wildner 	}
1375978408cSSascha Wildner 	if (nump)
1385978408cSSascha Wildner 		*nump = numlevels;
1395978408cSSascha Wildner 	return (0);
1405978408cSSascha Wildner }
141