/* * inline_data.c --- data in inode * * Copyright (C) 2012 Zheng Liu * * %Begin-Header% * This file may be redistributed under the terms of the GNU library * General Public License, version 2. * %End-Header% */ #include "config.h" #include #include #include "ext2_fs.h" #include "ext2_ext_attr.h" #include "ext2fs.h" #include "ext2fsP.h" struct ext2_inline_data { ext2_filsys fs; ext2_ino_t ino; size_t ea_size; /* the size of inline data in ea area */ void *ea_data; }; static errcode_t ext2fs_inline_data_ea_set(struct ext2_inline_data *data) { struct ext2_xattr_handle *handle; errcode_t retval; retval = ext2fs_xattrs_open(data->fs, data->ino, &handle); if (retval) return retval; retval = ext2fs_xattrs_read(handle); if (retval) goto err; retval = ext2fs_xattr_set(handle, "system.data", data->ea_data, data->ea_size); if (retval) goto err; retval = ext2fs_xattrs_write(handle); err: (void) ext2fs_xattrs_close(&handle); return retval; } static errcode_t ext2fs_inline_data_ea_get(struct ext2_inline_data *data) { struct ext2_xattr_handle *handle; errcode_t retval; data->ea_size = 0; data->ea_data = 0; retval = ext2fs_xattrs_open(data->fs, data->ino, &handle); if (retval) return retval; retval = ext2fs_xattrs_read(handle); if (retval) goto err; retval = ext2fs_xattr_get(handle, "system.data", (void **)&data->ea_data, &data->ea_size); if (retval) goto err; err: (void) ext2fs_xattrs_close(&handle); return retval; } int ext2fs_inline_data_dir_iterate(ext2_filsys fs, ext2_ino_t ino, void *priv_data) { struct dir_context *ctx; struct ext2_inode inode; struct ext2_dir_entry dirent; struct ext2_inline_data data; int ret = BLOCK_ABORT; e2_blkcnt_t blockcnt = 0; ctx = (struct dir_context *)priv_data; ctx->errcode = ext2fs_read_inode(fs, ino, &inode); if (ctx->errcode) goto out; if (!(inode.i_flags & EXT4_INLINE_DATA_FL)) { ctx->errcode = EXT2_ET_NO_INLINE_DATA; goto out; } if (!LINUX_S_ISDIR(inode.i_mode)) { ctx->errcode = EXT2_ET_NO_DIRECTORY; goto out; } ret = 0; /* we first check '.' and '..' dir */ dirent.inode = ino; dirent.name_len = 1; ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(2), &dirent); dirent.name[0] = '.'; dirent.name[1] = '\0'; ctx->buf = (char *)&dirent; ext2fs_get_rec_len(fs, &dirent, &ctx->buflen); ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data); if (ret & BLOCK_ABORT) goto out; dirent.inode = ext2fs_le32_to_cpu(inode.i_block[0]); dirent.name_len = 2; ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(3), &dirent); dirent.name[0] = '.'; dirent.name[1] = '.'; dirent.name[2] = '\0'; ctx->buf = (char *)&dirent; ext2fs_get_rec_len(fs, &dirent, &ctx->buflen); ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data); if (ret & BLOCK_INLINE_DATA_CHANGED) { errcode_t err; inode.i_block[0] = ext2fs_cpu_to_le32(dirent.inode); err = ext2fs_write_inode(fs, ino, &inode); if (err) goto out; ret &= ~BLOCK_INLINE_DATA_CHANGED; } if (ret & BLOCK_ABORT) goto out; ctx->buf = (char *)inode.i_block + EXT4_INLINE_DATA_DOTDOT_SIZE; ctx->buflen = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE; #ifdef WORDS_BIGENDIAN ctx->errcode = ext2fs_dirent_swab_in2(fs, ctx->buf, ctx->buflen, 0); if (ctx->errcode) { ret |= BLOCK_ABORT; goto out; } #endif ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data); if (ret & BLOCK_INLINE_DATA_CHANGED) { #ifdef WORDS_BIGENDIAN ctx->errcode = ext2fs_dirent_swab_out2(fs, ctx->buf, ctx->buflen, 0); if (ctx->errcode) { ret |= BLOCK_ABORT; goto out; } #endif ctx->errcode = ext2fs_write_inode(fs, ino, &inode); if (ctx->errcode) ret |= BLOCK_ABORT; ret &= ~BLOCK_INLINE_DATA_CHANGED; } if (ret & BLOCK_ABORT) goto out; data.fs = fs; data.ino = ino; ctx->errcode = ext2fs_inline_data_ea_get(&data); if (ctx->errcode) { ret |= BLOCK_ABORT; goto out; } if (data.ea_size <= 0) goto out; ctx->buf = data.ea_data; ctx->buflen = data.ea_size; #ifdef WORDS_BIGENDIAN ctx.errcode = ext2fs_dirent_swab_in2(fs, ctx->buf, ctx->buflen, 0); if (ctx.errcode) { ret |= BLOCK_ABORT; goto out; } #endif ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data); if (ret & BLOCK_INLINE_DATA_CHANGED) { #ifdef WORDS_BIGENDIAN ctx->errcode = ext2fs_dirent_swab_out2(fs, ctx->buf, ctx->buflen, 0); if (ctx->errcode) { ret |= BLOCK_ABORT; goto out1; } #endif ctx->errcode = ext2fs_inline_data_ea_set(&data); if (ctx->errcode) ret |= BLOCK_ABORT; } out1: ext2fs_free_mem(&data.ea_data); ctx->buf = 0; out: ret &= ~(BLOCK_ABORT | BLOCK_INLINE_DATA_CHANGED); return ret; }