]>
Commit | Line | Data |
---|---|---|
30fab293 TT |
1 | /* |
2 | * bmap.c --- logical to phiscal 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 | #include <stdlib.h> | |
18 | ||
19 | #include <linux/ext2_fs.h> | |
20 | ||
21 | #include "ext2fs.h" | |
22 | ||
78d8f90f | 23 | #if defined(__GNUC__) && !defined(NO_INLINE_FUNCS) |
30fab293 TT |
24 | #define _BMAP_INLINE_ __inline__ |
25 | #else | |
26 | #define _BMAP_INLINE_ | |
27 | #endif | |
28 | ||
29 | extern errcode_t ext2fs_bmap(ext2_filsys fs, ino_t ino, | |
30 | struct ext2_inode *inode, | |
31 | char *block_buf, int bmap_flags, | |
32 | blk_t block, blk_t *phys_blk); | |
33 | ||
34 | #define BMAP_ALLOC 1 | |
35 | ||
36 | #define inode_bmap(inode, nr) ((inode)->i_block[(nr)]) | |
37 | ||
38 | static blk_t _BMAP_INLINE_ block_bmap(ext2_filsys fs, char *buf, blk_t nr) | |
39 | { | |
40 | blk_t tmp; | |
41 | ||
42 | tmp = ((blk_t *) buf)[nr]; | |
43 | ||
44 | if ((fs->flags & EXT2_FLAG_SWAP_BYTES) || | |
45 | (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) | |
46 | return ext2fs_swab32(tmp); | |
47 | ||
48 | return tmp; | |
49 | } | |
50 | ||
51 | static errcode_t _BMAP_INLINE_ block_ind_bmap(ext2_filsys fs, int flags, | |
52 | blk_t ind, char *block_buf, | |
53 | int *blocks_alloc, | |
54 | blk_t nr, blk_t *ret_blk) | |
55 | { | |
56 | errcode_t retval; | |
57 | blk_t b; | |
58 | ||
59 | if (!ind) { | |
60 | *ret_blk = 0; | |
61 | return 0; | |
62 | } | |
63 | retval = io_channel_read_blk(fs->io, ind, 1, block_buf); | |
64 | if (retval) | |
65 | return retval; | |
66 | ||
67 | b = ((blk_t *) block_buf)[nr]; | |
68 | ||
69 | if ((fs->flags & EXT2_FLAG_SWAP_BYTES) || | |
70 | (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) | |
71 | b = ext2fs_swab32(b); | |
72 | ||
73 | if (!b && (flags & BMAP_ALLOC)) { | |
74 | b = nr ? ((blk_t *) block_buf)[nr-1] : 0; | |
75 | retval = ext2fs_alloc_block(fs, b, | |
76 | block_buf + fs->blocksize, &b); | |
77 | if (retval) | |
78 | return retval; | |
79 | ||
80 | if ((fs->flags & EXT2_FLAG_SWAP_BYTES) || | |
81 | (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) | |
82 | ((blk_t *) block_buf)[nr] = ext2fs_swab32(b); | |
83 | else | |
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 | ||
97 | static errcode_t _BMAP_INLINE_ 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 | int addr_per_block; | |
105 | ||
106 | addr_per_block = fs->blocksize >> 2; | |
107 | ||
108 | retval = block_ind_bmap(fs, flags, dind, block_buf, blocks_alloc, | |
109 | 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 | ||
117 | static errcode_t _BMAP_INLINE_ 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 | int addr_per_block; | |
125 | ||
126 | addr_per_block = fs->blocksize >> 2; | |
127 | ||
128 | retval = block_dind_bmap(fs, flags, tind, block_buf, blocks_alloc, | |
129 | 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 | ||
137 | errcode_t ext2fs_bmap(ext2_filsys fs, 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 | int addr_per_block; | |
143 | blk_t b; | |
144 | char *buf = 0; | |
145 | errcode_t retval = 0; | |
146 | int blocks_alloc = 0; | |
147 | ||
148 | *phys_blk = 0; | |
149 | ||
150 | /* Read inode structure if necessary */ | |
151 | if (!inode) { | |
152 | retval = ext2fs_read_inode(fs, ino, &inode_buf); | |
153 | if (!retval) | |
154 | return retval; | |
155 | inode = &inode_buf; | |
156 | } | |
157 | addr_per_block = fs->blocksize >> 2; | |
158 | ||
159 | if (!block_buf) { | |
160 | buf = malloc(fs->blocksize * 2); | |
161 | if (!buf) | |
162 | return EXT2_NO_MEMORY; | |
163 | block_buf = buf; | |
164 | } | |
165 | ||
166 | if (block < EXT2_NDIR_BLOCKS) { | |
167 | *phys_blk = inode_bmap(inode, block); | |
168 | b = block ? inode_bmap(inode, block-1) : 0; | |
169 | ||
170 | if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) { | |
171 | retval = ext2fs_alloc_block(fs, b, block_buf, &b); | |
172 | if (retval) | |
173 | goto done; | |
174 | inode_bmap(inode, block) = b; | |
175 | blocks_alloc++; | |
176 | *phys_blk = b; | |
177 | } | |
178 | goto done; | |
179 | } | |
180 | ||
181 | /* Indirect block */ | |
182 | block -= EXT2_NDIR_BLOCKS; | |
183 | if (block < addr_per_block) { | |
184 | b = inode_bmap(inode, EXT2_IND_BLOCK); | |
185 | if (!b) { | |
186 | if (!(bmap_flags & BMAP_ALLOC)) | |
187 | goto done; | |
188 | ||
189 | b = inode_bmap(inode, EXT2_IND_BLOCK-1); | |
190 | retval = ext2fs_alloc_block(fs, b, block_buf, &b); | |
191 | if (retval) | |
192 | goto done; | |
193 | inode_bmap(inode, EXT2_IND_BLOCK) = b; | |
194 | blocks_alloc++; | |
195 | } | |
196 | retval = block_ind_bmap(fs, bmap_flags, b, block_buf, | |
197 | &blocks_alloc, block, phys_blk); | |
198 | goto done; | |
199 | } | |
200 | ||
201 | /* Doubly indirect block */ | |
202 | block -= addr_per_block; | |
203 | if (block < addr_per_block * addr_per_block) { | |
204 | b = inode_bmap(inode, EXT2_DIND_BLOCK); | |
205 | if (!b) { | |
206 | if (!(bmap_flags & BMAP_ALLOC)) | |
207 | goto done; | |
208 | ||
209 | b = inode_bmap(inode, EXT2_IND_BLOCK); | |
210 | retval = ext2fs_alloc_block(fs, b, block_buf, &b); | |
211 | if (retval) | |
212 | goto done; | |
213 | inode_bmap(inode, EXT2_DIND_BLOCK) = b; | |
214 | blocks_alloc++; | |
215 | } | |
216 | retval = block_dind_bmap(fs, bmap_flags, b, block_buf, | |
217 | &blocks_alloc, block, phys_blk); | |
218 | goto done; | |
219 | } | |
220 | ||
221 | /* Triply indirect block */ | |
222 | block -= addr_per_block * addr_per_block; | |
223 | b = inode_bmap(inode, EXT2_TIND_BLOCK); | |
224 | if (!b) { | |
225 | if (!(bmap_flags & BMAP_ALLOC)) | |
226 | goto done; | |
227 | ||
228 | b = inode_bmap(inode, EXT2_DIND_BLOCK); | |
229 | retval = ext2fs_alloc_block(fs, b, block_buf, &b); | |
230 | if (retval) | |
231 | goto done; | |
232 | inode_bmap(inode, EXT2_TIND_BLOCK) = b; | |
233 | blocks_alloc++; | |
234 | } | |
235 | retval = block_tind_bmap(fs, bmap_flags, b, block_buf, | |
236 | &blocks_alloc, block, phys_blk); | |
237 | done: | |
238 | if (buf) | |
239 | free(buf); | |
240 | if ((retval == 0) && blocks_alloc) { | |
241 | inode->i_blocks += (blocks_alloc * fs->blocksize) / 512; | |
242 | retval = ext2fs_write_inode(fs, ino, inode); | |
243 | } | |
244 | return retval; | |
245 | } | |
246 | ||
247 | ||
248 |