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