block.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * block.c --- iterate over all blocks in an inode
  4. *
  5. * Copyright (C) 1993, 1994, 1995, 1996 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. struct block_context {
  20. ext2_filsys fs;
  21. int (*func)(ext2_filsys fs,
  22. blk_t *blocknr,
  23. e2_blkcnt_t bcount,
  24. blk_t ref_blk,
  25. int ref_offset,
  26. void *priv_data);
  27. e2_blkcnt_t bcount;
  28. int bsize;
  29. int flags;
  30. errcode_t errcode;
  31. char *ind_buf;
  32. char *dind_buf;
  33. char *tind_buf;
  34. void *priv_data;
  35. };
  36. static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
  37. int ref_offset, struct block_context *ctx)
  38. {
  39. int ret = 0, changed = 0;
  40. int i, flags, limit, offset;
  41. blk_t *block_nr;
  42. limit = ctx->fs->blocksize >> 2;
  43. if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
  44. !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
  45. ret = (*ctx->func)(ctx->fs, ind_block,
  46. BLOCK_COUNT_IND, ref_block,
  47. ref_offset, ctx->priv_data);
  48. if (!*ind_block || (ret & BLOCK_ABORT)) {
  49. ctx->bcount += limit;
  50. return ret;
  51. }
  52. if (*ind_block >= ctx->fs->super->s_blocks_count ||
  53. *ind_block < ctx->fs->super->s_first_data_block) {
  54. ctx->errcode = EXT2_ET_BAD_IND_BLOCK;
  55. ret |= BLOCK_ERROR;
  56. return ret;
  57. }
  58. ctx->errcode = ext2fs_read_ind_block(ctx->fs, *ind_block,
  59. ctx->ind_buf);
  60. if (ctx->errcode) {
  61. ret |= BLOCK_ERROR;
  62. return ret;
  63. }
  64. block_nr = (blk_t *) ctx->ind_buf;
  65. offset = 0;
  66. if (ctx->flags & BLOCK_FLAG_APPEND) {
  67. for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
  68. flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
  69. *ind_block, offset,
  70. ctx->priv_data);
  71. changed |= flags;
  72. if (flags & BLOCK_ABORT) {
  73. ret |= BLOCK_ABORT;
  74. break;
  75. }
  76. offset += sizeof(blk_t);
  77. }
  78. } else {
  79. for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
  80. if (*block_nr == 0)
  81. continue;
  82. flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
  83. *ind_block, offset,
  84. ctx->priv_data);
  85. changed |= flags;
  86. if (flags & BLOCK_ABORT) {
  87. ret |= BLOCK_ABORT;
  88. break;
  89. }
  90. offset += sizeof(blk_t);
  91. }
  92. }
  93. if (changed & BLOCK_CHANGED) {
  94. ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block,
  95. ctx->ind_buf);
  96. if (ctx->errcode)
  97. ret |= BLOCK_ERROR | BLOCK_ABORT;
  98. }
  99. if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
  100. !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
  101. !(ret & BLOCK_ABORT))
  102. ret |= (*ctx->func)(ctx->fs, ind_block,
  103. BLOCK_COUNT_IND, ref_block,
  104. ref_offset, ctx->priv_data);
  105. return ret;
  106. }
  107. static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
  108. int ref_offset, struct block_context *ctx)
  109. {
  110. int ret = 0, changed = 0;
  111. int i, flags, limit, offset;
  112. blk_t *block_nr;
  113. limit = ctx->fs->blocksize >> 2;
  114. if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
  115. BLOCK_FLAG_DATA_ONLY)))
  116. ret = (*ctx->func)(ctx->fs, dind_block,
  117. BLOCK_COUNT_DIND, ref_block,
  118. ref_offset, ctx->priv_data);
  119. if (!*dind_block || (ret & BLOCK_ABORT)) {
  120. ctx->bcount += limit*limit;
  121. return ret;
  122. }
  123. if (*dind_block >= ctx->fs->super->s_blocks_count ||
  124. *dind_block < ctx->fs->super->s_first_data_block) {
  125. ctx->errcode = EXT2_ET_BAD_DIND_BLOCK;
  126. ret |= BLOCK_ERROR;
  127. return ret;
  128. }
  129. ctx->errcode = ext2fs_read_ind_block(ctx->fs, *dind_block,
  130. ctx->dind_buf);
  131. if (ctx->errcode) {
  132. ret |= BLOCK_ERROR;
  133. return ret;
  134. }
  135. block_nr = (blk_t *) ctx->dind_buf;
  136. offset = 0;
  137. if (ctx->flags & BLOCK_FLAG_APPEND) {
  138. for (i = 0; i < limit; i++, block_nr++) {
  139. flags = block_iterate_ind(block_nr,
  140. *dind_block, offset,
  141. ctx);
  142. changed |= flags;
  143. if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
  144. ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
  145. break;
  146. }
  147. offset += sizeof(blk_t);
  148. }
  149. } else {
  150. for (i = 0; i < limit; i++, block_nr++) {
  151. if (*block_nr == 0) {
  152. ctx->bcount += limit;
  153. continue;
  154. }
  155. flags = block_iterate_ind(block_nr,
  156. *dind_block, offset,
  157. ctx);
  158. changed |= flags;
  159. if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
  160. ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
  161. break;
  162. }
  163. offset += sizeof(blk_t);
  164. }
  165. }
  166. if (changed & BLOCK_CHANGED) {
  167. ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block,
  168. ctx->dind_buf);
  169. if (ctx->errcode)
  170. ret |= BLOCK_ERROR | BLOCK_ABORT;
  171. }
  172. if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
  173. !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
  174. !(ret & BLOCK_ABORT))
  175. ret |= (*ctx->func)(ctx->fs, dind_block,
  176. BLOCK_COUNT_DIND, ref_block,
  177. ref_offset, ctx->priv_data);
  178. return ret;
  179. }
  180. static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
  181. int ref_offset, struct block_context *ctx)
  182. {
  183. int ret = 0, changed = 0;
  184. int i, flags, limit, offset;
  185. blk_t *block_nr;
  186. limit = ctx->fs->blocksize >> 2;
  187. if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
  188. BLOCK_FLAG_DATA_ONLY)))
  189. ret = (*ctx->func)(ctx->fs, tind_block,
  190. BLOCK_COUNT_TIND, ref_block,
  191. ref_offset, ctx->priv_data);
  192. if (!*tind_block || (ret & BLOCK_ABORT)) {
  193. ctx->bcount += limit*limit*limit;
  194. return ret;
  195. }
  196. if (*tind_block >= ctx->fs->super->s_blocks_count ||
  197. *tind_block < ctx->fs->super->s_first_data_block) {
  198. ctx->errcode = EXT2_ET_BAD_TIND_BLOCK;
  199. ret |= BLOCK_ERROR;
  200. return ret;
  201. }
  202. ctx->errcode = ext2fs_read_ind_block(ctx->fs, *tind_block,
  203. ctx->tind_buf);
  204. if (ctx->errcode) {
  205. ret |= BLOCK_ERROR;
  206. return ret;
  207. }
  208. block_nr = (blk_t *) ctx->tind_buf;
  209. offset = 0;
  210. if (ctx->flags & BLOCK_FLAG_APPEND) {
  211. for (i = 0; i < limit; i++, block_nr++) {
  212. flags = block_iterate_dind(block_nr,
  213. *tind_block,
  214. offset, ctx);
  215. changed |= flags;
  216. if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
  217. ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
  218. break;
  219. }
  220. offset += sizeof(blk_t);
  221. }
  222. } else {
  223. for (i = 0; i < limit; i++, block_nr++) {
  224. if (*block_nr == 0) {
  225. ctx->bcount += limit*limit;
  226. continue;
  227. }
  228. flags = block_iterate_dind(block_nr,
  229. *tind_block,
  230. offset, ctx);
  231. changed |= flags;
  232. if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
  233. ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
  234. break;
  235. }
  236. offset += sizeof(blk_t);
  237. }
  238. }
  239. if (changed & BLOCK_CHANGED) {
  240. ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block,
  241. ctx->tind_buf);
  242. if (ctx->errcode)
  243. ret |= BLOCK_ERROR | BLOCK_ABORT;
  244. }
  245. if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
  246. !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
  247. !(ret & BLOCK_ABORT))
  248. ret |= (*ctx->func)(ctx->fs, tind_block,
  249. BLOCK_COUNT_TIND, ref_block,
  250. ref_offset, ctx->priv_data);
  251. return ret;
  252. }
  253. errcode_t ext2fs_block_iterate2(ext2_filsys fs,
  254. ext2_ino_t ino,
  255. int flags,
  256. char *block_buf,
  257. int (*func)(ext2_filsys fs,
  258. blk_t *blocknr,
  259. e2_blkcnt_t blockcnt,
  260. blk_t ref_blk,
  261. int ref_offset,
  262. void *priv_data),
  263. void *priv_data)
  264. {
  265. int i;
  266. int got_inode = 0;
  267. int ret = 0;
  268. blk_t blocks[EXT2_N_BLOCKS]; /* directory data blocks */
  269. struct ext2_inode inode;
  270. errcode_t retval;
  271. struct block_context ctx;
  272. int limit;
  273. EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
  274. /*
  275. * Check to see if we need to limit large files
  276. */
  277. if (flags & BLOCK_FLAG_NO_LARGE) {
  278. ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
  279. if (ctx.errcode)
  280. return ctx.errcode;
  281. got_inode = 1;
  282. if (!LINUX_S_ISDIR(inode.i_mode) &&
  283. (inode.i_size_high != 0))
  284. return EXT2_ET_FILE_TOO_BIG;
  285. }
  286. retval = ext2fs_get_blocks(fs, ino, blocks);
  287. if (retval)
  288. return retval;
  289. limit = fs->blocksize >> 2;
  290. ctx.fs = fs;
  291. ctx.func = func;
  292. ctx.priv_data = priv_data;
  293. ctx.flags = flags;
  294. ctx.bcount = 0;
  295. if (block_buf) {
  296. ctx.ind_buf = block_buf;
  297. } else {
  298. retval = ext2fs_get_mem(fs->blocksize * 3, &ctx.ind_buf);
  299. if (retval)
  300. return retval;
  301. }
  302. ctx.dind_buf = ctx.ind_buf + fs->blocksize;
  303. ctx.tind_buf = ctx.dind_buf + fs->blocksize;
  304. /*
  305. * Iterate over the HURD translator block (if present)
  306. */
  307. if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
  308. !(flags & BLOCK_FLAG_DATA_ONLY)) {
  309. ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
  310. if (ctx.errcode)
  311. goto abort_exit;
  312. got_inode = 1;
  313. if (inode.osd1.hurd1.h_i_translator) {
  314. ret |= (*ctx.func)(fs,
  315. &inode.osd1.hurd1.h_i_translator,
  316. BLOCK_COUNT_TRANSLATOR,
  317. 0, 0, priv_data);
  318. if (ret & BLOCK_ABORT)
  319. goto abort_exit;
  320. }
  321. }
  322. /*
  323. * Iterate over normal data blocks
  324. */
  325. for (i = 0; i < EXT2_NDIR_BLOCKS; i++, ctx.bcount++) {
  326. if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) {
  327. ret |= (*ctx.func)(fs, &blocks[i],
  328. ctx.bcount, 0, i, priv_data);
  329. if (ret & BLOCK_ABORT)
  330. goto abort_exit;
  331. }
  332. }
  333. if (*(blocks + EXT2_IND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
  334. ret |= block_iterate_ind(blocks + EXT2_IND_BLOCK,
  335. 0, EXT2_IND_BLOCK, &ctx);
  336. if (ret & BLOCK_ABORT)
  337. goto abort_exit;
  338. } else
  339. ctx.bcount += limit;
  340. if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
  341. ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK,
  342. 0, EXT2_DIND_BLOCK, &ctx);
  343. if (ret & BLOCK_ABORT)
  344. goto abort_exit;
  345. } else
  346. ctx.bcount += limit * limit;
  347. if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
  348. ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK,
  349. 0, EXT2_TIND_BLOCK, &ctx);
  350. if (ret & BLOCK_ABORT)
  351. goto abort_exit;
  352. }
  353. abort_exit:
  354. if (ret & BLOCK_CHANGED) {
  355. if (!got_inode) {
  356. retval = ext2fs_read_inode(fs, ino, &inode);
  357. if (retval)
  358. return retval;
  359. }
  360. for (i=0; i < EXT2_N_BLOCKS; i++)
  361. inode.i_block[i] = blocks[i];
  362. retval = ext2fs_write_inode(fs, ino, &inode);
  363. if (retval)
  364. return retval;
  365. }
  366. if (!block_buf)
  367. ext2fs_free_mem(&ctx.ind_buf);
  368. return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
  369. }
  370. /*
  371. * Emulate the old ext2fs_block_iterate function!
  372. */
  373. struct xlate {
  374. int (*func)(ext2_filsys fs,
  375. blk_t *blocknr,
  376. int bcount,
  377. void *priv_data);
  378. void *real_private;
  379. };
  380. #ifdef __TURBOC__
  381. # pragma argsused
  382. #endif
  383. static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt,
  384. blk_t ref_block EXT2FS_ATTR((unused)),
  385. int ref_offset EXT2FS_ATTR((unused)),
  386. void *priv_data)
  387. {
  388. struct xlate *xl = (struct xlate *) priv_data;
  389. return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private);
  390. }
  391. errcode_t ext2fs_block_iterate(ext2_filsys fs,
  392. ext2_ino_t ino,
  393. int flags,
  394. char *block_buf,
  395. int (*func)(ext2_filsys fs,
  396. blk_t *blocknr,
  397. int blockcnt,
  398. void *priv_data),
  399. void *priv_data)
  400. {
  401. struct xlate xl;
  402. xl.real_private = priv_data;
  403. xl.func = func;
  404. return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags,
  405. block_buf, xlate_func, &xl);
  406. }