bmap.c revision 31dbecd482405e0d3a67eb58e1a1c8cb9f2ad83e
1/*
2 * bmap.c --- logical to physical block mapping
3 *
4 * Copyright (C) 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17
18#if EXT2_FLAT_INCLUDES
19#include "ext2_fs.h"
20#else
21#include <linux/ext2_fs.h>
22#endif
23
24#include "ext2fs.h"
25
26#if defined(__GNUC__) && !defined(NO_INLINE_FUNCS)
27#define _BMAP_INLINE_	__inline__
28#else
29#define _BMAP_INLINE_
30#endif
31
32extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
33			     struct ext2_inode *inode,
34			     char *block_buf, int bmap_flags,
35			     blk_t block, blk_t *phys_blk);
36
37#define BMAP_ALLOC	1
38
39#define inode_bmap(inode, nr) ((inode)->i_block[(nr)])
40
41static errcode_t _BMAP_INLINE_ block_ind_bmap(ext2_filsys fs, int flags,
42					      blk_t ind, char *block_buf,
43					      int *blocks_alloc,
44					      blk_t nr, blk_t *ret_blk)
45{
46	errcode_t	retval;
47	blk_t		b;
48
49	if (!ind) {
50		*ret_blk = 0;
51		return 0;
52	}
53	retval = io_channel_read_blk(fs->io, ind, 1, block_buf);
54	if (retval)
55		return retval;
56
57	b = ((blk_t *) block_buf)[nr];
58
59	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
60	    (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
61		b = ext2fs_swab32(b);
62
63	if (!b && (flags & BMAP_ALLOC)) {
64		b = nr ? ((blk_t *) block_buf)[nr-1] : 0;
65		retval = ext2fs_alloc_block(fs, b,
66					    block_buf + fs->blocksize, &b);
67		if (retval)
68			return retval;
69
70		if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
71		    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
72			((blk_t *) block_buf)[nr] = ext2fs_swab32(b);
73		else
74			((blk_t *) block_buf)[nr] = b;
75
76		retval = io_channel_write_blk(fs->io, ind, 1, block_buf);
77		if (retval)
78			return retval;
79
80		(*blocks_alloc)++;
81	}
82
83	*ret_blk = b;
84	return 0;
85}
86
87static errcode_t _BMAP_INLINE_ block_dind_bmap(ext2_filsys fs, int flags,
88					       blk_t dind, char *block_buf,
89					       int *blocks_alloc,
90					       blk_t nr, blk_t *ret_blk)
91{
92	blk_t		b;
93	errcode_t	retval;
94	blk_t		addr_per_block;
95
96	addr_per_block = (blk_t) fs->blocksize >> 2;
97
98	retval = block_ind_bmap(fs, flags, dind, block_buf, blocks_alloc,
99				nr / addr_per_block, &b);
100	if (retval)
101		return retval;
102	retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
103				nr % addr_per_block, ret_blk);
104	return retval;
105}
106
107static errcode_t _BMAP_INLINE_ block_tind_bmap(ext2_filsys fs, int flags,
108					       blk_t tind, char *block_buf,
109					       int *blocks_alloc,
110					       blk_t nr, blk_t *ret_blk)
111{
112	blk_t		b;
113	errcode_t	retval;
114	blk_t		addr_per_block;
115
116	addr_per_block = (blk_t) fs->blocksize >> 2;
117
118	retval = block_dind_bmap(fs, flags, tind, block_buf, blocks_alloc,
119				 nr / addr_per_block, &b);
120	if (retval)
121		return retval;
122	retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
123				nr % addr_per_block, ret_blk);
124	return retval;
125}
126
127errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
128		      char *block_buf, int bmap_flags, blk_t block,
129		      blk_t *phys_blk)
130{
131	struct ext2_inode inode_buf;
132	blk_t addr_per_block;
133	blk_t	b;
134	char	*buf = 0;
135	errcode_t	retval = 0;
136	int		blocks_alloc = 0;
137
138	*phys_blk = 0;
139
140	/* Read inode structure if necessary */
141	if (!inode) {
142		retval = ext2fs_read_inode(fs, ino, &inode_buf);
143		if (!retval)
144			return retval;
145		inode = &inode_buf;
146	}
147	addr_per_block = (blk_t) fs->blocksize >> 2;
148
149	if (!block_buf) {
150		retval = ext2fs_get_mem(fs->blocksize * 2, (void **) &buf);
151		if (retval)
152			return retval;
153		block_buf = buf;
154	}
155
156	if (block < EXT2_NDIR_BLOCKS) {
157		*phys_blk = inode_bmap(inode, block);
158		b = block ? inode_bmap(inode, block-1) : 0;
159
160		if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
161			retval = ext2fs_alloc_block(fs, b, block_buf, &b);
162			if (retval)
163				goto done;
164			inode_bmap(inode, block) = b;
165			blocks_alloc++;
166			*phys_blk = b;
167		}
168		goto done;
169	}
170
171	/* Indirect block */
172	block -= EXT2_NDIR_BLOCKS;
173	if (block < addr_per_block) {
174		b = inode_bmap(inode, EXT2_IND_BLOCK);
175		if (!b) {
176			if (!(bmap_flags & BMAP_ALLOC))
177			    goto done;
178
179			b = inode_bmap(inode, EXT2_IND_BLOCK-1);
180 			retval = ext2fs_alloc_block(fs, b, block_buf, &b);
181			if (retval)
182				goto done;
183			inode_bmap(inode, EXT2_IND_BLOCK) = b;
184			blocks_alloc++;
185		}
186		retval = block_ind_bmap(fs, bmap_flags, b, block_buf,
187					&blocks_alloc, block, phys_blk);
188		goto done;
189	}
190
191	/* Doubly indirect block  */
192	block -= addr_per_block;
193	if (block < addr_per_block * addr_per_block) {
194		b = inode_bmap(inode, EXT2_DIND_BLOCK);
195		if (!b) {
196			if (!(bmap_flags & BMAP_ALLOC))
197			    goto done;
198
199			b = inode_bmap(inode, EXT2_IND_BLOCK);
200 			retval = ext2fs_alloc_block(fs, b, block_buf, &b);
201			if (retval)
202				goto done;
203			inode_bmap(inode, EXT2_DIND_BLOCK) = b;
204			blocks_alloc++;
205		}
206		retval = block_dind_bmap(fs, bmap_flags, b, block_buf,
207					 &blocks_alloc, block, phys_blk);
208		goto done;
209	}
210
211	/* Triply indirect block */
212	block -= addr_per_block * addr_per_block;
213	b = inode_bmap(inode, EXT2_TIND_BLOCK);
214	if (!b) {
215		if (!(bmap_flags & BMAP_ALLOC))
216			goto done;
217
218		b = inode_bmap(inode, EXT2_DIND_BLOCK);
219		retval = ext2fs_alloc_block(fs, b, block_buf, &b);
220		if (retval)
221			goto done;
222		inode_bmap(inode, EXT2_TIND_BLOCK) = b;
223		blocks_alloc++;
224	}
225	retval = block_tind_bmap(fs, bmap_flags, b, block_buf,
226				 &blocks_alloc, block, phys_blk);
227done:
228	if (buf)
229		ext2fs_free_mem((void **) &buf);
230	if ((retval == 0) && blocks_alloc) {
231		inode->i_blocks += (blocks_alloc * fs->blocksize) / 512;
232		retval = ext2fs_write_inode(fs, ino, inode);
233	}
234	return retval;
235}
236
237
238
239