libext2fs: 32-bit bitmap refactorization, part 3

Create new functions ext2fs_{set,get}_{inode,block}_bitmap_range()
which allow programs like e2fsck, dumpe2fs, etc. to get and set chunks
of the bitmap at a time.

Move the representation details of the 32-bit old-style bitmaps into
gen_bitmap.c.

Change calls in dumpe2fs, mke2s, et. al to use the new abstractions.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
This commit is contained in:
Theodore Ts'o 2007-07-23 04:32:48 -04:00
parent 50448d3dff
commit f1f115a78f
7 changed files with 282 additions and 109 deletions

View File

@ -563,7 +563,7 @@ static void check_block_end(e2fsck_t ctx)
clear_problem_context(&pctx);
end = fs->block_map->start +
end = ext2fs_get_block_bitmap_start(fs->block_map) +
(EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end,
&save_blocks_count);

View File

@ -52,7 +52,6 @@ errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs,
const char *descr,
ext2fs_inode_bitmap *ret)
{
errcode_t retval;
__u32 start, end, real_end;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
@ -72,7 +71,6 @@ errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs,
const char *descr,
ext2fs_block_bitmap *ret)
{
errcode_t retval;
__u32 start, end, real_end;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
@ -148,3 +146,38 @@ errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
bm1, bm2));
}
errcode_t ext2fs_set_inode_bitmap_range(ext2fs_inode_bitmap bmap,
ext2_ino_t start, unsigned int num,
void *in)
{
return (ext2fs_set_generic_bitmap_range(bmap,
EXT2_ET_MAGIC_INODE_BITMAP,
start, num, in));
}
errcode_t ext2fs_get_inode_bitmap_range(ext2fs_inode_bitmap bmap,
ext2_ino_t start, unsigned int num,
void *out)
{
return (ext2fs_get_generic_bitmap_range(bmap,
EXT2_ET_MAGIC_INODE_BITMAP,
start, num, out));
}
errcode_t ext2fs_set_block_bitmap_range(ext2fs_block_bitmap bmap,
blk_t start, unsigned int num,
void *in)
{
return (ext2fs_set_generic_bitmap_range(bmap,
EXT2_ET_MAGIC_BLOCK_BITMAP,
start, num, in));
}
errcode_t ext2fs_get_block_bitmap_range(ext2fs_block_bitmap bmap,
blk_t start, unsigned int num,
void *out)
{
return (ext2fs_get_generic_bitmap_range(bmap,
EXT2_ET_MAGIC_BLOCK_BITMAP,
start, num, out));
}

View File

