2 * inline_data.c --- data in inode
4 * Copyright (C) 2012 Zheng Liu <wenqing.lz@taobao.com>
7 * This file may be redistributed under the terms of the GNU library
8 * General Public License, version 2.
17 #include "ext2_ext_attr.h"
22 struct ext2_inline_data {
25 size_t ea_size; /* the size of inline data in ea area */
29 static errcode_t ext2fs_inline_data_ea_set(struct ext2_inline_data *data)
31 struct ext2_xattr_handle *handle;
34 retval = ext2fs_xattrs_open(data->fs, data->ino, &handle);
38 retval = ext2fs_xattrs_read(handle);
42 retval = ext2fs_xattr_set(handle, "system.data",
43 data->ea_data, data->ea_size);
47 retval = ext2fs_xattrs_write(handle);
50 (void) ext2fs_xattrs_close(&handle);
54 static errcode_t ext2fs_inline_data_ea_get(struct ext2_inline_data *data)
56 struct ext2_xattr_handle *handle;
62 retval = ext2fs_xattrs_open(data->fs, data->ino, &handle);
66 retval = ext2fs_xattrs_read(handle);
70 retval = ext2fs_xattr_get(handle, "system.data",
71 (void **)&data->ea_data, &data->ea_size);
76 (void) ext2fs_xattrs_close(&handle);
80 errcode_t ext2fs_inline_data_init(ext2_filsys fs, ext2_ino_t ino)
82 struct ext2_inline_data data;
88 return ext2fs_inline_data_ea_set(&data);
91 errcode_t ext2fs_inline_data_size(ext2_filsys fs, ext2_ino_t ino, size_t *size)
93 struct ext2_inode inode;
94 struct ext2_inline_data data;
97 retval = ext2fs_read_inode(fs, ino, &inode);
101 if (!(inode.i_flags & EXT4_INLINE_DATA_FL))
102 return EXT2_ET_NO_INLINE_DATA;
106 retval = ext2fs_inline_data_ea_get(&data);
110 *size = EXT4_MIN_INLINE_DATA_SIZE + data.ea_size;
111 return ext2fs_free_mem(&data.ea_data);
114 int ext2fs_inline_data_dir_iterate(ext2_filsys fs, ext2_ino_t ino,
117 struct dir_context *ctx;
118 struct ext2_inode inode;
119 struct ext2_dir_entry dirent;
120 struct ext2_inline_data data;
121 int ret = BLOCK_ABORT;
122 e2_blkcnt_t blockcnt = 0;
124 ctx = (struct dir_context *)priv_data;
126 ctx->errcode = ext2fs_read_inode(fs, ino, &inode);
130 if (!(inode.i_flags & EXT4_INLINE_DATA_FL)) {
131 ctx->errcode = EXT2_ET_NO_INLINE_DATA;
135 if (!LINUX_S_ISDIR(inode.i_mode)) {
136 ctx->errcode = EXT2_ET_NO_DIRECTORY;
141 /* we first check '.' and '..' dir */
144 ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(2), &dirent);
145 dirent.name[0] = '.';
146 dirent.name[1] = '\0';
147 ctx->buf = (char *)&dirent;
148 ext2fs_get_rec_len(fs, &dirent, &ctx->buflen);
149 ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data);
150 if (ret & BLOCK_ABORT)
153 dirent.inode = ext2fs_le32_to_cpu(inode.i_block[0]);
155 ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(3), &dirent);
156 dirent.name[0] = '.';
157 dirent.name[1] = '.';
158 dirent.name[2] = '\0';
159 ctx->buf = (char *)&dirent;
160 ext2fs_get_rec_len(fs, &dirent, &ctx->buflen);
161 ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data);
162 if (ret & BLOCK_INLINE_DATA_CHANGED) {
165 inode.i_block[0] = ext2fs_cpu_to_le32(dirent.inode);
166 err = ext2fs_write_inode(fs, ino, &inode);
169 ret &= ~BLOCK_INLINE_DATA_CHANGED;
171 if (ret & BLOCK_ABORT)
174 ctx->buf = (char *)inode.i_block + EXT4_INLINE_DATA_DOTDOT_SIZE;
175 ctx->buflen = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE;
176 #ifdef WORDS_BIGENDIAN
177 ctx->errcode = ext2fs_dirent_swab_in2(fs, ctx->buf, ctx->buflen, 0);
183 ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data);
184 if (ret & BLOCK_INLINE_DATA_CHANGED) {
185 #ifdef WORDS_BIGENDIAN
186 ctx->errcode = ext2fs_dirent_swab_out2(fs, ctx->buf,
193 ctx->errcode = ext2fs_write_inode(fs, ino, &inode);
196 ret &= ~BLOCK_INLINE_DATA_CHANGED;
198 if (ret & BLOCK_ABORT)
203 ctx->errcode = ext2fs_inline_data_ea_get(&data);
208 if (data.ea_size <= 0)
211 ctx->buf = data.ea_data;
212 ctx->buflen = data.ea_size;
213 #ifdef WORDS_BIGENDIAN
214 ctx.errcode = ext2fs_dirent_swab_in2(fs, ctx->buf, ctx->buflen, 0);
221 ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data);
222 if (ret & BLOCK_INLINE_DATA_CHANGED) {
223 #ifdef WORDS_BIGENDIAN
224 ctx->errcode = ext2fs_dirent_swab_out2(fs, ctx->buf,
231 ctx->errcode = ext2fs_inline_data_ea_set(&data);
237 ext2fs_free_mem(&data.ea_data);
241 ret &= ~(BLOCK_ABORT | BLOCK_INLINE_DATA_CHANGED);
245 static errcode_t ext2fs_inline_data_ea_remove(ext2_filsys fs, ext2_ino_t ino)
247 struct ext2_xattr_handle *handle;
250 retval = ext2fs_xattrs_open(fs, ino, &handle);
254 retval = ext2fs_xattrs_read(handle);
258 retval = ext2fs_xattr_remove(handle, "system.data");
262 retval = ext2fs_xattrs_write(handle);
265 (void) ext2fs_xattrs_close(&handle);
269 static errcode_t ext2fs_inline_data_convert_dir(ext2_filsys fs, ext2_ino_t ino,
270 char *bbuf, char *ibuf, int size)
272 struct ext2_dir_entry *dir, *dir2;
273 struct ext2_dir_entry_tail *t;
280 if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
281 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
282 csum_size = sizeof(struct ext2_dir_entry_tail);
284 /* Create '.' and '..' */
285 if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
286 EXT2_FEATURE_INCOMPAT_FILETYPE))
287 filetype = EXT2_FT_DIR;
290 * Set up entry for '.'
292 dir = (struct ext2_dir_entry *) bbuf;
294 ext2fs_dirent_set_name_len(dir, 1);
295 ext2fs_dirent_set_file_type(dir, filetype);
297 rec_len = (fs->blocksize - csum_size) - EXT2_DIR_REC_LEN(1);
298 dir->rec_len = EXT2_DIR_REC_LEN(1);
301 * Set up entry for '..'
303 dir = (struct ext2_dir_entry *) (bbuf + dir->rec_len);
304 dir->rec_len = EXT2_DIR_REC_LEN(2);
305 dir->inode = ext2fs_le32_to_cpu(((__u32 *)ibuf)[0]);
306 ext2fs_dirent_set_name_len(dir, 2);
307 ext2fs_dirent_set_file_type(dir, filetype);
312 * Ajust the last rec_len
314 offset = EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2);
315 dir = (struct ext2_dir_entry *) (bbuf + offset);
316 memcpy(bbuf + offset, ibuf + EXT4_INLINE_DATA_DOTDOT_SIZE,
317 size - EXT4_INLINE_DATA_DOTDOT_SIZE);
318 size += EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) -
319 EXT4_INLINE_DATA_DOTDOT_SIZE;
323 retval = ext2fs_get_rec_len(fs, dir, &rec_len);
327 dir = (struct ext2_dir_entry *) (bbuf + offset);
328 } while (offset < size);
329 rec_len += fs->blocksize - csum_size - offset;
330 retval = ext2fs_set_rec_len(fs, rec_len, dir2);
335 t = EXT2_DIRENT_TAIL(bbuf, fs->blocksize);
336 ext2fs_initialize_dirent_tail(fs, t);
343 errcode_t ext2fs_inline_data_expand(ext2_filsys fs, ext2_ino_t ino)
345 struct ext2_inode inode;
346 struct ext2_inline_data data;
349 char *inline_buf = 0;
352 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
354 retval = ext2fs_read_inode(fs, ino, &inode);
358 if (!(inode.i_flags & EXT4_INLINE_DATA_FL))
359 return EXT2_ET_NO_INLINE_DATA;
361 /* Get inline data first */
364 retval = ext2fs_inline_data_ea_get(&data);
367 retval = ext2fs_get_mem(EXT4_MIN_INLINE_DATA_SIZE + data.ea_size,
372 memcpy(inline_buf, (void *)inode.i_block, EXT4_MIN_INLINE_DATA_SIZE);
373 if (data.ea_size > 0) {
374 memcpy(inline_buf + EXT4_MIN_INLINE_DATA_SIZE,
375 data.ea_data, data.ea_size);
378 #ifdef WORDS_BIGENDIAN
379 retval = ext2fs_dirent_swab_in2(fs, inline_buf,
380 data.ea_size + EXT4_MIN_INLINE_DATA_SIZE);
385 memset((void *)inode.i_block, 0, EXT4_MIN_INLINE_DATA_SIZE);
386 retval = ext2fs_inline_data_ea_remove(fs, ino);
390 retval = ext2fs_get_mem(fs->blocksize, &blk_buf);
394 /* Adjust the rec_len */
395 retval = ext2fs_inline_data_convert_dir(fs, ino, blk_buf, inline_buf,
396 EXT4_MIN_INLINE_DATA_SIZE +
401 /* Allocate a new block */
402 retval = ext2fs_new_block2(fs, 0, 0, &blk);
405 retval = ext2fs_write_dir_block4(fs, blk, blk_buf, 0, ino);
410 if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT3_FEATURE_INCOMPAT_EXTENTS))
411 inode.i_flags |= EXT4_EXTENTS_FL;
412 inode.i_flags &= ~EXT4_INLINE_DATA_FL;
413 ext2fs_iblk_set(fs, &inode, 1);
414 inode.i_size = fs->blocksize;
415 retval = ext2fs_bmap2(fs, ino, &inode, 0, BMAP_SET, 0, 0, &blk);
418 retval = ext2fs_write_inode(fs, ino, &inode);
421 ext2fs_block_alloc_stats2(fs, blk, +1);
425 ext2fs_free_mem(&blk_buf);
427 ext2fs_free_mem(&inline_buf);
428 ext2fs_free_mem(&data.ea_data);