ufs_bmap.c revision 186335
1184610Salfred/*	$NetBSD: ufs_bmap.c,v 1.14 2004/06/20 22:20:18 jmc Exp $	*/
2184610Salfred/* From: NetBSD: ufs_bmap.c,v 1.14 2001/11/08 05:00:51 chs Exp */
3184610Salfred
4184610Salfred/*
5184610Salfred * Copyright (c) 1989, 1991, 1993
6184610Salfred *	The Regents of the University of California.  All rights reserved.
7184610Salfred * (c) UNIX System Laboratories, Inc.
8184610Salfred * All or some portions of this file are derived from material licensed
9184610Salfred * to the University of California by American Telephone and Telegraph
10184610Salfred * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11184610Salfred * the permission of UNIX System Laboratories, Inc.
12184610Salfred *
13184610Salfred * Redistribution and use in source and binary forms, with or without
14184610Salfred * modification, are permitted provided that the following conditions
15184610Salfred * are met:
16184610Salfred * 1. Redistributions of source code must retain the above copyright
17184610Salfred *    notice, this list of conditions and the following disclaimer.
18184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
19184610Salfred *    notice, this list of conditions and the following disclaimer in the
20184610Salfred *    documentation and/or other materials provided with the distribution.
21184610Salfred * 3. Neither the name of the University nor the names of its contributors
22184610Salfred *    may be used to endorse or promote products derived from this software
23184610Salfred *    without specific prior written permission.
24184610Salfred *
25184610Salfred * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29188942Sthompsa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30188942Sthompsa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31188942Sthompsa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32188942Sthompsa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33188942Sthompsa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35184610Salfred * SUCH DAMAGE.
36184610Salfred *
37188942Sthompsa *	@(#)ufs_bmap.c	8.8 (Berkeley) 8/11/95
38188942Sthompsa */
39188942Sthompsa
40188942Sthompsa#include <sys/cdefs.h>
41188942Sthompsa__FBSDID("$FreeBSD: head/usr.sbin/makefs/ffs/ufs_bmap.c 186334 2008-12-19 18:45:43Z sam $");
42188942Sthompsa
43188942Sthompsa#include <sys/param.h>
44188942Sthompsa#include <sys/time.h>
45188942Sthompsa
46184610Salfred#include <assert.h>
47188942Sthompsa#include <errno.h>
48188942Sthompsa#include <strings.h>
49184610Salfred
50184610Salfred#include "makefs.h"
51184610Salfred
52184610Salfred#include <ufs/ufs/dinode.h>
53184610Salfred#include <ufs/ffs/fs.h>
54184610Salfred
55184610Salfred#include "ffs/ufs_bswap.h"
56184610Salfred#include "ffs/ufs_inode.h"
57184610Salfred#include "ffs/ffs_extern.h"
58184610Salfred
59184610Salfred/*
60184610Salfred * Create an array of logical block number/offset pairs which represent the
61184610Salfred * path of indirect blocks required to access a data block.  The first "pair"
62184610Salfred * contains the logical block number of the appropriate single, double or
63184610Salfred * triple indirect block and the offset into the inode indirect block array.
64184610Salfred * Note, the logical block number of the inode single/double/triple indirect
65184610Salfred * block appears twice in the array, once with the offset into the i_ffs_ib and
66184610Salfred * once with the offset into the page itself.
67184610Salfred */
68184610Salfredint
69184610Salfredufs_getlbns(struct inode *ip, daddr_t bn, struct indir *ap, int *nump)
70184610Salfred{
71184610Salfred	daddr_t metalbn, realbn;
72184610Salfred	int64_t blockcnt;
73184610Salfred	int lbc;
74184610Salfred	int i, numlevels, off;
75184610Salfred	u_long lognindir;
76184610Salfred
77184610Salfred	lognindir = ffs(NINDIR(ip->i_fs)) - 1;
78184610Salfred	if (nump)
79184610Salfred		*nump = 0;
80184610Salfred	numlevels = 0;
81184610Salfred	realbn = bn;
82187173Sthompsa	if ((long)bn < 0)
83184610Salfred		bn = -(long)bn;
84184610Salfred
85184610Salfred	assert (bn >= NDADDR);
86184610Salfred
87184610Salfred	/*
88184610Salfred	 * Determine the number of levels of indirection.  After this loop
89184610Salfred	 * is done, blockcnt indicates the number of data blocks possible
90184610Salfred	 * at the given level of indirection, and NIADDR - i is the number
91184610Salfred	 * of levels of indirection needed to locate the requested block.
92184610Salfred	 */
93184610Salfred
94184610Salfred	bn -= NDADDR;
95184610Salfred	for (lbc = 0, i = NIADDR;; i--, bn -= blockcnt) {
96187173Sthompsa		if (i == 0)
97184610Salfred			return (EFBIG);
98184610Salfred
99184610Salfred		lbc += lognindir;
100190731Sthompsa		blockcnt = (int64_t)1 << lbc;
101184610Salfred
102187173Sthompsa		if (bn < blockcnt)
103184610Salfred			break;
104187173Sthompsa	}
105187173Sthompsa
106184610Salfred	/* Calculate the address of the first meta-block. */
107184610Salfred	if (realbn >= 0)
108187173Sthompsa		metalbn = -(realbn - bn + NIADDR - i);
109190731Sthompsa	else
110187173Sthompsa		metalbn = -(-realbn - bn + NIADDR - i);
111190731Sthompsa
112184610Salfred	/*
113184610Salfred	 * At each iteration, off is the offset into the bap array which is
114184610Salfred	 * an array of disk addresses at the current level of indirection.
115184610Salfred	 * The logical block number and the offset in that block are stored
116184610Salfred	 * into the argument array.
117184610Salfred	 */
118184610Salfred	ap->in_lbn = metalbn;
119184610Salfred	ap->in_off = off = NIADDR - i;
120184610Salfred	ap->in_exists = 0;
121184610Salfred	ap++;
122184610Salfred	for (++numlevels; i <= NIADDR; i++) {
123184610Salfred		/* If searching for a meta-data block, quit when found. */
124184610Salfred		if (metalbn == realbn)
125184610Salfred			break;
126184610Salfred
127184610Salfred		lbc -= lognindir;
128184610Salfred		blockcnt = (int64_t)1 << lbc;
129184610Salfred		off = (bn >> lbc) & (NINDIR(ip->i_fs) - 1);
130184610Salfred
131184610Salfred		++numlevels;
132184610Salfred		ap->in_lbn = metalbn;
133184610Salfred		ap->in_off = off;
134184610Salfred		ap->in_exists = 0;
135184610Salfred		++ap;
136184610Salfred
137184610Salfred		metalbn -= -1 + (off << lbc);
138184610Salfred	}
139184610Salfred	if (nump)
140184610Salfred		*nump = numlevels;
141184610Salfred	return (0);
142184610Salfred}
143184610Salfred