Whamcloud - gitweb
ChangeLog, message.c:
[tools/e2fsprogs.git] / lib / ext2fs / bmap.c
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
18 #if EXT2_FLAT_INCLUDES
19 #include "ext2_fs.h"
20 #else
21 #include <linux/ext2_fs.h>
22 #endif
23
24 #include "ext2fs.h"
25
26 #if defined(__GNUC__) && !defined(NO_INLINE_FUNCS)
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
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         blk_t           addr_per_block;
95         
96         addr_per_block = (blk_t) 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         blk_t           addr_per_block;
115         
116         addr_per_block = (blk_t) 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         blk_t 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 = (blk_t) fs->blocksize >> 2;
148
149         if (!block_buf) {
150                 retval = ext2fs_get_mem(fs->blocksize * 2, (void **) &buf);
151                 if (retval)
152                         return retval;
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)
229                 ext2fs_free_mem((void **) &buf);
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