1185222Ssam/*	$NetBSD: ufs_bmap.c,v 1.14 2004/06/20 22:20:18 jmc Exp $	*/
2185222Ssam/* From: NetBSD: ufs_bmap.c,v 1.14 2001/11/08 05:00:51 chs Exp */
3185222Ssam
4185222Ssam/*
5185222Ssam * Copyright (c) 1989, 1991, 1993
6185222Ssam *	The Regents of the University of California.  All rights reserved.
7185222Ssam * (c) UNIX System Laboratories, Inc.
8185222Ssam * All or some portions of this file are derived from material licensed
9185222Ssam * to the University of California by American Telephone and Telegraph
10185222Ssam * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11185222Ssam * the permission of UNIX System Laboratories, Inc.
12185222Ssam *
13185222Ssam * Redistribution and use in source and binary forms, with or without
14185222Ssam * modification, are permitted provided that the following conditions
15185222Ssam * are met:
16185222Ssam * 1. Redistributions of source code must retain the above copyright
17185222Ssam *    notice, this list of conditions and the following disclaimer.
18185222Ssam * 2. Redistributions in binary form must reproduce the above copyright
19185222Ssam *    notice, this list of conditions and the following disclaimer in the
20185222Ssam *    documentation and/or other materials provided with the distribution.
21185222Ssam * 3. Neither the name of the University nor the names of its contributors
22185222Ssam *    may be used to endorse or promote products derived from this software
23185222Ssam *    without specific prior written permission.
24185222Ssam *
25185222Ssam * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26185222Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27185222Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28185222Ssam * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29185222Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30185222Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31185222Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32185222Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33185222Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34185222Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35185222Ssam * SUCH DAMAGE.
36185222Ssam *
37185222Ssam *	@(#)ufs_bmap.c	8.8 (Berkeley) 8/11/95
38185222Ssam */
39185222Ssam
40185222Ssam#include <sys/cdefs.h>
41186334Ssam__FBSDID("$FreeBSD$");
42185222Ssam
43185222Ssam#include <sys/param.h>
44185222Ssam#include <sys/time.h>
45185222Ssam
46185222Ssam#include <assert.h>
47185222Ssam#include <errno.h>
48185222Ssam#include <strings.h>
49185222Ssam
50185222Ssam#include "makefs.h"
51185222Ssam
52185222Ssam#include <ufs/ufs/dinode.h>
53185222Ssam#include <ufs/ffs/fs.h>
54185222Ssam
55186261Ssam#include "ffs/ufs_bswap.h"
56185222Ssam#include "ffs/ufs_inode.h"
57185222Ssam#include "ffs/ffs_extern.h"
58185222Ssam
59185222Ssam/*
60185222Ssam * Create an array of logical block number/offset pairs which represent the
61185222Ssam * path of indirect blocks required to access a data block.  The first "pair"
62185222Ssam * contains the logical block number of the appropriate single, double or
63185222Ssam * triple indirect block and the offset into the inode indirect block array.
64185222Ssam * Note, the logical block number of the inode single/double/triple indirect
65185222Ssam * block appears twice in the array, once with the offset into the i_ffs_ib and
66185222Ssam * once with the offset into the page itself.
67185222Ssam */
68185222Ssamint
69185222Ssamufs_getlbns(struct inode *ip, daddr_t bn, struct indir *ap, int *nump)
70185222Ssam{
71185222Ssam	daddr_t metalbn, realbn;
72185222Ssam	int64_t blockcnt;
73185222Ssam	int lbc;
74185222Ssam	int i, numlevels, off;
75185222Ssam	u_long lognindir;
76185222Ssam
77185222Ssam	lognindir = ffs(NINDIR(ip->i_fs)) - 1;
78185222Ssam	if (nump)
79185222Ssam		*nump = 0;
80185222Ssam	numlevels = 0;
81185222Ssam	realbn = bn;
82185222Ssam	if ((long)bn < 0)
83185222Ssam		bn = -(long)bn;
84185222Ssam
85185222Ssam	assert (bn >= NDADDR);
86185222Ssam
87185222Ssam	/*
88185222Ssam	 * Determine the number of levels of indirection.  After this loop
89185222Ssam	 * is done, blockcnt indicates the number of data blocks possible
90185222Ssam	 * at the given level of indirection, and NIADDR - i is the number
91185222Ssam	 * of levels of indirection needed to locate the requested block.
92185222Ssam	 */
93185222Ssam
94185222Ssam	bn -= NDADDR;
95185222Ssam	for (lbc = 0, i = NIADDR;; i--, bn -= blockcnt) {
96185222Ssam		if (i == 0)
97185222Ssam			return (EFBIG);
98185222Ssam
99185222Ssam		lbc += lognindir;
100185222Ssam		blockcnt = (int64_t)1 << lbc;
101185222Ssam
102185222Ssam		if (bn < blockcnt)
103185222Ssam			break;
104185222Ssam	}
105185222Ssam
106185222Ssam	/* Calculate the address of the first meta-block. */
107185222Ssam	if (realbn >= 0)
108185222Ssam		metalbn = -(realbn - bn + NIADDR - i);
109185222Ssam	else
110185222Ssam		metalbn = -(-realbn - bn + NIADDR - i);
111185222Ssam
112185222Ssam	/*
113185222Ssam	 * At each iteration, off is the offset into the bap array which is
114185222Ssam	 * an array of disk addresses at the current level of indirection.
115185222Ssam	 * The logical block number and the offset in that block are stored
116185222Ssam	 * into the argument array.
117185222Ssam	 */
118185222Ssam	ap->in_lbn = metalbn;
119185222Ssam	ap->in_off = off = NIADDR - i;
120185222Ssam	ap++;
121185222Ssam	for (++numlevels; i <= NIADDR; i++) {
122185222Ssam		/* If searching for a meta-data block, quit when found. */
123185222Ssam		if (metalbn == realbn)
124185222Ssam			break;
125185222Ssam
126185222Ssam		lbc -= lognindir;
127185222Ssam		blockcnt = (int64_t)1 << lbc;
128185222Ssam		off = (bn >> lbc) & (NINDIR(ip->i_fs) - 1);
129185222Ssam
130185222Ssam		++numlevels;
131185222Ssam		ap->in_lbn = metalbn;
132185222Ssam		ap->in_off = off;
133185222Ssam		++ap;
134185222Ssam
135185222Ssam		metalbn -= -1 + (off << lbc);
136185222Ssam	}
137185222Ssam	if (nump)
138185222Ssam		*nump = numlevels;
139185222Ssam	return (0);
140185222Ssam}
141