• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
27 extern 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 inode_bmap(inode, nr) ((inode)->i_block[(nr)])
33 
block_ind_bmap(ext2_filsys fs,int flags,blk_t ind,char * block_buf,int * blocks_alloc,blk_t nr,blk_t * ret_blk)34 static _BMAP_INLINE_ errcode_t block_ind_bmap(ext2_filsys fs, int flags,
35 					      blk_t ind, char *block_buf,
36 					      int *blocks_alloc,
37 					      blk_t nr, blk_t *ret_blk)
38 {
39 	errcode_t	retval;
40 	blk_t		b;
41 
42 	if (!ind) {
43 		if (flags & BMAP_SET)
44 			return EXT2_ET_SET_BMAP_NO_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 	if (flags & BMAP_SET) {
53 		b = *ret_blk;
54 #ifdef EXT2FS_ENABLE_SWAPFS
55 		if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
56 		    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
57 			b = ext2fs_swab32(b);
58 #endif
59 		((blk_t *) block_buf)[nr] = b;
60 		return io_channel_write_blk(fs->io, ind, 1, block_buf);
61 	}
62 
63 	b = ((blk_t *) block_buf)[nr];
64 
65 #ifdef EXT2FS_ENABLE_SWAPFS
66 	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
67 	    (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
68 		b = ext2fs_swab32(b);
69 #endif
70 
71 	if (!b && (flags & BMAP_ALLOC)) {
72 		b = nr ? ((blk_t *) block_buf)[nr-1] : 0;
73 		retval = ext2fs_alloc_block(fs, b,
74 					    block_buf + fs->blocksize, &b);
75 		if (retval)
76 			return retval;
77 
78 #ifdef EXT2FS_ENABLE_SWAPFS
79 		if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
80 		    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
81 			((blk_t *) block_buf)[nr] = ext2fs_swab32(b);
82 		else
83 #endif
84 			((blk_t *) block_buf)[nr] = b;
85 
86 		retval = io_channel_write_blk(fs->io, ind, 1, block_buf);
87 		if (retval)
88 			return retval;
89 
90 		(*blocks_alloc)++;
91 	}
92 
93 	*ret_blk = b;
94 	return 0;
95 }
96 
block_dind_bmap(ext2_filsys fs,int flags,blk_t dind,char * block_buf,int * blocks_alloc,blk_t nr,blk_t * ret_blk)97 static _BMAP_INLINE_ errcode_t block_dind_bmap(ext2_filsys fs, int flags,
98 					       blk_t dind, char *block_buf,
99 					       int *blocks_alloc,
100 					       blk_t nr, blk_t *ret_blk)
101 {
102 	blk_t		b;
103 	errcode_t	retval;
104 	blk_t		addr_per_block;
105 
106 	addr_per_block = (blk_t) fs->blocksize >> 2;
107 
108 	retval = block_ind_bmap(fs, flags & ~BMAP_SET, dind, block_buf,
109 				blocks_alloc, nr / addr_per_block, &b);
110 	if (retval)
111 		return retval;
112 	retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
113 				nr % addr_per_block, ret_blk);
114 	return retval;
115 }
116 
block_tind_bmap(ext2_filsys fs,int flags,blk_t tind,char * block_buf,int * blocks_alloc,blk_t nr,blk_t * ret_blk)117 static _BMAP_INLINE_ errcode_t block_tind_bmap(ext2_filsys fs, int flags,
118 					       blk_t tind, char *block_buf,
119 					       int *blocks_alloc,
120 					       blk_t nr, blk_t *ret_blk)
121 {
122 	blk_t		b;
123 	errcode_t	retval;
124 	blk_t		addr_per_block;
125 
126 	addr_per_block = (blk_t) fs->blocksize >> 2;
127 
128 	retval = block_dind_bmap(fs, flags & ~BMAP_SET, tind, block_buf,
129 				 blocks_alloc, nr / addr_per_block, &b);
130 	if (retval)
131 		return retval;
132 	retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
133 				nr % addr_per_block, ret_blk);
134 	return retval;
135 }
136 
ext2fs_bmap(ext2_filsys fs,ext2_ino_t ino,struct ext2_inode * inode,char * block_buf,int bmap_flags,blk_t block,blk_t * phys_blk)137 errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
138 		      char *block_buf, int bmap_flags, blk_t block,
139 		      blk_t *phys_blk)
140 {
141 	struct ext2_inode inode_buf;
142 	blk_t addr_per_block;
143 	blk_t	b;
144 	char	*buf = 0;
145 	errcode_t	retval = 0;
146 	int		blocks_alloc = 0, inode_dirty = 0;
147 
148 	if (!(bmap_flags & BMAP_SET))
149 		*phys_blk = 0;
150 
151 	/* Read inode structure if necessary */
152 	if (!inode) {
153 		retval = ext2fs_read_inode(fs, ino, &inode_buf);
154 		if (retval)
155 			return retval;
156 		inode = &inode_buf;
157 	}
158 	addr_per_block = (blk_t) fs->blocksize >> 2;
159 
160 	if (!block_buf) {
161 		retval = ext2fs_get_array(2, fs->blocksize, &buf);
162 		if (retval)
163 			return retval;
164 		block_buf = buf;
165 	}
166 
167 	if (block < EXT2_NDIR_BLOCKS) {
168 		if (bmap_flags & BMAP_SET) {
169 			b = *phys_blk;
170 #ifdef EXT2FS_ENABLE_SWAPFS
171 			if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
172 			    (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
173 				b = ext2fs_swab32(b);
174 #endif
175 			inode_bmap(inode, block) = b;
176 			inode_dirty++;
177 			goto done;
178 		}
179 
180 		*phys_blk = inode_bmap(inode, block);
181 		b = block ? inode_bmap(inode, block-1) : 0;
182 
183 		if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
184 			retval = ext2fs_alloc_block(fs, b, block_buf, &b);
185 			if (retval)
186 				goto done;
187 			inode_bmap(inode, block) = b;
188 			blocks_alloc++;
189 			*phys_blk = b;
190 		}
191 		goto done;
192 	}
193 
194 	/* Indirect block */
195 	block -= EXT2_NDIR_BLOCKS;
196 	if (block < addr_per_block) {
197 		b = inode_bmap(inode, EXT2_IND_BLOCK);
198 		if (!b) {
199 			if (!(bmap_flags & BMAP_ALLOC)) {
200 				if (bmap_flags & BMAP_SET)
201 					retval = EXT2_ET_SET_BMAP_NO_IND;
202 				goto done;
203 			}
204 
205 			b = inode_bmap(inode, EXT2_IND_BLOCK-1);
206  			retval = ext2fs_alloc_block(fs, b, block_buf, &b);
207 			if (retval)
208 				goto done;
209 			inode_bmap(inode, EXT2_IND_BLOCK) = b;
210 			blocks_alloc++;
211 		}
212 		retval = block_ind_bmap(fs, bmap_flags, b, block_buf,
213 					&blocks_alloc, block, phys_blk);
214 		goto done;
215 	}
216 
217 	/* Doubly indirect block  */
218 	block -= addr_per_block;
219 	if (block < addr_per_block * addr_per_block) {
220 		b = inode_bmap(inode, EXT2_DIND_BLOCK);
221 		if (!b) {
222 			if (!(bmap_flags & BMAP_ALLOC)) {
223 				if (bmap_flags & BMAP_SET)
224 					retval = EXT2_ET_SET_BMAP_NO_IND;
225 				goto done;
226 			}
227 
228 			b = inode_bmap(inode, EXT2_IND_BLOCK);
229  			retval = ext2fs_alloc_block(fs, b, block_buf, &b);
230 			if (retval)
231 				goto done;
232 			inode_bmap(inode, EXT2_DIND_BLOCK) = b;
233 			blocks_alloc++;
234 		}
235 		retval = block_dind_bmap(fs, bmap_flags, b, block_buf,
236 					 &blocks_alloc, block, phys_blk);
237 		goto done;
238 	}
239 
240 	/* Triply indirect block */
241 	block -= addr_per_block * addr_per_block;
242 	b = inode_bmap(inode, EXT2_TIND_BLOCK);
243 	if (!b) {
244 		if (!(bmap_flags & BMAP_ALLOC)) {
245 			if (bmap_flags & BMAP_SET)
246 				retval = EXT2_ET_SET_BMAP_NO_IND;
247 			goto done;
248 		}
249 
250 		b = inode_bmap(inode, EXT2_DIND_BLOCK);
251 		retval = ext2fs_alloc_block(fs, b, block_buf, &b);
252 		if (retval)
253 			goto done;
254 		inode_bmap(inode, EXT2_TIND_BLOCK) = b;
255 		blocks_alloc++;
256 	}
257 	retval = block_tind_bmap(fs, bmap_flags, b, block_buf,
258 				 &blocks_alloc, block, phys_blk);
259 done:
260 	if (buf)
261 		ext2fs_free_mem(&buf);
262 	if ((retval == 0) && (blocks_alloc || inode_dirty)) {
263 		inode->i_blocks += (blocks_alloc * fs->blocksize) / 512;
264 		retval = ext2fs_write_inode(fs, ino, inode);
265 	}
266 	return retval;
267 }
268 
269 
270 
271