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