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