bmap.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * bmap.c --- logical to physical block mapping
  4. *
  5. * Copyright (C) 1997 Theodore Ts'o.
  6. *
  7. * %Begin-Header%
  8. * This file may be redistributed under the terms of the GNU Public
  9. * License.
  10. * %End-Header%
  11. */
  12. #include <stdio.h>
  13. #include <string.h>
  14. #if HAVE_UNISTD_H
  15. #include <unistd.h>
  16. #endif
  17. #include "ext2_fs.h"
  18. #include "ext2fs.h"
  19. extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
  20. struct ext2_inode *inode,
  21. char *block_buf, int bmap_flags,
  22. blk_t block, blk_t *phys_blk);
  23. #define inode_bmap(inode, nr) ((inode)->i_block[(nr)])
  24. static errcode_t block_ind_bmap(ext2_filsys fs, int flags,
  25. blk_t ind, char *block_buf,
  26. int *blocks_alloc,
  27. blk_t nr, blk_t *ret_blk)
  28. {
  29. errcode_t retval;
  30. blk_t b;
  31. if (!ind) {
  32. if (flags & BMAP_SET)
  33. return EXT2_ET_SET_BMAP_NO_IND;
  34. *ret_blk = 0;
  35. return 0;
  36. }
  37. retval = io_channel_read_blk(fs->io, ind, 1, block_buf);
  38. if (retval)
  39. return retval;
  40. if (flags & BMAP_SET) {
  41. b = *ret_blk;
  42. #if BB_BIG_ENDIAN
  43. if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
  44. (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
  45. b = ext2fs_swab32(b);
  46. #endif
  47. ((blk_t *) block_buf)[nr] = b;
  48. return io_channel_write_blk(fs->io, ind, 1, block_buf);
  49. }
  50. b = ((blk_t *) block_buf)[nr];
  51. #if BB_BIG_ENDIAN
  52. if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
  53. (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
  54. b = ext2fs_swab32(b);
  55. #endif
  56. if (!b && (flags & BMAP_ALLOC)) {
  57. b = nr ? ((blk_t *) block_buf)[nr-1] : 0;
  58. retval = ext2fs_alloc_block(fs, b,
  59. block_buf + fs->blocksize, &b);
  60. if (retval)
  61. return retval;
  62. #if BB_BIG_ENDIAN
  63. if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
  64. (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
  65. ((blk_t *) block_buf)[nr] = ext2fs_swab32(b);
  66. else
  67. #endif
  68. ((blk_t *) block_buf)[nr] = b;
  69. retval = io_channel_write_blk(fs->io, ind, 1, block_buf);
  70. if (retval)
  71. return retval;
  72. (*blocks_alloc)++;
  73. }
  74. *ret_blk = b;
  75. return 0;
  76. }
  77. static errcode_t block_dind_bmap(ext2_filsys fs, int flags,
  78. blk_t dind, char *block_buf,
  79. int *blocks_alloc,
  80. blk_t nr, blk_t *ret_blk)
  81. {
  82. blk_t b;
  83. errcode_t retval;
  84. blk_t addr_per_block;
  85. addr_per_block = (blk_t) fs->blocksize >> 2;
  86. retval = block_ind_bmap(fs, flags & ~BMAP_SET, dind, block_buf,
  87. blocks_alloc, nr / addr_per_block, &b);
  88. if (retval)
  89. return retval;
  90. retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
  91. nr % addr_per_block, ret_blk);
  92. return retval;
  93. }
  94. static errcode_t block_tind_bmap(ext2_filsys fs, int flags,
  95. blk_t tind, char *block_buf,
  96. int *blocks_alloc,
  97. blk_t nr, blk_t *ret_blk)
  98. {
  99. blk_t b;
  100. errcode_t retval;
  101. blk_t addr_per_block;
  102. addr_per_block = (blk_t) fs->blocksize >> 2;
  103. retval = block_dind_bmap(fs, flags & ~BMAP_SET, tind, block_buf,
  104. blocks_alloc, nr / addr_per_block, &b);
  105. if (retval)
  106. return retval;
  107. retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
  108. nr % addr_per_block, ret_blk);
  109. return retval;
  110. }
  111. errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
  112. char *block_buf, int bmap_flags, blk_t block,
  113. blk_t *phys_blk)
  114. {
  115. struct ext2_inode inode_buf;
  116. blk_t addr_per_block;
  117. blk_t b;
  118. char *buf = NULL;
  119. errcode_t retval = 0;
  120. int blocks_alloc = 0, inode_dirty = 0;
  121. if (!(bmap_flags & BMAP_SET))
  122. *phys_blk = 0;
  123. /* Read inode structure if necessary */
  124. if (!inode) {
  125. retval = ext2fs_read_inode(fs, ino, &inode_buf);
  126. if (retval)
  127. return retval;
  128. inode = &inode_buf;
  129. }
  130. addr_per_block = (blk_t) fs->blocksize >> 2;
  131. if (!block_buf) {
  132. retval = ext2fs_get_mem(fs->blocksize * 2, &buf);
  133. if (retval)
  134. return retval;
  135. block_buf = buf;
  136. }
  137. if (block < EXT2_NDIR_BLOCKS) {
  138. if (bmap_flags & BMAP_SET) {
  139. b = *phys_blk;
  140. #if BB_BIG_ENDIAN
  141. if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
  142. (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
  143. b = ext2fs_swab32(b);
  144. #endif
  145. inode_bmap(inode, block) = b;
  146. inode_dirty++;
  147. goto done;
  148. }
  149. *phys_blk = inode_bmap(inode, block);
  150. b = block ? inode_bmap(inode, block-1) : 0;
  151. if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
  152. retval = ext2fs_alloc_block(fs, b, block_buf, &b);
  153. if (retval)
  154. goto done;
  155. inode_bmap(inode, block) = b;
  156. blocks_alloc++;
  157. *phys_blk = b;
  158. }
  159. goto done;
  160. }
  161. /* Indirect block */
  162. block -= EXT2_NDIR_BLOCKS;
  163. if (block < addr_per_block) {
  164. b = inode_bmap(inode, EXT2_IND_BLOCK);
  165. if (!b) {
  166. if (!(bmap_flags & BMAP_ALLOC)) {
  167. if (bmap_flags & BMAP_SET)
  168. retval = EXT2_ET_SET_BMAP_NO_IND;
  169. goto done;
  170. }
  171. b = inode_bmap(inode, EXT2_IND_BLOCK-1);
  172. retval = ext2fs_alloc_block(fs, b, block_buf, &b);
  173. if (retval)
  174. goto done;
  175. inode_bmap(inode, EXT2_IND_BLOCK) = b;
  176. blocks_alloc++;
  177. }
  178. retval = block_ind_bmap(fs, bmap_flags, b, block_buf,
  179. &blocks_alloc, block, phys_blk);
  180. goto done;
  181. }
  182. /* Doubly indirect block */
  183. block -= addr_per_block;
  184. if (block < addr_per_block * addr_per_block) {
  185. b = inode_bmap(inode, EXT2_DIND_BLOCK);
  186. if (!b) {
  187. if (!(bmap_flags & BMAP_ALLOC)) {
  188. if (bmap_flags & BMAP_SET)
  189. retval = EXT2_ET_SET_BMAP_NO_IND;
  190. goto done;
  191. }
  192. b = inode_bmap(inode, EXT2_IND_BLOCK);
  193. retval = ext2fs_alloc_block(fs, b, block_buf, &b);
  194. if (retval)
  195. goto done;
  196. inode_bmap(inode, EXT2_DIND_BLOCK) = b;
  197. blocks_alloc++;
  198. }
  199. retval = block_dind_bmap(fs, bmap_flags, b, block_buf,
  200. &blocks_alloc, block, phys_blk);
  201. goto done;
  202. }
  203. /* Triply indirect block */
  204. block -= addr_per_block * addr_per_block;
  205. b = inode_bmap(inode, EXT2_TIND_BLOCK);
  206. if (!b) {
  207. if (!(bmap_flags & BMAP_ALLOC)) {
  208. if (bmap_flags & BMAP_SET)
  209. retval = EXT2_ET_SET_BMAP_NO_IND;
  210. goto done;
  211. }
  212. b = inode_bmap(inode, EXT2_DIND_BLOCK);
  213. retval = ext2fs_alloc_block(fs, b, block_buf, &b);
  214. if (retval)
  215. goto done;
  216. inode_bmap(inode, EXT2_TIND_BLOCK) = b;
  217. blocks_alloc++;
  218. }
  219. retval = block_tind_bmap(fs, bmap_flags, b, block_buf,
  220. &blocks_alloc, block, phys_blk);
  221. done:
  222. ext2fs_free_mem(&buf);
  223. if ((retval == 0) && (blocks_alloc || inode_dirty)) {
  224. inode->i_blocks += (blocks_alloc * fs->blocksize) / 512;
  225. retval = ext2fs_write_inode(fs, ino, inode);
  226. }
  227. return retval;
  228. }