aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ext2fs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ext2fs')
-rw-r--r--lib/ext2fs/block.c22
-rw-r--r--lib/ext2fs/dir_iterate.c2
-rw-r--r--lib/ext2fs/ext2_err.et.in3
-rw-r--r--lib/ext2fs/ext2fs.h4
-rw-r--r--lib/ext2fs/read_bb.c4
5 files changed, 31 insertions, 4 deletions
diff --git a/lib/ext2fs/block.c b/lib/ext2fs/block.c
index 07a64157..381d31c7 100644
--- a/lib/ext2fs/block.c
+++ b/lib/ext2fs/block.c
@@ -36,6 +36,16 @@ struct block_context {
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 @@ static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
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 @@ static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
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 @@ static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
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 @@ static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
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 @@ static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
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 @@ static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
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 @@ static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
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 @@ static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
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 @@ static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
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 @@ errcode_t ext2fs_block_iterate2(ext2_filsys fs,
&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 @@ errcode_t ext2fs_block_iterate2(ext2_filsys fs,
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 003c0a3b..3e7b7b06 100644
--- a/lib/ext2fs/dir_iterate.c
+++ b/lib/ext2fs/dir_iterate.c
@@ -78,7 +78,7 @@ errcode_t ext2fs_dir_iterate2(ext2_filsys fs,
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 eda4bb4e..2f442192 100644
--- a/lib/ext2fs/ext2_err.et.in
+++ b/lib/ext2fs/ext2_err.et.in
@@ -326,5 +326,8 @@ ec EXT2_ET_TDB_ERR_NOEXIST,
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 19213b8e..731033fa 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -259,6 +259,9 @@ struct struct_ext2_filsys {
* 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 @@ struct struct_ext2_filsys {
#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 c717adcd..ff7e2924 100644
--- a/lib/ext2fs/read_bb.c
+++ b/lib/ext2fs/read_bb.c
@@ -86,8 +86,8 @@ errcode_t ext2fs_read_bb_inode(ext2_filsys fs, ext2_badblocks_list *bb_list)
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;