libext2: Add BLOCK_FLAG_READ_ONLY flag to ext2fs_block_iterate2()
This flag allows the caller to promise that it will not try to modify
the block numbers returned by the iterator.
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
diff --git a/lib/ext2fs/block.c b/lib/ext2fs/block.c
index 07a6415..381d31c 100644
--- a/lib/ext2fs/block.c
+++ b/lib/ext2fs/block.c
@@ -36,6 +36,16 @@
void *priv_data;
};
+#define check_for_ro_violation(ctx, ret) \
+ do { \
+ if (((ctx)->flags & BLOCK_FLAG_READ_ONLY) && \
+ ((ret) & BLOCK_CHANGED)) { \
+ (ctx)->errcode = EXT2_ET_RO_BLOCK_ITERATE; \
+ return BLOCK_ABORT; \
+ } \
+ } while (0)
+
+
static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
int ref_offset, struct block_context *ctx)
{
@@ -49,6 +59,7 @@
ret = (*ctx->func)(ctx->fs, ind_block,
BLOCK_COUNT_IND, ref_block,
ref_offset, ctx->priv_data);
+ check_for_ro_violation(ctx, ret);
if (!*ind_block || (ret & BLOCK_ABORT)) {
ctx->bcount += limit;
return ret;
@@ -95,6 +106,7 @@
offset += sizeof(blk_t);
}
}
+ check_for_ro_violation(ctx, changed);
if (changed & BLOCK_CHANGED) {
ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block,
ctx->ind_buf);
@@ -107,6 +119,7 @@
ret |= (*ctx->func)(ctx->fs, ind_block,
BLOCK_COUNT_IND, ref_block,
ref_offset, ctx->priv_data);
+ check_for_ro_violation(ctx, ret);
return ret;
}
@@ -123,6 +136,7 @@
ret = (*ctx->func)(ctx->fs, dind_block,
BLOCK_COUNT_DIND, ref_block,
ref_offset, ctx->priv_data);
+ check_for_ro_violation(ctx, ret);
if (!*dind_block || (ret & BLOCK_ABORT)) {
ctx->bcount += limit*limit;
return ret;
@@ -171,6 +185,7 @@
offset += sizeof(blk_t);
}
}
+ check_for_ro_violation(ctx, changed);
if (changed & BLOCK_CHANGED) {
ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block,
ctx->dind_buf);
@@ -183,6 +198,7 @@
ret |= (*ctx->func)(ctx->fs, dind_block,
BLOCK_COUNT_DIND, ref_block,
ref_offset, ctx->priv_data);
+ check_for_ro_violation(ctx, ret);
return ret;
}
@@ -199,6 +215,7 @@
ret = (*ctx->func)(ctx->fs, tind_block,
BLOCK_COUNT_TIND, ref_block,
ref_offset, ctx->priv_data);
+ check_for_ro_violation(ctx, ret);
if (!*tind_block || (ret & BLOCK_ABORT)) {
ctx->bcount += limit*limit*limit;
return ret;
@@ -247,6 +264,7 @@
offset += sizeof(blk_t);
}
}
+ check_for_ro_violation(ctx, changed);
if (changed & BLOCK_CHANGED) {
ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block,
ctx->tind_buf);
@@ -259,7 +277,7 @@
ret |= (*ctx->func)(ctx->fs, tind_block,
BLOCK_COUNT_TIND, ref_block,
ref_offset, ctx->priv_data);
-
+ check_for_ro_violation(ctx, ret);
return ret;
}
@@ -334,6 +352,7 @@
&inode.osd1.hurd1.h_i_translator,
BLOCK_COUNT_TRANSLATOR,
0, 0, priv_data);
+ check_for_ro_violation(&ctx, ret);
if (ret & BLOCK_ABORT)
goto abort_exit;
}
@@ -350,6 +369,7 @@
goto abort_exit;
}
}
+ check_for_ro_violation(&ctx, ret);
if (*(blocks + EXT2_IND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
ret |= block_iterate_ind(blocks + EXT2_IND_BLOCK,
0, EXT2_IND_BLOCK, &ctx);
diff --git a/lib/ext2fs/dir_iterate.c b/lib/ext2fs/dir_iterate.c
index 003c0a3..3e7b7b0 100644
--- a/lib/ext2fs/dir_iterate.c
+++ b/lib/ext2fs/dir_iterate.c
@@ -78,7 +78,7 @@
ctx.func = func;
ctx.priv_data = priv_data;
ctx.errcode = 0;
- retval = ext2fs_block_iterate2(fs, dir, 0, 0,
+ retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_READ_ONLY, 0,
ext2fs_process_dir_block, &ctx);
if (!block_buf)
ext2fs_free_mem(&ctx.buf);
diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
index eda4bb4..2f44219 100644
--- a/lib/ext2fs/ext2_err.et.in
+++ b/lib/ext2fs/ext2_err.et.in
@@ -326,5 +326,8 @@
ec EXT2_ET_TDB_ERR_RDONLY,
"TDB: Write not permitted"
+ec EXT2_ET_RO_BLOCK_ITERATE,
+ "Attempt to modify a block mapping via a read-only block iterator"
+
end
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 19213b8..731033f 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -259,6 +259,9 @@
* BLOCK_FLAG_DATA_ONLY indicates that the iterator function should be
* called for data blocks only.
*
+ * BLOCK_FLAG_READ_ONLY is a promise by the caller that it will not
+ * modify returned block number.
+ *
* BLOCK_FLAG_NO_LARGE is for internal use only. It informs
* ext2fs_block_iterate2 that large files won't be accepted.
*/
@@ -266,6 +269,7 @@
#define BLOCK_FLAG_HOLE 1
#define BLOCK_FLAG_DEPTH_TRAVERSE 2
#define BLOCK_FLAG_DATA_ONLY 4
+#define BLOCK_FLAG_READ_ONLY 8
#define BLOCK_FLAG_NO_LARGE 0x1000
diff --git a/lib/ext2fs/read_bb.c b/lib/ext2fs/read_bb.c
index c717adc..ff7e292 100644
--- a/lib/ext2fs/read_bb.c
+++ b/lib/ext2fs/read_bb.c
@@ -86,8 +86,8 @@
rb.bb_list = *bb_list;
rb.err = 0;
- retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO, 0, 0,
- mark_bad_block, &rb);
+ retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO, BLOCK_FLAG_READ_ONLY,
+ 0, mark_bad_block, &rb);
if (retval)
return retval;