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