130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o/*
280e808fceb61c2061b32593c610893bf07a863eeTheodore Ts'o * bmap.c --- logical to physical block mapping
330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o *
430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * Copyright (C) 1997 Theodore Ts'o.
530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o *
630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * %Begin-Header%
7543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * This file may be redistributed under the terms of the GNU Library
8543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * General Public License, version 2.
930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * %End-Header%
1030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o */
1130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
1230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#include <stdio.h>
1330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#include <string.h>
1430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#if HAVE_UNISTD_H
1530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#include <unistd.h>
1630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#endif
17cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o#include <errno.h>
1830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
19b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h"
20e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include "ext2fsP.h"
2130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
2278d8f90ffae45808096133c461ef1ee0e65de937Theodore Ts'o#if defined(__GNUC__) && !defined(NO_INLINE_FUNCS)
2330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#define _BMAP_INLINE_	__inline__
2430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#else
2530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#define _BMAP_INLINE_
2630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#endif
2730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
2831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'oextern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
29efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			     struct ext2_inode *inode,
3030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			     char *block_buf, int bmap_flags,
3130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			     blk_t block, blk_t *phys_blk);
3230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
3330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#define inode_bmap(inode, nr) ((inode)->i_block[(nr)])
3430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
35efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'ostatic _BMAP_INLINE_ errcode_t block_ind_bmap(ext2_filsys fs, int flags,
36efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o					      blk_t ind, char *block_buf,
3730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o					      int *blocks_alloc,
3830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o					      blk_t nr, blk_t *ret_blk)
3930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o{
4030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	errcode_t	retval;
4130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	blk_t		b;
4230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
4330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (!ind) {
441d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o		if (flags & BMAP_SET)
451d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o			return EXT2_ET_SET_BMAP_NO_IND;
4630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		*ret_blk = 0;
4730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		return 0;
4830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	}
4930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	retval = io_channel_read_blk(fs->io, ind, 1, block_buf);
5030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (retval)
5130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		return retval;
5230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
531d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o	if (flags & BMAP_SET) {
541d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o		b = *ret_blk;
55126a291c768b523bc228b276d3bea82675a86d09Theodore Ts'o#ifdef WORDS_BIGENDIAN
56126a291c768b523bc228b276d3bea82675a86d09Theodore Ts'o		b = ext2fs_swab32(b);
571d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o#endif
581d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o		((blk_t *) block_buf)[nr] = b;
591d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o		return io_channel_write_blk(fs->io, ind, 1, block_buf);
601d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o	}
611d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o
6230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	b = ((blk_t *) block_buf)[nr];
6330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
64126a291c768b523bc228b276d3bea82675a86d09Theodore Ts'o#ifdef WORDS_BIGENDIAN
65126a291c768b523bc228b276d3bea82675a86d09Theodore Ts'o	b = ext2fs_swab32(b);
665df55d7f847e29d23227592a0bb23daad1a61500Theodore Ts'o#endif
6730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
6830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (!b && (flags & BMAP_ALLOC)) {
6930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		b = nr ? ((blk_t *) block_buf)[nr-1] : 0;
7030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		retval = ext2fs_alloc_block(fs, b,
7130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o					    block_buf + fs->blocksize, &b);
7230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		if (retval)
7330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			return retval;
7430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
75126a291c768b523bc228b276d3bea82675a86d09Theodore Ts'o#ifdef WORDS_BIGENDIAN
76126a291c768b523bc228b276d3bea82675a86d09Theodore Ts'o		((blk_t *) block_buf)[nr] = ext2fs_swab32(b);
77126a291c768b523bc228b276d3bea82675a86d09Theodore Ts'o#else
78126a291c768b523bc228b276d3bea82675a86d09Theodore Ts'o		((blk_t *) block_buf)[nr] = b;
795df55d7f847e29d23227592a0bb23daad1a61500Theodore Ts'o#endif
8030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
8130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		retval = io_channel_write_blk(fs->io, ind, 1, block_buf);
8230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		if (retval)
8330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			return retval;
8430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
8530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		(*blocks_alloc)++;
8630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	}
8730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
8830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	*ret_blk = b;
8930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	return 0;
9030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o}
9130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
92546a1ff18cc912003883ff67ba3e87c69f700fc4Theodore Ts'ostatic _BMAP_INLINE_ errcode_t block_dind_bmap(ext2_filsys fs, int flags,
93efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o					       blk_t dind, char *block_buf,
9430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o					       int *blocks_alloc,
9530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o					       blk_t nr, blk_t *ret_blk)
9630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o{
97e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk_t		b = 0;
9830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	errcode_t	retval;
992eb374c9401079aa56aa12f0047ca3866e69b754Theodore Ts'o	blk_t		addr_per_block;
100efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
1012eb374c9401079aa56aa12f0047ca3866e69b754Theodore Ts'o	addr_per_block = (blk_t) fs->blocksize >> 2;
10230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
103efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	retval = block_ind_bmap(fs, flags & ~BMAP_SET, dind, block_buf,
1041d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o				blocks_alloc, nr / addr_per_block, &b);
10530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (retval)
10630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		return retval;
10730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
10830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o				nr % addr_per_block, ret_blk);
10930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	return retval;
11030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o}
11130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
112546a1ff18cc912003883ff67ba3e87c69f700fc4Theodore Ts'ostatic _BMAP_INLINE_ errcode_t block_tind_bmap(ext2_filsys fs, int flags,
113efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o					       blk_t tind, char *block_buf,
11430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o					       int *blocks_alloc,
11530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o					       blk_t nr, blk_t *ret_blk)
11630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o{
117e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk_t		b = 0;
11830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	errcode_t	retval;
1192eb374c9401079aa56aa12f0047ca3866e69b754Theodore Ts'o	blk_t		addr_per_block;
120efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
1212eb374c9401079aa56aa12f0047ca3866e69b754Theodore Ts'o	addr_per_block = (blk_t) fs->blocksize >> 2;
12230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
123efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	retval = block_dind_bmap(fs, flags & ~BMAP_SET, tind, block_buf,
1241d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o				 blocks_alloc, nr / addr_per_block, &b);
12530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (retval)
12630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		return retval;
12730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
12830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o				nr % addr_per_block, ret_blk);
12930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	return retval;
13030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o}
13130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
132e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic errcode_t extent_bmap(ext2_filsys fs, ext2_ino_t ino,
133e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     struct ext2_inode *inode,
134e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     ext2_extent_handle_t handle,
135e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     char *block_buf, int bmap_flags, blk64_t block,
136e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     int *ret_flags, int *blocks_alloc,
137e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     blk64_t *phys_blk);
138e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
139e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic errcode_t implied_cluster_alloc(ext2_filsys fs, ext2_ino_t ino,
140e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				       struct ext2_inode *inode,
141e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				       ext2_extent_handle_t handle,
142e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				       blk64_t lblk, blk64_t *phys_blk)
143e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
144e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t	base_block, pblock = 0;
145e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	int i;
146e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
147e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
148e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					EXT4_FEATURE_RO_COMPAT_BIGALLOC))
149e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return 0;
150e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
151e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	base_block = lblk & ~EXT2FS_CLUSTER_MASK(fs);
152e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	/*
153e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * Except for the logical block (lblk) that was passed in, search all
154e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * blocks in this logical cluster for a mapping to a physical cluster.
155e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * If any such map exists, calculate the physical block that maps to
156e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * the logical block and return that.
157e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 *
158e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * The old code wouldn't even look if (block % cluster_ratio) == 0;
159e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * this is incorrect if we're allocating blocks in reverse order.
160e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 */
161e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	for (i = 0; i < EXT2FS_CLUSTER_RATIO(fs); i++) {
162e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (base_block + i == lblk)
163e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			continue;
164e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		extent_bmap(fs, ino, inode, handle, 0, 0,
165e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			    base_block + i, 0, 0, &pblock);
166e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (pblock)
167e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			break;
168e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
169e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (pblock == 0)
170e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return 0;
171e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	*phys_blk = pblock - i + (lblk - base_block);
172e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return 0;
173e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
174e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
175e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall/* Try to map a logical block to an already-allocated physical cluster. */
176e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallerrcode_t ext2fs_map_cluster_block(ext2_filsys fs, ext2_ino_t ino,
177e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				   struct ext2_inode *inode, blk64_t lblk,
178e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				   blk64_t *pblk)
179e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
180e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2_extent_handle_t handle;
181e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	errcode_t retval;
182e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
183e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	/* Need bigalloc and extents to be enabled */
184e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	*pblk = 0;
185e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
186e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					EXT4_FEATURE_RO_COMPAT_BIGALLOC) ||
187e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	    !(inode->i_flags & EXT4_EXTENTS_FL))
188e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return 0;
189e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
190e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	retval = ext2fs_extent_open2(fs, ino, inode, &handle);
191e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (retval)
192e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		goto out;
193e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
194e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	retval = implied_cluster_alloc(fs, ino, inode, handle, lblk, pblk);
195e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (retval)
196e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		goto out2;
197e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
198e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallout2:
199e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_extent_free(handle);
200e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallout:
201e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return retval;
202e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
203e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
204e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic errcode_t extent_bmap(ext2_filsys fs, ext2_ino_t ino,
205e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     struct ext2_inode *inode,
206e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     ext2_extent_handle_t handle,
207e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     char *block_buf, int bmap_flags, blk64_t block,
208e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     int *ret_flags, int *blocks_alloc,
209e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     blk64_t *phys_blk)
210e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
211e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	struct ext2fs_extent	extent;
212e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	unsigned int		offset;
213e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	errcode_t		retval = 0;
214e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t			blk64 = 0;
215e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	int			alloc = 0;
216e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
217e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (bmap_flags & BMAP_SET) {
218e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		retval = ext2fs_extent_set_bmap(handle, block,
219e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall						*phys_blk, 0);
220e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return retval;
221e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
222e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	retval = ext2fs_extent_goto(handle, block);
223e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (retval) {
224e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		/* If the extent is not found, return phys_blk = 0 */
225e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (retval == EXT2_ET_EXTENT_NOT_FOUND)
226e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			goto got_block;
227e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return retval;
228e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
229e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
230e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (retval)
231e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return retval;
232e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	offset = block - extent.e_lblk;
233e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (block >= extent.e_lblk && (offset <= extent.e_len)) {
234e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		*phys_blk = extent.e_pblk + offset;
235e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (ret_flags && extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
236e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			*ret_flags |= BMAP_RET_UNINIT;
237e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
238e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallgot_block:
239e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
240e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		implied_cluster_alloc(fs, ino, inode, handle, block, &blk64);
241e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (blk64)
242e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			goto set_extent;
243e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		retval = extent_bmap(fs, ino, inode, handle, block_buf,
244e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				     0, block-1, 0, blocks_alloc, &blk64);
245e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (retval)
246e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			blk64 = 0;
247e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		retval = ext2fs_alloc_block2(fs, blk64, block_buf,
248e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					     &blk64);
249e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (retval)
250e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			return retval;
251e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		blk64 &= ~EXT2FS_CLUSTER_MASK(fs);
252e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		blk64 += EXT2FS_CLUSTER_MASK(fs) & block;
253e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		alloc++;
254e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	set_extent:
255e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		retval = ext2fs_extent_set_bmap(handle, block,
256e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall						blk64, 0);
257e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (retval)
258e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			return retval;
259e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		/* Update inode after setting extent */
260e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		retval = ext2fs_read_inode(fs, ino, inode);
261e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (retval)
262e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			return retval;
263e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		*blocks_alloc += alloc;
264e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		*phys_blk = blk64;
265e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
266e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return 0;
267e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
268e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
269e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallint ext2fs_file_block_offset_too_big(ext2_filsys fs,
270e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				     struct ext2_inode *inode,
271e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				     blk64_t offset)
272e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
273e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t addr_per_block, max_map_block;
274e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
275e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	/* Kernel seems to cut us off at 4294967294 blocks */
276e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (offset >= (1ULL << 32) - 1)
277e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return 1;
278e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
279e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (inode->i_flags & EXT4_EXTENTS_FL)
280e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return 0;
281e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
282e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	addr_per_block = fs->blocksize >> 2;
283e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	max_map_block = addr_per_block;
284e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	max_map_block += addr_per_block * addr_per_block;
285e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	max_map_block += addr_per_block * addr_per_block * addr_per_block;
286e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	max_map_block += 12;
287e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
288e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return offset >= max_map_block;
289e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
290e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
291cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'oerrcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
292cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		       char *block_buf, int bmap_flags, blk64_t block,
293cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		       int *ret_flags, blk64_t *phys_blk)
29430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o{
29530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	struct ext2_inode inode_buf;
296cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	ext2_extent_handle_t handle = 0;
2972eb374c9401079aa56aa12f0047ca3866e69b754Theodore Ts'o	blk_t addr_per_block;
298cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	blk_t	b, blk32;
29930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	char	*buf = 0;
30030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	errcode_t	retval = 0;
3011d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o	int		blocks_alloc = 0, inode_dirty = 0;
30230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
3031d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o	if (!(bmap_flags & BMAP_SET))
3041d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o		*phys_blk = 0;
30530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
306cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	if (ret_flags)
307cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		*ret_flags = 0;
308cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o
30930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	/* Read inode structure if necessary */
31030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (!inode) {
31130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		retval = ext2fs_read_inode(fs, ino, &inode_buf);
312b38cd283637dafff6b39d4b76bf76fa2789eb21fTheodore Ts'o		if (retval)
31330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			return retval;
31430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		inode = &inode_buf;
31530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	}
3162eb374c9401079aa56aa12f0047ca3866e69b754Theodore Ts'o	addr_per_block = (blk_t) fs->blocksize >> 2;
31730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
318e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (ext2fs_file_block_offset_too_big(fs, inode, block))
319e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return EXT2_ET_FILE_TOO_BIG;
3201e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong
32130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (!block_buf) {
322ee01079a17bfecd17292ccd60058056fb3a8ba6cTheodore Ts'o		retval = ext2fs_get_array(2, fs->blocksize, &buf);
3237b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		if (retval)
3247b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o			return retval;
32530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		block_buf = buf;
32630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	}
32730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
328e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (inode->i_flags & EXT4_EXTENTS_FL) {
329e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		retval = ext2fs_extent_open2(fs, ino, inode, &handle);
330e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (retval)
331e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			goto done;
332e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		retval = extent_bmap(fs, ino, inode, handle, block_buf,
333e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				     bmap_flags, block, ret_flags,
334e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				     &blocks_alloc, phys_blk);
335e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		goto done;
336e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
337e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
33830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (block < EXT2_NDIR_BLOCKS) {
3391d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o		if (bmap_flags & BMAP_SET) {
3401d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o			b = *phys_blk;
3411d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o			inode_bmap(inode, block) = b;
3421d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o			inode_dirty++;
3431d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o			goto done;
3441d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o		}
3451d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o
34630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		*phys_blk = inode_bmap(inode, block);
34730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		b = block ? inode_bmap(inode, block-1) : 0;
348efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
34930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
35030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			retval = ext2fs_alloc_block(fs, b, block_buf, &b);
35130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			if (retval)
35230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o				goto done;
35330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			inode_bmap(inode, block) = b;
35430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			blocks_alloc++;
35530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			*phys_blk = b;
35630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		}
35730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		goto done;
35830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	}
359efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
36030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	/* Indirect block */
36130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	block -= EXT2_NDIR_BLOCKS;
362cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	blk32 = *phys_blk;
36330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (block < addr_per_block) {
36430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		b = inode_bmap(inode, EXT2_IND_BLOCK);
36530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		if (!b) {
3661d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o			if (!(bmap_flags & BMAP_ALLOC)) {
3671d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o				if (bmap_flags & BMAP_SET)
3681d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o					retval = EXT2_ET_SET_BMAP_NO_IND;
3691d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o				goto done;
3701d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o			}
37130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
37230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			b = inode_bmap(inode, EXT2_IND_BLOCK-1);
37330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o 			retval = ext2fs_alloc_block(fs, b, block_buf, &b);
37430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			if (retval)
37530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o				goto done;
37630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			inode_bmap(inode, EXT2_IND_BLOCK) = b;
37730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			blocks_alloc++;
37830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		}
379efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		retval = block_ind_bmap(fs, bmap_flags, b, block_buf,
380cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o					&blocks_alloc, block, &blk32);
381cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		if (retval == 0)
382cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o			*phys_blk = blk32;
38330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		goto done;
38430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	}
385efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
38630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	/* Doubly indirect block  */
38730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	block -= addr_per_block;
38830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (block < addr_per_block * addr_per_block) {
38930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		b = inode_bmap(inode, EXT2_DIND_BLOCK);
39030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		if (!b) {
3911d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o			if (!(bmap_flags & BMAP_ALLOC)) {
3921d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o				if (bmap_flags & BMAP_SET)
3931d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o					retval = EXT2_ET_SET_BMAP_NO_IND;
3941d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o				goto done;
3951d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o			}
39630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
39730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			b = inode_bmap(inode, EXT2_IND_BLOCK);
39830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o 			retval = ext2fs_alloc_block(fs, b, block_buf, &b);
39930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			if (retval)
40030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o				goto done;
40130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			inode_bmap(inode, EXT2_DIND_BLOCK) = b;
40230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			blocks_alloc++;
40330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		}
404efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		retval = block_dind_bmap(fs, bmap_flags, b, block_buf,
405cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o					 &blocks_alloc, block, &blk32);
406cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		if (retval == 0)
407cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o			*phys_blk = blk32;
40830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		goto done;
40930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	}
41030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
41130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	/* Triply indirect block */
41230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	block -= addr_per_block * addr_per_block;
41330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	b = inode_bmap(inode, EXT2_TIND_BLOCK);
41430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (!b) {
4151d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o		if (!(bmap_flags & BMAP_ALLOC)) {
4161d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o			if (bmap_flags & BMAP_SET)
4171d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o				retval = EXT2_ET_SET_BMAP_NO_IND;
41830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			goto done;
4191d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o		}
42030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
42130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		b = inode_bmap(inode, EXT2_DIND_BLOCK);
42230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		retval = ext2fs_alloc_block(fs, b, block_buf, &b);
42330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		if (retval)
42430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			goto done;
42530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		inode_bmap(inode, EXT2_TIND_BLOCK) = b;
42630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		blocks_alloc++;
42730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	}
428efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	retval = block_tind_bmap(fs, bmap_flags, b, block_buf,
429cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o				 &blocks_alloc, block, &blk32);
430cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	if (retval == 0)
431cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		*phys_blk = blk32;
43230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'odone:
43330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (buf)
434c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&buf);
435cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	if (handle)
436cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		ext2fs_extent_free(handle);
4371d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o	if ((retval == 0) && (blocks_alloc || inode_dirty)) {
4381ca1059fd0126fd2c065f272a566c18f14bab16dTheodore Ts'o		ext2fs_iblk_add_blocks(fs, inode, blocks_alloc);
43930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		retval = ext2fs_write_inode(fs, ino, inode);
44030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	}
44130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	return retval;
44230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o}
44330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
444cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'oerrcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
445cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		      char *block_buf, int bmap_flags, blk_t block,
446cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		      blk_t *phys_blk)
447cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o{
448cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	errcode_t ret;
4499c9e1d5fe507d08309e9815eee50ca73e21bd2bdTheodore Ts'o	blk64_t	ret_blk = *phys_blk;
450cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o
451cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	ret = ext2fs_bmap2(fs, ino, inode, block_buf, bmap_flags, block,
452cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o			    0, &ret_blk);
453cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	if (ret)
454cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		return ret;
455cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	if (ret_blk >= ((long long) 1 << 32))
456cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		return EOVERFLOW;
457cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	*phys_blk = ret_blk;
458cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	return 0;
459cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o}
460