1/* 2 * inline_data.c --- data in inode 3 * 4 * Copyright (C) 2012 Zheng Liu <wenqing.lz@taobao.com> 5 * 6 * %Begin-Header% 7 * This file may be redistributed under the terms of the GNU library 8 * General Public License, version 2. 9 * %End-Header% 10 */ 11 12#include "config.h" 13#include <stdio.h> 14#include <time.h> 15#include <limits.h> /* for PATH_MAX */ 16 17#include "ext2_fs.h" 18#include "ext2_ext_attr.h" 19 20#include "ext2fs.h" 21#include "ext2fsP.h" 22 23struct ext2_inline_data { 24 ext2_filsys fs; 25 ext2_ino_t ino; 26 size_t ea_size; /* the size of inline data in ea area */ 27 void *ea_data; 28}; 29 30static errcode_t ext2fs_inline_data_ea_set(struct ext2_inline_data *data) 31{ 32 struct ext2_xattr_handle *handle; 33 errcode_t retval; 34 35 retval = ext2fs_xattrs_open(data->fs, data->ino, &handle); 36 if (retval) 37 return retval; 38 39 retval = ext2fs_xattrs_read(handle); 40 if (retval) 41 goto err; 42 43 retval = ext2fs_xattr_set(handle, "system.data", 44 data->ea_data, data->ea_size); 45 if (retval) 46 goto err; 47 48 retval = ext2fs_xattrs_write(handle); 49 50err: 51 (void) ext2fs_xattrs_close(&handle); 52 return retval; 53} 54 55static errcode_t ext2fs_inline_data_ea_get(struct ext2_inline_data *data) 56{ 57 struct ext2_xattr_handle *handle; 58 errcode_t retval; 59 60 data->ea_size = 0; 61 data->ea_data = 0; 62 63 retval = ext2fs_xattrs_open(data->fs, data->ino, &handle); 64 if (retval) 65 return retval; 66 67 retval = ext2fs_xattrs_read(handle); 68 if (retval) 69 goto err; 70 71 retval = ext2fs_xattr_get(handle, "system.data", 72 (void **)&data->ea_data, &data->ea_size); 73 if (retval == EXT2_ET_EA_KEY_NOT_FOUND) { 74 data->ea_size = 0; 75 data->ea_data = NULL; 76 retval = 0; 77 } else if (retval) 78 goto err; 79 80err: 81 (void) ext2fs_xattrs_close(&handle); 82 return retval; 83} 84 85errcode_t ext2fs_inline_data_init(ext2_filsys fs, ext2_ino_t ino) 86{ 87 struct ext2_inline_data data; 88 char empty[1] = { '\0' }; 89 90 data.fs = fs; 91 data.ino = ino; 92 data.ea_size = 0; 93 data.ea_data = empty; 94 return ext2fs_inline_data_ea_set(&data); 95} 96 97errcode_t ext2fs_inline_data_size(ext2_filsys fs, ext2_ino_t ino, size_t *size) 98{ 99 struct ext2_inode inode; 100 struct ext2_inline_data data; 101 errcode_t retval; 102 103 retval = ext2fs_read_inode(fs, ino, &inode); 104 if (retval) 105 return retval; 106 107 if (!(inode.i_flags & EXT4_INLINE_DATA_FL)) 108 return EXT2_ET_NO_INLINE_DATA; 109 110 data.fs = fs; 111 data.ino = ino; 112 retval = ext2fs_inline_data_ea_get(&data); 113 if (retval) 114 return retval; 115 116 *size = EXT4_MIN_INLINE_DATA_SIZE + data.ea_size; 117 return ext2fs_free_mem(&data.ea_data); 118} 119 120int ext2fs_inline_data_dir_iterate(ext2_filsys fs, ext2_ino_t ino, 121 void *priv_data) 122{ 123 struct dir_context *ctx; 124 struct ext2_inode inode; 125 struct ext2_dir_entry dirent; 126 struct ext2_inline_data data; 127 int ret = BLOCK_ABORT; 128 e2_blkcnt_t blockcnt = 0; 129 char *old_buf; 130 unsigned int old_buflen; 131 int old_flags; 132 133 ctx = (struct dir_context *)priv_data; 134 old_buf = ctx->buf; 135 old_buflen = ctx->buflen; 136 old_flags = ctx->flags; 137 ctx->flags |= DIRENT_FLAG_INCLUDE_INLINE_DATA; 138 139 ctx->errcode = ext2fs_read_inode(fs, ino, &inode); 140 if (ctx->errcode) 141 goto out; 142 143 if (!(inode.i_flags & EXT4_INLINE_DATA_FL)) { 144 ctx->errcode = EXT2_ET_NO_INLINE_DATA; 145 goto out; 146 } 147 148 if (!LINUX_S_ISDIR(inode.i_mode)) { 149 ctx->errcode = EXT2_ET_NO_DIRECTORY; 150 goto out; 151 } 152 ret = 0; 153 154 /* we first check '.' and '..' dir */ 155 dirent.inode = ino; 156 dirent.name_len = 1; 157 ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(2), &dirent); 158 dirent.name[0] = '.'; 159 dirent.name[1] = '\0'; 160 ctx->buf = (char *)&dirent; 161 ext2fs_get_rec_len(fs, &dirent, &ctx->buflen); 162 ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data); 163 if (ret & BLOCK_ABORT) 164 goto out; 165 166 dirent.inode = ext2fs_le32_to_cpu(inode.i_block[0]); 167 dirent.name_len = 2; 168 ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(3), &dirent); 169 dirent.name[0] = '.'; 170 dirent.name[1] = '.'; 171 dirent.name[2] = '\0'; 172 ctx->buf = (char *)&dirent; 173 ext2fs_get_rec_len(fs, &dirent, &ctx->buflen); 174 ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data); 175 if (ret & BLOCK_INLINE_DATA_CHANGED) { 176 errcode_t err; 177 178 inode.i_block[0] = ext2fs_cpu_to_le32(dirent.inode); 179 err = ext2fs_write_inode(fs, ino, &inode); 180 if (err) 181 goto out; 182 ret &= ~BLOCK_INLINE_DATA_CHANGED; 183 } 184 if (ret & BLOCK_ABORT) 185 goto out; 186 187 ctx->buf = (char *)inode.i_block + EXT4_INLINE_DATA_DOTDOT_SIZE; 188 ctx->buflen = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE; 189#ifdef WORDS_BIGENDIAN 190 ctx->errcode = ext2fs_dirent_swab_in2(fs, ctx->buf, ctx->buflen, 0); 191 if (ctx->errcode) { 192 ret |= BLOCK_ABORT; 193 goto out; 194 } 195#endif 196 ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data); 197 if (ret & BLOCK_INLINE_DATA_CHANGED) { 198#ifdef WORDS_BIGENDIAN 199 ctx->errcode = ext2fs_dirent_swab_out2(fs, ctx->buf, 200 ctx->buflen, 0); 201 if (ctx->errcode) { 202 ret |= BLOCK_ABORT; 203 goto out; 204 } 205#endif 206 ctx->errcode = ext2fs_write_inode(fs, ino, &inode); 207 if (ctx->errcode) 208 ret |= BLOCK_ABORT; 209 ret &= ~BLOCK_INLINE_DATA_CHANGED; 210 } 211 if (ret & BLOCK_ABORT) 212 goto out; 213 214 data.fs = fs; 215 data.ino = ino; 216 ctx->errcode = ext2fs_inline_data_ea_get(&data); 217 if (ctx->errcode) { 218 ret |= BLOCK_ABORT; 219 goto out; 220 } 221 if (data.ea_size <= 0) 222 goto out1; 223 224 ctx->buf = data.ea_data; 225 ctx->buflen = data.ea_size; 226#ifdef WORDS_BIGENDIAN 227 ctx->errcode = ext2fs_dirent_swab_in2(fs, ctx->buf, ctx->buflen, 0); 228 if (ctx->errcode) { 229 ret |= BLOCK_ABORT; 230 goto out1; 231 } 232#endif 233 234 ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data); 235 if (ret & BLOCK_INLINE_DATA_CHANGED) { 236#ifdef WORDS_BIGENDIAN 237 ctx->errcode = ext2fs_dirent_swab_out2(fs, ctx->buf, 238 ctx->buflen, 0); 239 if (ctx->errcode) { 240 ret |= BLOCK_ABORT; 241 goto out1; 242 } 243#endif 244 ctx->errcode = ext2fs_inline_data_ea_set(&data); 245 if (ctx->errcode) 246 ret |= BLOCK_ABORT; 247 } 248 249out1: 250 ext2fs_free_mem(&data.ea_data); 251out: 252 ctx->buf = old_buf; 253 ctx->buflen = old_buflen; 254 ctx->flags = old_flags; 255 ret &= ~(BLOCK_ABORT | BLOCK_INLINE_DATA_CHANGED); 256 return ret; 257} 258 259errcode_t ext2fs_inline_data_ea_remove(ext2_filsys fs, ext2_ino_t ino) 260{ 261 struct ext2_xattr_handle *handle; 262 errcode_t retval; 263 264 retval = ext2fs_xattrs_open(fs, ino, &handle); 265 if (retval) 266 return retval; 267 268 retval = ext2fs_xattrs_read(handle); 269 if (retval) 270 goto err; 271 272 retval = ext2fs_xattr_remove(handle, "system.data"); 273 if (retval) 274 goto err; 275 276 retval = ext2fs_xattrs_write(handle); 277 278err: 279 (void) ext2fs_xattrs_close(&handle); 280 return retval; 281} 282 283static errcode_t ext2fs_inline_data_convert_dir(ext2_filsys fs, ext2_ino_t ino, 284 char *bbuf, char *ibuf, int size) 285{ 286 struct ext2_dir_entry *dir, *dir2; 287 struct ext2_dir_entry_tail *t; 288 errcode_t retval; 289 int offset; 290 unsigned int rec_len; 291 int csum_size = 0; 292 int filetype = 0; 293 294 if (ext2fs_has_feature_metadata_csum(fs->super)) 295 csum_size = sizeof(struct ext2_dir_entry_tail); 296 297 /* Create '.' and '..' */ 298 if (ext2fs_has_feature_filetype(fs->super)) 299 filetype = EXT2_FT_DIR; 300 301 /* 302 * Set up entry for '.' 303 */ 304 dir = (struct ext2_dir_entry *) bbuf; 305 dir->inode = ino; 306 ext2fs_dirent_set_name_len(dir, 1); 307 ext2fs_dirent_set_file_type(dir, filetype); 308 dir->name[0] = '.'; 309 rec_len = (fs->blocksize - csum_size) - EXT2_DIR_REC_LEN(1); 310 dir->rec_len = EXT2_DIR_REC_LEN(1); 311 312 /* 313 * Set up entry for '..' 314 */ 315 dir = (struct ext2_dir_entry *) (bbuf + dir->rec_len); 316 dir->rec_len = EXT2_DIR_REC_LEN(2); 317 dir->inode = ext2fs_le32_to_cpu(((__u32 *)ibuf)[0]); 318 ext2fs_dirent_set_name_len(dir, 2); 319 ext2fs_dirent_set_file_type(dir, filetype); 320 dir->name[0] = '.'; 321 dir->name[1] = '.'; 322 323 /* 324 * Ajust the last rec_len 325 */ 326 offset = EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2); 327 dir = (struct ext2_dir_entry *) (bbuf + offset); 328 memcpy(bbuf + offset, ibuf + EXT4_INLINE_DATA_DOTDOT_SIZE, 329 size - EXT4_INLINE_DATA_DOTDOT_SIZE); 330 size += EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) - 331 EXT4_INLINE_DATA_DOTDOT_SIZE; 332 333 do { 334 dir2 = dir; 335 retval = ext2fs_get_rec_len(fs, dir, &rec_len); 336 if (retval) 337 goto err; 338 offset += rec_len; 339 dir = (struct ext2_dir_entry *) (bbuf + offset); 340 } while (offset < size); 341 rec_len += fs->blocksize - csum_size - offset; 342 retval = ext2fs_set_rec_len(fs, rec_len, dir2); 343 if (retval) 344 goto err; 345 346 if (csum_size) { 347 t = EXT2_DIRENT_TAIL(bbuf, fs->blocksize); 348 ext2fs_initialize_dirent_tail(fs, t); 349 } 350 351err: 352 return retval; 353} 354 355static errcode_t 356ext2fs_inline_data_dir_expand(ext2_filsys fs, ext2_ino_t ino, 357 struct ext2_inode *inode, char *buf, size_t size) 358{ 359 errcode_t retval; 360 blk64_t blk; 361 char *blk_buf; 362 363 retval = ext2fs_get_memzero(fs->blocksize, &blk_buf); 364 if (retval) 365 return retval; 366 367#ifdef WORDS_BIGENDIAN 368 retval = ext2fs_dirent_swab_in2(fs, buf + EXT4_INLINE_DATA_DOTDOT_SIZE, 369 size, 0); 370 if (retval) 371 goto errout; 372#endif 373 374 /* Adjust the rec_len */ 375 retval = ext2fs_inline_data_convert_dir(fs, ino, blk_buf, buf, size); 376 if (retval) 377 goto errout; 378 /* Allocate a new block */ 379 retval = ext2fs_new_block2(fs, 0, 0, &blk); 380 if (retval) 381 goto errout; 382 retval = ext2fs_write_dir_block4(fs, blk, blk_buf, 0, ino); 383 if (retval) 384 goto errout; 385 386 /* Update inode */ 387 if (ext2fs_has_feature_extents(fs->super)) 388 inode->i_flags |= EXT4_EXTENTS_FL; 389 inode->i_flags &= ~EXT4_INLINE_DATA_FL; 390 retval = ext2fs_iblk_add_blocks(fs, inode, 1); 391 if (retval) 392 goto errout; 393 inode->i_size = fs->blocksize; 394 retval = ext2fs_bmap2(fs, ino, inode, 0, BMAP_SET, 0, 0, &blk); 395 if (retval) 396 goto errout; 397 retval = ext2fs_write_inode(fs, ino, inode); 398 if (retval) 399 goto errout; 400 ext2fs_block_alloc_stats(fs, blk, +1); 401 402errout: 403 ext2fs_free_mem(&blk_buf); 404 return retval; 405} 406 407static errcode_t 408ext2fs_inline_data_file_expand(ext2_filsys fs, ext2_ino_t ino, 409 struct ext2_inode *inode, char *buf, size_t size) 410{ 411 ext2_file_t e2_file; 412 errcode_t retval; 413 414 /* Update inode */ 415 memset(inode->i_block, 0, sizeof(inode->i_block)); 416 if (ext2fs_has_feature_extents(fs->super)) { 417 ext2_extent_handle_t handle; 418 419 inode->i_flags &= ~EXT4_EXTENTS_FL; 420 retval = ext2fs_extent_open2(fs, ino, inode, &handle); 421 if (retval) 422 return retval; 423 ext2fs_extent_free(handle); 424 } 425 inode->i_flags &= ~EXT4_INLINE_DATA_FL; 426 inode->i_size = 0; 427 retval = ext2fs_write_inode(fs, ino, inode); 428 if (retval) 429 return retval; 430 431 /* Write out the block buffer */ 432 retval = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &e2_file); 433 if (retval) 434 return retval; 435 retval = ext2fs_file_write(e2_file, buf, size, 0); 436 ext2fs_file_close(e2_file); 437 return retval; 438} 439 440errcode_t ext2fs_inline_data_expand(ext2_filsys fs, ext2_ino_t ino) 441{ 442 struct ext2_inode inode; 443 struct ext2_inline_data data; 444 errcode_t retval; 445 size_t inline_size; 446 char *inline_buf = 0; 447 448 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 449 450 retval = ext2fs_read_inode(fs, ino, &inode); 451 if (retval) 452 return retval; 453 454 if (!(inode.i_flags & EXT4_INLINE_DATA_FL)) 455 return EXT2_ET_NO_INLINE_DATA; 456 457 data.fs = fs; 458 data.ino = ino; 459 retval = ext2fs_inline_data_ea_get(&data); 460 if (retval) 461 return retval; 462 inline_size = data.ea_size + EXT4_MIN_INLINE_DATA_SIZE; 463 retval = ext2fs_get_mem(inline_size, &inline_buf); 464 if (retval) 465 goto errout; 466 467 memcpy(inline_buf, (void *)inode.i_block, EXT4_MIN_INLINE_DATA_SIZE); 468 if (data.ea_size > 0) { 469 memcpy(inline_buf + EXT4_MIN_INLINE_DATA_SIZE, 470 data.ea_data, data.ea_size); 471 } 472 473 memset((void *)inode.i_block, 0, EXT4_MIN_INLINE_DATA_SIZE); 474 /* 475 * NOTE: We must do this write -> ea_remove -> read cycle here because 476 * removing the inline data EA can free the EA block, which is a change 477 * that our stack copy of the inode will never see. If that happens, 478 * we can end up with the EA block and lblk 0 pointing to the same 479 * pblk, which is bad news. 480 */ 481 retval = ext2fs_write_inode(fs, ino, &inode); 482 if (retval) 483 goto errout; 484 retval = ext2fs_inline_data_ea_remove(fs, ino); 485 if (retval) 486 goto errout; 487 retval = ext2fs_read_inode(fs, ino, &inode); 488 if (retval) 489 goto errout; 490 491 if (LINUX_S_ISDIR(inode.i_mode)) { 492 retval = ext2fs_inline_data_dir_expand(fs, ino, &inode, 493 inline_buf, inline_size); 494 } else { 495 retval = ext2fs_inline_data_file_expand(fs, ino, &inode, 496 inline_buf, inline_size); 497 } 498 499errout: 500 if (inline_buf) 501 ext2fs_free_mem(&inline_buf); 502 ext2fs_free_mem(&data.ea_data); 503 return retval; 504} 505 506/* 507 * When caller uses this function to retrieve the inline data, it must 508 * allocate a buffer which has the size of inline data. The size of 509 * inline data can be know by ext2fs_inline_data_get_size(). 510 */ 511errcode_t ext2fs_inline_data_get(ext2_filsys fs, ext2_ino_t ino, 512 struct ext2_inode *inode, 513 void *buf, size_t *size) 514{ 515 struct ext2_inode inode_buf; 516 struct ext2_inline_data data; 517 errcode_t retval; 518 519 if (!inode) { 520 retval = ext2fs_read_inode(fs, ino, &inode_buf); 521 if (retval) 522 return retval; 523 inode = &inode_buf; 524 } 525 526 data.fs = fs; 527 data.ino = ino; 528 retval = ext2fs_inline_data_ea_get(&data); 529 if (retval) 530 return retval; 531 532 memcpy(buf, (void *)inode->i_block, EXT4_MIN_INLINE_DATA_SIZE); 533 if (data.ea_size > 0) 534 memcpy((char *) buf + EXT4_MIN_INLINE_DATA_SIZE, 535 data.ea_data, data.ea_size); 536 537 if (size) 538 *size = EXT4_MIN_INLINE_DATA_SIZE + data.ea_size; 539 ext2fs_free_mem(&data.ea_data); 540 return 0; 541} 542 543errcode_t ext2fs_inline_data_set(ext2_filsys fs, ext2_ino_t ino, 544 struct ext2_inode *inode, 545 void *buf, size_t size) 546{ 547 struct ext2_inode inode_buf; 548 struct ext2_inline_data data; 549 errcode_t retval; 550 size_t free_ea_size, existing_size, free_inode_size; 551 552 if (!inode) { 553 retval = ext2fs_read_inode(fs, ino, &inode_buf); 554 if (retval) 555 return retval; 556 inode = &inode_buf; 557 } 558 559 if (size <= EXT4_MIN_INLINE_DATA_SIZE) { 560 retval = ext2fs_inline_data_ea_remove(fs, ino); 561 if (retval) 562 return retval; 563 memcpy((void *)inode->i_block, buf, size); 564 return ext2fs_write_inode(fs, ino, inode); 565 } 566 567 retval = ext2fs_xattr_inode_max_size(fs, ino, &free_ea_size); 568 if (retval) 569 return retval; 570 571 retval = ext2fs_inline_data_size(fs, ino, &existing_size); 572 if (retval) 573 return retval; 574 575 if (existing_size < EXT4_MIN_INLINE_DATA_SIZE) 576 free_inode_size = EXT4_MIN_INLINE_DATA_SIZE - existing_size; 577 else 578 free_inode_size = 0; 579 580 if (size != existing_size && 581 size > existing_size + free_ea_size + free_inode_size) 582 return EXT2_ET_INLINE_DATA_NO_SPACE; 583 584 memcpy((void *)inode->i_block, buf, EXT4_MIN_INLINE_DATA_SIZE); 585 retval = ext2fs_write_inode(fs, ino, inode); 586 if (retval) 587 return retval; 588 data.fs = fs; 589 data.ino = ino; 590 data.ea_size = size - EXT4_MIN_INLINE_DATA_SIZE; 591 data.ea_data = (char *) buf + EXT4_MIN_INLINE_DATA_SIZE; 592 return ext2fs_inline_data_ea_set(&data); 593} 594 595#ifdef DEBUG 596#include "e2p/e2p.h" 597 598/* 599 * The length of buffer is set to 64 because in inode's i_block member it only 600 * can save 60 bytes. Thus this value can let the data being saved in extra 601 * space. 602 */ 603#define BUFF_SIZE (64) 604 605static errcode_t file_test(ext2_filsys fs) 606{ 607 struct ext2_inode inode; 608 ext2_ino_t newfile; 609 errcode_t retval; 610 size_t size; 611 char *buf = 0, *cmpbuf = 0; 612 613 /* create a new file */ 614 retval = ext2fs_new_inode(fs, 2, 010755, 0, &newfile); 615 if (retval) { 616 com_err("file_test", retval, "while allocaing a new inode"); 617 return 1; 618 } 619 620 memset(&inode, 0, sizeof(inode)); 621 inode.i_flags |= EXT4_INLINE_DATA_FL; 622 inode.i_size = EXT4_MIN_INLINE_DATA_SIZE; 623 inode.i_mode = LINUX_S_IFREG; 624 retval = ext2fs_write_new_inode(fs, newfile, &inode); 625 if (retval) { 626 com_err("file_test", retval, "while writting a new inode"); 627 return 1; 628 } 629 630 retval = ext2fs_inline_data_init(fs, newfile); 631 if (retval) { 632 com_err("file_test", retval, "while init 'system.data'"); 633 return 1; 634 } 635 636 retval = ext2fs_inline_data_size(fs, newfile, &size); 637 if (retval) { 638 com_err("file_test", retval, "while getting size"); 639 return 1; 640 } 641 642 if (size != EXT4_MIN_INLINE_DATA_SIZE) { 643 fprintf(stderr, 644 "tst_inline_data: size of inline data is wrong\n"); 645 return 1; 646 } 647 648 ext2fs_get_mem(BUFF_SIZE, &buf); 649 memset(buf, 'a', BUFF_SIZE); 650 retval = ext2fs_inline_data_set(fs, newfile, 0, buf, BUFF_SIZE); 651 if (retval) { 652 com_err("file_test", retval, 653 "while setting inline data %s", buf); 654 goto err; 655 } 656 657 ext2fs_get_mem(BUFF_SIZE, &cmpbuf); 658 retval = ext2fs_inline_data_get(fs, newfile, 0, cmpbuf, &size); 659 if (retval) { 660 com_err("file_test", retval, "while getting inline data"); 661 goto err; 662 } 663 664 if (size != BUFF_SIZE) { 665 fprintf(stderr, 666 "tst_inline_data: size %lu != buflen %u\n", 667 size, BUFF_SIZE); 668 retval = 1; 669 goto err; 670 } 671 672 if (memcmp(buf, cmpbuf, BUFF_SIZE)) { 673 fprintf(stderr, "tst_inline_data: buf != cmpbuf\n"); 674 retval = 1; 675 goto err; 676 } 677 678 retval = ext2fs_punch(fs, newfile, 0, 0, 0, ~0ULL); 679 if (retval) { 680 com_err("file_test", retval, "while truncating inode"); 681 goto err; 682 } 683 684 /* reload inode and check isize */ 685 ext2fs_read_inode(fs, newfile, &inode); 686 if (inode.i_size != 0) { 687 fprintf(stderr, "tst_inline_data: i_size should be 0\n"); 688 retval = 1; 689 } 690 691err: 692 if (cmpbuf) 693 ext2fs_free_mem(&cmpbuf); 694 if (buf) 695 ext2fs_free_mem(&buf); 696 return retval; 697} 698 699static errcode_t dir_test(ext2_filsys fs) 700{ 701 const char *dot_name = "."; 702 const char *stub_name = "stub"; 703 const char *parent_name = "test"; 704 ext2_ino_t parent, dir, tmp; 705 errcode_t retval; 706 char dirname[PATH_MAX]; 707 int i; 708 709 retval = ext2fs_mkdir(fs, 11, 11, stub_name); 710 if (retval) { 711 com_err("dir_test", retval, "while creating %s dir", stub_name); 712 return retval; 713 } 714 715 retval = ext2fs_mkdir(fs, 11, 0, parent_name); 716 if (retval) { 717 com_err("dir_test", retval, 718 "while creating %s dir", parent_name); 719 return retval; 720 } 721 722 retval = ext2fs_lookup(fs, 11, parent_name, strlen(parent_name), 723 0, &parent); 724 if (retval) { 725 com_err("dir_test", retval, 726 "while looking up %s dir", parent_name); 727 return retval; 728 } 729 730 retval = ext2fs_lookup(fs, parent, dot_name, strlen(dot_name), 731 0, &tmp); 732 if (retval) { 733 com_err("dir_test", retval, 734 "while looking up %s dir", parent_name); 735 return retval; 736 } 737 738 if (parent != tmp) { 739 fprintf(stderr, "tst_inline_data: parent (%u) != tmp (%u)\n", 740 parent, tmp); 741 return 1; 742 } 743 744 for (i = 0, dir = 13; i < 4; i++, dir++) { 745 tmp = 0; 746 snprintf(dirname, sizeof(dirname), "%d", i); 747 retval = ext2fs_mkdir(fs, parent, 0, dirname); 748 if (retval) { 749 com_err("dir_test", retval, 750 "while creating %s dir", dirname); 751 return retval; 752 } 753 754 retval = ext2fs_lookup(fs, parent, dirname, strlen(dirname), 755 0, &tmp); 756 if (retval) { 757 com_err("dir_test", retval, 758 "while looking up %s dir", parent_name); 759 return retval; 760 } 761 762 if (dir != tmp) { 763 fprintf(stderr, 764 "tst_inline_data: dir (%u) != tmp (%u)\n", 765 dir, tmp); 766 return 1; 767 } 768 } 769 770 snprintf(dirname, sizeof(dirname), "%d", i); 771 retval = ext2fs_mkdir(fs, parent, 0, dirname); 772 if (retval && retval != EXT2_ET_DIR_NO_SPACE) { 773 com_err("dir_test", retval, "while creating %s dir", dirname); 774 return retval; 775 } 776 777 retval = ext2fs_expand_dir(fs, parent); 778 if (retval) { 779 com_err("dir_test", retval, "while expanding %s dir", parent_name); 780 return retval; 781 } 782 783 return 0; 784} 785 786int main(int argc, char *argv[]) 787{ 788 ext2_filsys fs; 789 struct ext2_super_block param; 790 errcode_t retval; 791 792 /* setup */ 793 initialize_ext2_error_table(); 794 795 memset(¶m, 0, sizeof(param)); 796 ext2fs_blocks_count_set(¶m, 32768); 797 param.s_inodes_count = 100; 798 799 param.s_feature_incompat |= EXT4_FEATURE_INCOMPAT_INLINE_DATA; 800 param.s_rev_level = EXT2_DYNAMIC_REV; 801 param.s_inode_size = 256; 802 803 retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, ¶m, 804 test_io_manager, &fs); 805 if (retval) { 806 com_err("setup", retval, 807 "while initializing filesystem"); 808 exit(1); 809 } 810 811 retval = ext2fs_allocate_tables(fs); 812 if (retval) { 813 com_err("setup", retval, 814 "while allocating tables for test filesysmte"); 815 exit(1); 816 } 817 818 /* initialize inode cache */ 819 if (!fs->icache) { 820 ext2_ino_t first_ino = EXT2_FIRST_INO(fs->super); 821 int i; 822 823 /* we just want to init inode cache. So ignore error */ 824 ext2fs_create_inode_cache(fs, 16); 825 if (!fs->icache) { 826 fprintf(stderr, 827 "tst_inline_data: init inode cache failed\n"); 828 exit(1); 829 } 830 831 /* setup inode cache */ 832 for (i = 0; i < fs->icache->cache_size; i++) 833 fs->icache->cache[i].ino = first_ino++; 834 } 835 836 /* test */ 837 if (file_test(fs)) { 838 fprintf(stderr, "tst_inline_data(FILE): FAILED\n"); 839 return 1; 840 } 841 printf("tst_inline_data(FILE): OK\n"); 842 843 if (dir_test(fs)) { 844 fprintf(stderr, "tst_inline_data(DIR): FAILED\n"); 845 return 1; 846 } 847 printf("tst_inline_data(DIR): OK\n"); 848 849 return 0; 850} 851#endif 852