@ -100,17 +100,6 @@ typedef __u32 ext2_dirhash_t;
typedef struct struct_ext2_filsys *ext2_filsys;
struct ext2fs_struct_generic_bitmap {
errcode_t magic;
ext2_filsys fs;
__u32 start, end;
__u32 real_end;
char * description;
char * bitmap;
errcode_t base_error_code;
__u32 reserved[7];
};
#define EXT2FS_MARK_ERROR 0
#define EXT2FS_UNMARK_ERROR 1
#define EXT2FS_TEST_ERROR 2
@ -553,6 +542,8 @@ extern errcode_t ext2fs_update_bb_inode(ext2_filsys fs,
/* bitmaps.c */
extern void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap);
extern void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap);
extern errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
ext2fs_generic_bitmap *dest);
extern errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs);
extern errcode_t ext2fs_write_block_bitmap (ext2_filsys fs);
extern errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs);
@ -579,6 +570,18 @@ extern errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1,
ext2fs_block_bitmap bm2);
extern errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
ext2fs_inode_bitmap bm2);
extern errcode_t ext2fs_set_inode_bitmap_range(ext2fs_inode_bitmap bmap,
ext2_ino_t start, unsigned int num,
void *in);
extern errcode_t ext2fs_get_inode_bitmap_range(ext2fs_inode_bitmap bmap,
ext2_ino_t start, unsigned int num,
void *out);
extern errcode_t ext2fs_set_block_bitmap_range(ext2fs_block_bitmap bmap,
blk_t start, unsigned int num,
void *in);
extern errcode_t ext2fs_get_block_bitmap_range(ext2fs_block_bitmap bmap,
blk_t start, unsigned int num,
void *out);
/* block.c */
@ -782,6 +785,14 @@ extern errcode_t ext2fs_resize_generic_bitmap(errcode_t magic,
extern errcode_t ext2fs_compare_generic_bitmap(errcode_t magic, errcode_t neq,
ext2fs_generic_bitmap bm1,
ext2fs_generic_bitmap bm2);
extern errcode_t ext2fs_get_generic_bitmap_range(ext2fs_generic_bitmap bmap,
errcode_t magic,
__u32 start, __u32 num,
void *out);
extern errcode_t ext2fs_set_generic_bitmap_range(ext2fs_generic_bitmap bmap,
errcode_t magic,
__u32 start, __u32 num,
void *in);
/* getsize.c */
extern errcode_t ext2fs_get_device_size(const char *file, int blocksize,

View File

@ -27,6 +27,17 @@
#include "ext2_fs.h"
#include "ext2fs.h"
struct ext2fs_struct_generic_bitmap {
errcode_t magic;
ext2_filsys fs;
__u32 start, end;
__u32 real_end;
char * description;
char * bitmap;
errcode_t base_error_code;
__u32 reserved[7];
};
/*
* Used by previously inlined function, so we have to export this and
* not change the function signature
@ -284,14 +295,44 @@ void ext2fs_set_generic_bitmap_padding(ext2fs_generic_bitmap map)
i <= map->real_end && i > map->end;
i++, j++)
ext2fs_set_bit(j, map->bitmap);
}
}
errcode_t ext2fs_get_generic_bitmap_range(ext2fs_generic_bitmap bmap,
errcode_t magic,
__u32 start, __u32 num,
void *out)
{
if (!bmap || (bmap->magic != magic))
return magic;
if ((start < bmap->start) || (start+num-1 > bmap->real_end))
return EXT2_ET_INVALID_ARGUMENT;
memcpy(out, bmap->bitmap + (start >> 3), (num+7) >> 3);
return 0;
}
errcode_t ext2fs_set_generic_bitmap_range(ext2fs_generic_bitmap bmap,
errcode_t magic,
__u32 start, __u32 num,
void *in)
{
if (!bmap || (bmap->magic != magic))
return magic;
if ((start < bmap->start) || (start+num-1 > bmap->real_end))
return EXT2_ET_INVALID_ARGUMENT;
memcpy(bmap->bitmap + (start >> 3), in, (num+7) >> 3);
return 0;
}
int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
blk_t block, int num)
{
int i;
if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
if ((block < bitmap->start) || (block+num-1 > bitmap->real_end)) {
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
block, bitmap->description);
return 0;

View File

@ -277,11 +277,12 @@ errout:
*/
errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
{
char *ptr;
int c, size;
char zero_buf[1024];
ssize_t actual;
errcode_t retval;
ext2fs_generic_bitmap bmap;
errcode_t err, retval;
ssize_t actual;
__u32 itr, cnt, size;
int c, total_size;
char buf[1024];
if (flags & IMAGER_FLAG_INODEMAP) {
if (!fs->inode_map) {
@ -289,7 +290,10 @@ errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
if (retval)
return retval;
}
ptr = fs->inode_map->bitmap;
bmap = fs->inode_map;
err = EXT2_ET_MAGIC_INODE_BITMAP;
itr = 1;
cnt = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
} else {
if (!fs->block_map) {
@ -297,43 +301,51 @@ errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
if (retval)
return retval;
}
ptr = fs->block_map->bitmap;
bmap = fs->block_map;
err = EXT2_ET_MAGIC_BLOCK_BITMAP;
itr = fs->super->s_first_data_block;
cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count;
size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
}
size = size * fs->group_desc_count;
total_size = size * fs->group_desc_count;
actual = write(fd, ptr, size);
if (actual == -1) {
retval = errno;
goto errout;
while (cnt > 0) {
size = sizeof(buf);
if (size > (cnt >> 3))
size = (cnt >> 3);
retval = ext2fs_get_generic_bitmap_range(bmap,
err, itr, size << 3, buf);
if (retval)
return retval;
actual = write(fd, buf, size);
if (actual == -1)
return errno;
if (actual != (int) size)
return EXT2_ET_SHORT_READ;
itr += size << 3;
cnt -= size << 3;
}
if (actual != size) {
retval = EXT2_ET_SHORT_WRITE;
goto errout;
}
size = size % fs->blocksize;
memset(zero_buf, 0, sizeof(zero_buf));
size = total_size % fs->blocksize;
memset(buf, 0, sizeof(buf));
if (size) {
size = fs->blocksize - size;
while (size) {
c = size;
if (c > (int) sizeof(zero_buf))
c = sizeof(zero_buf);
actual = write(fd, zero_buf, c);
if (actual == -1) {
retval = errno;
goto errout;
}
if (actual != c) {
retval = EXT2_ET_SHORT_WRITE;
goto errout;
}
if (c > (int) sizeof(buf))
c = sizeof(buf);
actual = write(fd, buf, c);
if (actual == -1)
return errno;
if (actual != c)
return EXT2_ET_SHORT_WRITE;
size -= c;
}
}
retval = 0;
errout:
return (retval);
return 0;
}
@ -342,10 +354,12 @@ errout:
*/
errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
{
char *ptr, *buf = 0;
int size;
ssize_t actual;
errcode_t retval;
ext2fs_generic_bitmap bmap;
errcode_t err, retval;
__u32 itr, cnt;
char buf[1024];
unsigned int size;
ssize_t actual;
if (flags & IMAGER_FLAG_INODEMAP) {
if (!fs->inode_map) {
@ -353,7 +367,10 @@ errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
if (retval)
return retval;
}
ptr = fs->inode_map->bitmap;
bmap = fs->inode_map;
err = EXT2_ET_MAGIC_INODE_BITMAP;
itr = 1;
cnt = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
} else {
if (!fs->block_map) {
@ -361,29 +378,31 @@ errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
if (retval)
return retval;
}
ptr = fs->block_map->bitmap;
bmap = fs->block_map;
err = EXT2_ET_MAGIC_BLOCK_BITMAP;
itr = fs->super->s_first_data_block;
cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count;
size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
}
size = size * fs->group_desc_count;
buf = malloc(size);
if (!buf)
return ENOMEM;
while (cnt > 0) {
size = sizeof(buf);
if (size > (cnt >> 3))
size = (cnt >> 3);
actual = read(fd, buf, size);
if (actual == -1) {
retval = errno;
goto errout;
actual = read(fd, buf, size);
if (actual == -1)
return errno;
if (actual != (int) size)
return EXT2_ET_SHORT_READ;
retval = ext2fs_set_generic_bitmap_range(bmap,
err, itr, size << 3, buf);
if (retval)
return retval;
itr += size << 3;
cnt -= size << 3;
}
if (actual != size) {
retval = EXT2_ET_SHORT_WRITE;
goto errout;
}
memcpy(ptr, buf, size);
retval = 0;
errout:
if (buf)
free(buf);
return (retval);
return 0;
}

View File

@ -58,10 +58,11 @@ static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block)
int block_nbytes, inode_nbytes;
unsigned int nbits;
errcode_t retval;
char *block_bitmap, *inode_bitmap;
char *block_buf, *inode_buf;
int lazy_flag = 0;
blk_t blk;
blk_t blk_itr = fs->super->s_first_data_block;
ext2_ino_t ino_itr = 1;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
@ -71,9 +72,7 @@ static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block)
EXT2_FEATURE_COMPAT_LAZY_BG))
lazy_flag = 1;
inode_nbytes = block_nbytes = 0;
block_bitmap = inode_bitmap = 0;
if (do_block) {
block_bitmap = fs->block_map->bitmap;
block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
retval = ext2fs_get_mem(fs->blocksize, &block_buf);
if (retval)
@ -81,7 +80,6 @@ static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block)
memset(block_buf, 0xff, fs->blocksize);
}
if (do_inode) {
inode_bitmap = fs->inode_map->bitmap;
inode_nbytes = (size_t)
((EXT2_INODES_PER_GROUP(fs->super)+7) / 8);
retval = ext2fs_get_mem(fs->blocksize, &inode_buf);
@ -91,14 +89,18 @@ static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block)
}
for (i = 0; i < fs->group_desc_count; i++) {
if (!block_bitmap || !do_block)
if (!do_block)
goto skip_block_bitmap;
if (lazy_flag && fs->group_desc[i].bg_flags &
EXT2_BG_BLOCK_UNINIT)
goto skip_this_block_bitmap;
memcpy(block_buf, block_bitmap, block_nbytes);
retval = ext2fs_get_block_bitmap_range(fs->block_map,
blk_itr, block_nbytes << 3, block_buf);
if (retval)
return retval;
if (i == fs->group_desc_count - 1) {
/* Force bitmap padding for the last group */
nbits = ((fs->super->s_blocks_count
@ -122,17 +124,21 @@ static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block)
return EXT2_ET_BLOCK_BITMAP_WRITE;
}
skip_this_block_bitmap:
block_bitmap += block_nbytes;
blk_itr += block_nbytes << 3;
skip_block_bitmap:
if (!inode_bitmap || !do_inode)
if (!do_inode)
continue;
if (lazy_flag && fs->group_desc[i].bg_flags &
EXT2_BG_INODE_UNINIT)
goto skip_this_inode_bitmap;
memcpy(inode_buf, inode_bitmap, inode_nbytes);
retval = ext2fs_get_inode_bitmap_range(fs->inode_map,
ino_itr, inode_nbytes << 3, inode_buf);
if (retval)
return retval;
blk = fs->group_desc[i].bg_inode_bitmap;
if (blk) {
#ifdef EXT2_BIG_ENDIAN_BITMAPS
@ -147,7 +153,7 @@ static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block)
return EXT2_ET_INODE_BITMAP_WRITE;
}
skip_this_inode_bitmap:
inode_bitmap += inode_nbytes;
ino_itr += inode_nbytes << 3;
}
if (do_block) {
@ -167,10 +173,16 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
char *block_bitmap = 0, *inode_bitmap = 0;
char *buf;
errcode_t retval;
int block_nbytes = (int) EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
int inode_nbytes = (int) EXT2_INODES_PER_GROUP(fs->super) / 8;
unsigned int block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
unsigned inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
int lazy_flag = 0;
int do_image = fs->flags & EXT2_FLAG_IMAGE_FILE;
unsigned int cnt;
blk_t blk;
blk_t blk_itr = fs->super->s_first_data_block;
blk_t blk_cnt;
ext2_ino_t ino_itr = 1;
ext2_ino_t ino_cnt;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
@ -190,8 +202,12 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
if (retval)
goto cleanup;
block_bitmap = fs->block_map->bitmap;
}
retval = ext2fs_get_mem(do_image ? fs->blocksize :
block_nbytes, &block_bitmap);
if (retval)
goto cleanup;
} else
block_nbytes = 0;
if (do_inode) {
if (fs->inode_map)
ext2fs_free_inode_bitmap(fs->inode_map);
@ -199,30 +215,54 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
if (retval)
goto cleanup;
inode_bitmap = fs->inode_map->bitmap;
}
retval = ext2fs_get_mem(do_image ? fs->blocksize :
inode_nbytes, &inode_bitmap);
if (retval)
goto cleanup;
} else
inode_nbytes = 0;
ext2fs_free_mem(&buf);
if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
if (inode_bitmap) {
blk = (fs->image_header->offset_inodemap /
fs->blocksize);
retval = io_channel_read_blk(fs->image_io, blk,
-(inode_nbytes * fs->group_desc_count),
inode_bitmap);
blk = (fs->image_header->offset_inodemap / fs->blocksize);
ino_cnt = fs->super->s_inodes_count;
while (inode_nbytes > 0) {
retval = io_channel_read_blk(fs->image_io, blk++,
1, inode_bitmap);
if (retval)
goto cleanup;
}
if (block_bitmap) {
blk = (fs->image_header->offset_blockmap /
fs->blocksize);
retval = io_channel_read_blk(fs->image_io, blk,
-(block_nbytes * fs->group_desc_count),
block_bitmap);
cnt = fs->blocksize << 3;
if (cnt > ino_cnt)
cnt = ino_cnt;
retval = ext2fs_set_inode_bitmap_range(fs->inode_map,
ino_itr, cnt, inode_bitmap);
if (retval)
goto cleanup;
ino_itr += fs->blocksize << 3;
ino_cnt -= fs->blocksize << 3;
inode_nbytes -= fs->blocksize;
}
return 0;
blk = (fs->image_header->offset_blockmap /
fs->blocksize);
blk_cnt = EXT2_BLOCKS_PER_GROUP(fs->super) *
fs->group_desc_count;
while (block_nbytes > 0) {
retval = io_channel_read_blk(fs->image_io, blk++,
1, block_bitmap);
if (retval)
goto cleanup;
cnt = fs->blocksize << 3;
if (cnt > blk_cnt)
cnt = blk_cnt;
retval = ext2fs_set_block_bitmap_range(fs->block_map,
blk_itr, cnt, block_bitmap);
if (retval)
goto cleanup;
blk_itr += fs->blocksize << 3;
blk_cnt -= fs->blocksize << 3;
block_nbytes -= fs->blocksize;
}
goto success_cleanup;
}
for (i = 0; i < fs->group_desc_count; i++) {
@ -245,7 +285,12 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
#endif
} else
memset(block_bitmap, 0xff, block_nbytes);
block_bitmap += block_nbytes;
cnt = block_nbytes << 3;
retval = ext2fs_set_block_bitmap_range(fs->block_map,
blk_itr, cnt, block_bitmap);
if (retval)
goto cleanup;
blk_itr += block_nbytes << 3;
}
if (inode_bitmap) {
blk = fs->group_desc[i].bg_inode_bitmap;
@ -266,9 +311,19 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
#endif
} else
memset(inode_bitmap, 0xff, inode_nbytes);
inode_bitmap += inode_nbytes;
cnt = inode_nbytes << 3;
retval = ext2fs_set_inode_bitmap_range(fs->inode_map,
ino_itr, cnt, inode_bitmap);
if (retval)
goto cleanup;
ino_itr += inode_nbytes << 3;
}
}
success_cleanup:
if (inode_bitmap)
ext2fs_free_mem(&inode_bitmap);
if (block_bitmap)
ext2fs_free_mem(&block_bitmap);
return 0;
cleanup:
@ -280,6 +335,10 @@ cleanup:
ext2fs_free_mem(&fs->inode_map);
fs->inode_map = 0;
}
if (inode_bitmap)
ext2fs_free_mem(&inode_bitmap);
if (block_bitmap)
ext2fs_free_mem(&block_bitmap);
if (buf)
ext2fs_free_mem(&buf);
return retval;

