]>
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 | 17 | |
b5abe6fa TT |
18 | #if EXT2_FLAT_INCLUDES |
19 | #include "ext2_fs.h" | |
20 | #else | |
30fab293 | 21 | #include <linux/ext2_fs.h> |
b5abe6fa | 22 | #endif |
30fab293 TT |
23 | |
24 | #include "ext2fs.h" | |
25 | ||
78d8f90f | 26 | #if defined(__GNUC__) && !defined(NO_INLINE_FUNCS) |
30fab293 TT |
27 | #define _BMAP_INLINE_ __inline__ |
28 | #else | |
29 | #define _BMAP_INLINE_ | |
30 | #endif | |
31 | ||
32 | extern errcode_t ext2fs_bmap(ext2_filsys fs, 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 | ||
30fab293 TT |
41 | static 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 | ||
87 | static 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 | int addr_per_block; | |
95 | ||
96 | addr_per_block = 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 | ||
107 | static 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 | int addr_per_block; | |
115 | ||
116 | addr_per_block = 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 | ||
127 | errcode_t ext2fs_bmap(ext2_filsys fs, 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 | int 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 = fs->blocksize >> 2; | |
148 | ||
149 | if (!block_buf) { | |
7b4e4534 TT |
150 | retval = ext2fs_get_mem(fs->blocksize * 2, (void **) &buf); |
151 | if (retval) | |
152 | return retval; | |
30fab293 TT |
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); | |
227 | done: | |
228 | if (buf) | |
7b4e4534 | 229 | ext2fs_free_mem((void **) &buf); |
30fab293 TT |
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 |