View File

@ -134,12 +134,18 @@ static void list_desc (ext2_filsys fs)
blk_t super_blk, old_desc_blk, new_desc_blk;
char *block_bitmap=NULL, *inode_bitmap=NULL;
int inode_blocks_per_group, old_desc_blocks, reserved_gdt;
int block_nbytes, inode_nbytes;
int has_super;
blk_t blk_itr = fs->super->s_first_data_block;
ext2_ino_t ino_itr = 1;
block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
if (fs->block_map)
block_bitmap = fs->block_map->bitmap;
block_bitmap = malloc(block_nbytes);
if (fs->inode_map)
inode_bitmap = fs->inode_map->bitmap;
inode_bitmap = malloc(inode_nbytes);
inode_blocks_per_group = ((fs->super->s_inodes_per_group *
EXT2_INODE_SIZE(fs->super)) +
@ -211,18 +217,22 @@ static void list_desc (ext2_filsys fs)
fs->group_desc[i].bg_used_dirs_count);
if (block_bitmap) {
fputs(_(" Free blocks: "), stdout);
ext2fs_get_block_bitmap_range(fs->block_map,
blk_itr, block_nbytes << 3, block_bitmap);
print_free (i, block_bitmap,
fs->super->s_blocks_per_group,
fs->super->s_first_data_block);
fputc('\n', stdout);
block_bitmap += fs->super->s_blocks_per_group / 8;
blk_itr += fs->super->s_blocks_per_group;
}
if (inode_bitmap) {
fputs(_(" Free inodes: "), stdout);
ext2fs_get_inode_bitmap_range(fs->inode_map,
ino_itr, inode_nbytes << 3, inode_bitmap);
print_free (i, inode_bitmap,
fs->super->s_inodes_per_group, 1);
fputc('\n', stdout);
inode_bitmap += fs->super->s_inodes_per_group / 8;
ino_itr += fs->super->s_inodes_per_group;
}
}
}