1 /* 2 * create_inode.c --- create an inode 3 * 4 * Copyright (C) 2014 Robert Yang <liezhi.yang (at) windriver.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 #define _FILE_OFFSET_BITS 64 13 #define _LARGEFILE64_SOURCE 1 14 #define _GNU_SOURCE 1 15 16 #include "config.h" 17 #include <time.h> 18 #include <sys/stat.h> 19 #include <sys/types.h> 20 #include <unistd.h> 21 #include <limits.h> /* for PATH_MAX */ 22 #ifdef HAVE_ATTR_XATTR_H 23 #include <attr/xattr.h> 24 #endif 25 #ifdef HAVE_SYS_IOCTL_H 26 #include <sys/ioctl.h> 27 #endif 28 #ifdef HAVE_SYS_SYSMACROS_H 29 #include <sys/sysmacros.h> 30 #endif 31 32 #include <ext2fs/ext2fs.h> 33 #include <ext2fs/ext2_types.h> 34 #include <ext2fs/fiemap.h> 35 36 #include "create_inode.h" 37 #include "support/nls-enable.h" 38 39 /* 64KiB is the minimium blksize to best minimize system call overhead. */ 40 #define COPY_FILE_BUFLEN 65536 41 42 static int ext2_file_type(unsigned int mode) 43 { 44 if (LINUX_S_ISREG(mode)) 45 return EXT2_FT_REG_FILE; 46 47 if (LINUX_S_ISDIR(mode)) 48 return EXT2_FT_DIR; 49 50 if (LINUX_S_ISCHR(mode)) 51 return EXT2_FT_CHRDEV; 52 53 if (LINUX_S_ISBLK(mode)) 54 return EXT2_FT_BLKDEV; 55 56 if (LINUX_S_ISLNK(mode)) 57 return EXT2_FT_SYMLINK; 58 59 if (LINUX_S_ISFIFO(mode)) 60 return EXT2_FT_FIFO; 61 62 if (LINUX_S_ISSOCK(mode)) 63 return EXT2_FT_SOCK; 64 65 return 0; 66 } 67 68 /* Link an inode number to a directory */ 69 static errcode_t add_link(ext2_filsys fs, ext2_ino_t parent_ino, 70 ext2_ino_t ino, const char *name) 71 { 72 struct ext2_inode inode; 73 errcode_t retval; 74 75 retval = ext2fs_read_inode(fs, ino, &inode); 76 if (retval) { 77 com_err(__func__, retval, _("while reading inode %u"), ino); 78 return retval; 79 } 80 81 retval = ext2fs_link(fs, parent_ino, name, ino, 82 ext2_file_type(inode.i_mode)); 83 if (retval == EXT2_ET_DIR_NO_SPACE) { 84 retval = ext2fs_expand_dir(fs, parent_ino); 85 if (retval) { 86 com_err(__func__, retval, 87 _("while expanding directory")); 88 return retval; 89 } 90 retval = ext2fs_link(fs, parent_ino, name, ino, 91 ext2_file_type(inode.i_mode)); 92 } 93 if (retval) { 94 com_err(__func__, retval, _("while linking \"%s\""), name); 95 return retval; 96 } 97 98 inode.i_links_count++; 99 100 retval = ext2fs_write_inode(fs, ino, &inode); 101 if (retval) 102 com_err(__func__, retval, _("while writing inode %u"), ino); 103 104 return retval; 105 } 106 107 /* Set the uid, gid, mode and time for the inode */ 108 static errcode_t set_inode_extra(ext2_filsys fs, ext2_ino_t ino, 109 struct stat *st) 110 { 111 errcode_t retval; 112 struct ext2_inode inode; 113 114 retval = ext2fs_read_inode(fs, ino, &inode); 115 if (retval) { 116 com_err(__func__, retval, _("while reading inode %u"), ino); 117 return retval; 118 } 119 120 inode.i_uid = st->st_uid; 121 inode.i_gid = st->st_gid; 122 inode.i_mode |= st->st_mode; 123 inode.i_atime = st->st_atime; 124 inode.i_mtime = st->st_mtime; 125 inode.i_ctime = st->st_ctime; 126 127 retval = ext2fs_write_inode(fs, ino, &inode); 128 if (retval) 129 com_err(__func__, retval, _("while writing inode %u"), ino); 130 return retval; 131 } 132 133 #ifdef HAVE_LLISTXATTR 134 static errcode_t set_inode_xattr(ext2_filsys fs, ext2_ino_t ino, 135 const char *filename) 136 { 137 errcode_t retval, close_retval; 138 struct ext2_xattr_handle *handle; 139 ssize_t size, value_size; 140 char *list = NULL; 141 int i; 142 143 size = llistxattr(filename, NULL, 0); 144 if (size == -1) { 145 retval = errno; 146 com_err(__func__, retval, _("while listing attributes of \"%s\""), 147 filename); 148 return retval; 149 } else if (size == 0) { 150 return 0; 151 } 152 153 retval = ext2fs_xattrs_open(fs, ino, &handle); 154 if (retval) { 155 if (retval == EXT2_ET_MISSING_EA_FEATURE) 156 return 0; 157 com_err(__func__, retval, _("while opening inode %u"), ino); 158 return retval; 159 } 160 161 retval = ext2fs_get_mem(size, &list); 162 if (retval) { 163 com_err(__func__, retval, _("while allocating memory")); 164 goto out; 165 } 166 167 size = llistxattr(filename, list, size); 168 if (size == -1) { 169 retval = errno; 170 com_err(__func__, retval, _("while listing attributes of \"%s\""), 171 filename); 172 goto out; 173 } 174 175 for (i = 0; i < size; i += strlen(&list[i]) + 1) { 176 const char *name = &list[i]; 177 char *value; 178 179 value_size = lgetxattr(filename, name, NULL, 0); 180 if (value_size == -1) { 181 retval = errno; 182 com_err(__func__, retval, 183 _("while reading attribute \"%s\" of \"%s\""), 184 name, filename); 185 break; 186 } 187 188 retval = ext2fs_get_mem(value_size, &value); 189 if (retval) { 190 com_err(__func__, retval, _("while allocating memory")); 191 break; 192 } 193 194 value_size = lgetxattr(filename, name, value, value_size); 195 if (value_size == -1) { 196 ext2fs_free_mem(&value); 197 retval = errno; 198 com_err(__func__, retval, 199 _("while reading attribute \"%s\" of \"%s\""), 200 name, filename); 201 break; 202 } 203 204 retval = ext2fs_xattr_set(handle, name, value, value_size); 205 ext2fs_free_mem(&value); 206 if (retval) { 207 com_err(__func__, retval, 208 _("while writing attribute \"%s\" to inode %u"), 209 name, ino); 210 break; 211 } 212 213 } 214 out: 215 ext2fs_free_mem(&list); 216 close_retval = ext2fs_xattrs_close(&handle); 217 if (close_retval) { 218 com_err(__func__, retval, _("while closing inode %u"), ino); 219 retval = retval ? retval : close_retval; 220 } 221 return retval; 222 return 0; 223 } 224 #else /* HAVE_LLISTXATTR */ 225 static errcode_t set_inode_xattr(ext2_filsys fs EXT2FS_ATTR((unused)), 226 ext2_ino_t ino EXT2FS_ATTR((unused)), 227 const char *filename EXT2FS_ATTR((unused))) 228 { 229 return 0; 230 } 231 #endif /* HAVE_LLISTXATTR */ 232 233 #ifndef _WIN32 234 /* Make a special files (block and character devices), fifo's, and sockets */ 235 errcode_t do_mknod_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name, 236 struct stat *st) 237 { 238 ext2_ino_t ino; 239 errcode_t retval; 240 struct ext2_inode inode; 241 unsigned long devmajor, devminor, mode; 242 int filetype; 243 244 switch(st->st_mode & S_IFMT) { 245 case S_IFCHR: 246 mode = LINUX_S_IFCHR; 247 filetype = EXT2_FT_CHRDEV; 248 break; 249 case S_IFBLK: 250 mode = LINUX_S_IFBLK; 251 filetype = EXT2_FT_BLKDEV; 252 break; 253 case S_IFIFO: 254 mode = LINUX_S_IFIFO; 255 filetype = EXT2_FT_FIFO; 256 break; 257 #ifndef _WIN32 258 case S_IFSOCK: 259 mode = LINUX_S_IFSOCK; 260 filetype = EXT2_FT_SOCK; 261 break; 262 #endif 263 default: 264 return EXT2_ET_INVALID_ARGUMENT; 265 } 266 267 retval = ext2fs_new_inode(fs, cwd, 010755, 0, &ino); 268 if (retval) { 269 com_err(__func__, retval, _("while allocating inode \"%s\""), 270 name); 271 return retval; 272 } 273 274 #ifdef DEBUGFS 275 printf("Allocated inode: %u\n", ino); 276 #endif 277 retval = ext2fs_link(fs, cwd, name, ino, filetype); 278 if (retval == EXT2_ET_DIR_NO_SPACE) { 279 retval = ext2fs_expand_dir(fs, cwd); 280 if (retval) { 281 com_err(__func__, retval, 282 _("while expanding directory")); 283 return retval; 284 } 285 retval = ext2fs_link(fs, cwd, name, ino, filetype); 286 } 287 if (retval) { 288 com_err(name, retval, _("while creating inode \"%s\""), name); 289 return retval; 290 } 291 if (ext2fs_test_inode_bitmap2(fs->inode_map, ino)) 292 com_err(__func__, 0, "Warning: inode already set"); 293 ext2fs_inode_alloc_stats2(fs, ino, +1, 0); 294 memset(&inode, 0, sizeof(inode)); 295 inode.i_mode = mode; 296 inode.i_atime = inode.i_ctime = inode.i_mtime = 297 fs->now ? fs->now : time(0); 298 299 if (filetype != S_IFIFO) { 300 devmajor = major(st->st_rdev); 301 devminor = minor(st->st_rdev); 302 303 if ((devmajor < 256) && (devminor < 256)) { 304 inode.i_block[0] = devmajor * 256 + devminor; 305 inode.i_block[1] = 0; 306 } else { 307 inode.i_block[0] = 0; 308 inode.i_block[1] = (devminor & 0xff) | (devmajor << 8) | 309 ((devminor & ~0xff) << 12); 310 } 311 } 312 inode.i_links_count = 1; 313 314 retval = ext2fs_write_new_inode(fs, ino, &inode); 315 if (retval) 316 com_err(__func__, retval, _("while writing inode %u"), ino); 317 318 return retval; 319 } 320 #endif 321 322 /* Make a symlink name -> target */ 323 errcode_t do_symlink_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name, 324 char *target, ext2_ino_t root) 325 { 326 char *cp; 327 ext2_ino_t parent_ino; 328 errcode_t retval; 329 330 cp = strrchr(name, '/'); 331 if (cp) { 332 *cp = 0; 333 retval = ext2fs_namei(fs, root, cwd, name, &parent_ino); 334 if (retval) { 335 com_err(name, retval, 0); 336 return retval; 337 } 338 name = cp+1; 339 } else 340 parent_ino = cwd; 341 342 retval = ext2fs_symlink(fs, parent_ino, 0, name, target); 343 if (retval == EXT2_ET_DIR_NO_SPACE) { 344 retval = ext2fs_expand_dir(fs, parent_ino); 345 if (retval) { 346 com_err("do_symlink_internal", retval, 347 _("while expanding directory")); 348 return retval; 349 } 350 retval = ext2fs_symlink(fs, parent_ino, 0, name, target); 351 } 352 if (retval) 353 com_err("ext2fs_symlink", retval, 354 _("while creating symlink \"%s\""), name); 355 return retval; 356 } 357 358 /* Make a directory in the fs */ 359 errcode_t do_mkdir_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name, 360 ext2_ino_t root) 361 { 362 char *cp; 363 ext2_ino_t parent_ino; 364 errcode_t retval; 365 366 367 cp = strrchr(name, '/'); 368 if (cp) { 369 *cp = 0; 370 retval = ext2fs_namei(fs, root, cwd, name, &parent_ino); 371 if (retval) { 372 com_err(name, retval, _("while looking up \"%s\""), 373 name); 374 return retval; 375 } 376 name = cp+1; 377 } else 378 parent_ino = cwd; 379 380 retval = ext2fs_mkdir(fs, parent_ino, 0, name); 381 if (retval == EXT2_ET_DIR_NO_SPACE) { 382 retval = ext2fs_expand_dir(fs, parent_ino); 383 if (retval) { 384 com_err(__func__, retval, 385 _("while expanding directory")); 386 return retval; 387 } 388 retval = ext2fs_mkdir(fs, parent_ino, 0, name); 389 } 390 if (retval) 391 com_err("ext2fs_mkdir", retval, 392 _("while creating directory \"%s\""), name); 393 return retval; 394 } 395 396 #if !defined HAVE_PREAD64 && !defined HAVE_PREAD 397 static ssize_t my_pread(int fd, void *buf, size_t count, off_t offset) 398 { 399 if (lseek(fd, offset, SEEK_SET) < 0) 400 return 0; 401 402 return read(fd, buf, count); 403 } 404 #endif /* !defined HAVE_PREAD64 && !defined HAVE_PREAD */ 405 406 static errcode_t copy_file_range(ext2_filsys fs, int fd, ext2_file_t e2_file, 407 off_t start, off_t end, char *buf, 408 char *zerobuf) 409 { 410 off_t off, bpos; 411 ssize_t got, blen; 412 unsigned int written; 413 char *ptr; 414 errcode_t err = 0; 415 416 for (off = start; off < end; off += COPY_FILE_BUFLEN) { 417 #ifdef HAVE_PREAD64 418 got = pread64(fd, buf, COPY_FILE_BUFLEN, off); 419 #elif HAVE_PREAD 420 got = pread(fd, buf, COPY_FILE_BUFLEN, off); 421 #else 422 got = my_pread(fd, buf, COPY_FILE_BUFLEN, off); 423 #endif 424 if (got < 0) { 425 err = errno; 426 goto fail; 427 } 428 for (bpos = 0, ptr = buf; bpos < got; bpos += fs->blocksize) { 429 blen = fs->blocksize; 430 if (blen > got - bpos) 431 blen = got - bpos; 432 if (memcmp(ptr, zerobuf, blen) == 0) { 433 ptr += blen; 434 continue; 435 } 436 err = ext2fs_file_lseek(e2_file, off + bpos, 437 EXT2_SEEK_SET, NULL); 438 if (err) 439 goto fail; 440 while (blen > 0) { 441 err = ext2fs_file_write(e2_file, ptr, blen, 442 &written); 443 if (err) 444 goto fail; 445 if (written == 0) { 446 err = EIO; 447 goto fail; 448 } 449 blen -= written; 450 ptr += written; 451 } 452 } 453 } 454 fail: 455 return err; 456 } 457 458 #if defined(SEEK_DATA) && defined(SEEK_HOLE) 459 static errcode_t try_lseek_copy(ext2_filsys fs, int fd, struct stat *statbuf, 460 ext2_file_t e2_file, char *buf, char *zerobuf) 461 { 462 off_t data = 0, hole; 463 off_t data_blk, hole_blk; 464 errcode_t err = 0; 465 466 /* Try to use SEEK_DATA and SEEK_HOLE */ 467 while (data < statbuf->st_size) { 468 data = lseek(fd, data, SEEK_DATA); 469 if (data < 0) { 470 if (errno == ENXIO) 471 break; 472 return EXT2_ET_UNIMPLEMENTED; 473 } 474 hole = lseek(fd, data, SEEK_HOLE); 475 if (hole < 0) 476 return EXT2_ET_UNIMPLEMENTED; 477 478 data_blk = data & ~(fs->blocksize - 1); 479 hole_blk = (hole + (fs->blocksize - 1)) & ~(fs->blocksize - 1); 480 err = copy_file_range(fs, fd, e2_file, data_blk, hole_blk, buf, 481 zerobuf); 482 if (err) 483 return err; 484 485 data = hole; 486 } 487 488 return err; 489 } 490 #endif /* SEEK_DATA and SEEK_HOLE */ 491 492 #if defined(FS_IOC_FIEMAP) 493 static errcode_t try_fiemap_copy(ext2_filsys fs, int fd, ext2_file_t e2_file, 494 char *buf, char *zerobuf) 495 { 496 #define EXTENT_MAX_COUNT 512 497 struct fiemap *fiemap_buf; 498 struct fiemap_extent *ext_buf, *ext; 499 int ext_buf_size, fie_buf_size; 500 off_t pos = 0; 501 unsigned int i; 502 errcode_t err; 503 504 ext_buf_size = EXTENT_MAX_COUNT * sizeof(struct fiemap_extent); 505 fie_buf_size = sizeof(struct fiemap) + ext_buf_size; 506 507 err = ext2fs_get_memzero(fie_buf_size, &fiemap_buf); 508 if (err) 509 return err; 510 511 ext_buf = fiemap_buf->fm_extents; 512 memset(fiemap_buf, 0, fie_buf_size); 513 fiemap_buf->fm_length = FIEMAP_MAX_OFFSET; 514 fiemap_buf->fm_flags |= FIEMAP_FLAG_SYNC; 515 fiemap_buf->fm_extent_count = EXTENT_MAX_COUNT; 516 517 do { 518 fiemap_buf->fm_start = pos; 519 memset(ext_buf, 0, ext_buf_size); 520 err = ioctl(fd, FS_IOC_FIEMAP, fiemap_buf); 521 if (err < 0 && (errno == EOPNOTSUPP || errno == ENOTTY)) { 522 err = EXT2_ET_UNIMPLEMENTED; 523 goto out; 524 } else if (err < 0 || fiemap_buf->fm_mapped_extents == 0) { 525 err = errno; 526 goto out; 527 } 528 for (i = 0, ext = ext_buf; i < fiemap_buf->fm_mapped_extents; 529 i++, ext++) { 530 err = copy_file_range(fs, fd, e2_file, ext->fe_logical, 531 ext->fe_logical + ext->fe_length, 532 buf, zerobuf); 533 if (err) 534 goto out; 535 } 536 537 ext--; 538 /* Record file's logical offset this time */ 539 pos = ext->fe_logical + ext->fe_length; 540 /* 541 * If fm_extents array has been filled and 542 * there are extents left, continue to cycle. 543 */ 544 } while (fiemap_buf->fm_mapped_extents == EXTENT_MAX_COUNT && 545 !(ext->fe_flags & FIEMAP_EXTENT_LAST)); 546 out: 547 ext2fs_free_mem(&fiemap_buf); 548 return err; 549 } 550 #endif /* FS_IOC_FIEMAP */ 551 552 static errcode_t copy_file(ext2_filsys fs, int fd, struct stat *statbuf, 553 ext2_ino_t ino) 554 { 555 ext2_file_t e2_file; 556 char *buf = NULL, *zerobuf = NULL; 557 errcode_t err, close_err; 558 559 err = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &e2_file); 560 if (err) 561 return err; 562 563 err = ext2fs_get_mem(COPY_FILE_BUFLEN, &buf); 564 if (err) 565 goto out; 566 567 err = ext2fs_get_memzero(fs->blocksize, &zerobuf); 568 if (err) 569 goto out; 570 571 #if defined(SEEK_DATA) && defined(SEEK_HOLE) 572 err = try_lseek_copy(fs, fd, statbuf, e2_file, buf, zerobuf); 573 if (err != EXT2_ET_UNIMPLEMENTED) 574 goto out; 575 #endif 576 577 #if defined(FS_IOC_FIEMAP) 578 err = try_fiemap_copy(fs, fd, e2_file, buf, zerobuf); 579 if (err != EXT2_ET_UNIMPLEMENTED) 580 goto out; 581 #endif 582 583 err = copy_file_range(fs, fd, e2_file, 0, statbuf->st_size, buf, 584 zerobuf); 585 out: 586 ext2fs_free_mem(&zerobuf); 587 ext2fs_free_mem(&buf); 588 close_err = ext2fs_file_close(e2_file); 589 if (err == 0) 590 err = close_err; 591 return err; 592 } 593 594 static int is_hardlink(struct hdlinks_s *hdlinks, dev_t dev, ino_t ino) 595 { 596 int i; 597 598 for (i = 0; i < hdlinks->count; i++) { 599 if (hdlinks->hdl[i].src_dev == dev && 600 hdlinks->hdl[i].src_ino == ino) 601 return i; 602 } 603 return -1; 604 } 605 606 /* Copy the native file to the fs */ 607 errcode_t do_write_internal(ext2_filsys fs, ext2_ino_t cwd, const char *src, 608 const char *dest, ext2_ino_t root) 609 { 610 int fd; 611 struct stat statbuf; 612 ext2_ino_t newfile; 613 errcode_t retval; 614 struct ext2_inode inode; 615 616 fd = ext2fs_open_file(src, O_RDONLY, 0); 617 if (fd < 0) { 618 retval = errno; 619 com_err(__func__, retval, _("while opening \"%s\" to copy"), 620 src); 621 return retval; 622 } 623 if (fstat(fd, &statbuf) < 0) { 624 retval = errno; 625 goto out; 626 } 627 628 retval = ext2fs_namei(fs, root, cwd, dest, &newfile); 629 if (retval == 0) { 630 retval = EXT2_ET_FILE_EXISTS; 631 goto out; 632 } 633 634 retval = ext2fs_new_inode(fs, cwd, 010755, 0, &newfile); 635 if (retval) 636 goto out; 637 #ifdef DEBUGFS 638 printf("Allocated inode: %u\n", newfile); 639 #endif 640 retval = ext2fs_link(fs, cwd, dest, newfile, 641 EXT2_FT_REG_FILE); 642 if (retval == EXT2_ET_DIR_NO_SPACE) { 643 retval = ext2fs_expand_dir(fs, cwd); 644 if (retval) 645 goto out; 646 retval = ext2fs_link(fs, cwd, dest, newfile, 647 EXT2_FT_REG_FILE); 648 } 649 if (retval) 650 goto out; 651 if (ext2fs_test_inode_bitmap2(fs->inode_map, newfile)) 652 com_err(__func__, 0, "Warning: inode already set"); 653 ext2fs_inode_alloc_stats2(fs, newfile, +1, 0); 654 memset(&inode, 0, sizeof(inode)); 655 inode.i_mode = (statbuf.st_mode & ~LINUX_S_IFMT) | LINUX_S_IFREG; 656 inode.i_atime = inode.i_ctime = inode.i_mtime = 657 fs->now ? fs->now : time(0); 658 inode.i_links_count = 1; 659 retval = ext2fs_inode_size_set(fs, &inode, statbuf.st_size); 660 if (retval) 661 goto out; 662 if (ext2fs_has_feature_inline_data(fs->super)) { 663 inode.i_flags |= EXT4_INLINE_DATA_FL; 664 } else if (ext2fs_has_feature_extents(fs->super)) { 665 ext2_extent_handle_t handle; 666 667 inode.i_flags &= ~EXT4_EXTENTS_FL; 668 retval = ext2fs_extent_open2(fs, newfile, &inode, &handle); 669 if (retval) 670 goto out; 671 ext2fs_extent_free(handle); 672 } 673 674 retval = ext2fs_write_new_inode(fs, newfile, &inode); 675 if (retval) 676 goto out; 677 if (inode.i_flags & EXT4_INLINE_DATA_FL) { 678 retval = ext2fs_inline_data_init(fs, newfile); 679 if (retval) 680 goto out; 681 } 682 if (LINUX_S_ISREG(inode.i_mode)) { 683 retval = copy_file(fs, fd, &statbuf, newfile); 684 if (retval) 685 goto out; 686 } 687 out: 688 close(fd); 689 return retval; 690 } 691 692 struct file_info { 693 char *path; 694 size_t path_len; 695 size_t path_max_len; 696 }; 697 698 static errcode_t path_append(struct file_info *target, const char *file) 699 { 700 if (strlen(file) + target->path_len + 1 > target->path_max_len) { 701 target->path_max_len *= 2; 702 target->path = realloc(target->path, target->path_max_len); 703 if (!target->path) 704 return EXT2_ET_NO_MEMORY; 705 } 706 target->path_len += sprintf(target->path + target->path_len, "/%s", 707 file); 708 return 0; 709 } 710 711 /* Copy files from source_dir to fs */ 712 static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino, 713 const char *source_dir, ext2_ino_t root, 714 struct hdlinks_s *hdlinks, 715 struct file_info *target, 716 struct fs_ops_callbacks *fs_callbacks) 717 { 718 const char *name; 719 DIR *dh; 720 struct dirent *dent; 721 struct stat st; 722 char *ln_target = NULL; 723 unsigned int save_inode; 724 ext2_ino_t ino; 725 errcode_t retval = 0; 726 int read_cnt; 727 int hdlink; 728 size_t cur_dir_path_len; 729 730 if (chdir(source_dir) < 0) { 731 retval = errno; 732 com_err(__func__, retval, 733 _("while changing working directory to \"%s\""), 734 source_dir); 735 return retval; 736 } 737 738 if (!(dh = opendir("."))) { 739 retval = errno; 740 com_err(__func__, retval, 741 _("while opening directory \"%s\""), source_dir); 742 return retval; 743 } 744 745 while ((dent = readdir(dh))) { 746 if ((!strcmp(dent->d_name, ".")) || 747 (!strcmp(dent->d_name, ".."))) 748 continue; 749 if (lstat(dent->d_name, &st)) { 750 retval = errno; 751 com_err(__func__, retval, _("while lstat \"%s\""), 752 dent->d_name); 753 goto out; 754 } 755 name = dent->d_name; 756 757 /* Check for hardlinks */ 758 save_inode = 0; 759 if (!S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode) && 760 st.st_nlink > 1) { 761 hdlink = is_hardlink(hdlinks, st.st_dev, st.st_ino); 762 if (hdlink >= 0) { 763 retval = add_link(fs, parent_ino, 764 hdlinks->hdl[hdlink].dst_ino, 765 name); 766 if (retval) { 767 com_err(__func__, retval, 768 "while linking %s", name); 769 goto out; 770 } 771 continue; 772 } else 773 save_inode = 1; 774 } 775 776 cur_dir_path_len = target->path_len; 777 retval = path_append(target, name); 778 if (retval) { 779 com_err(__func__, retval, 780 "while appending %s", name); 781 goto out; 782 } 783 784 if (fs_callbacks && fs_callbacks->create_new_inode) { 785 retval = fs_callbacks->create_new_inode(fs, 786 target->path, name, parent_ino, root, 787 st.st_mode & S_IFMT); 788 if (retval) 789 goto out; 790 } 791 792 switch(st.st_mode & S_IFMT) { 793 case S_IFCHR: 794 case S_IFBLK: 795 case S_IFIFO: 796 #ifndef _WIN32 797 case S_IFSOCK: 798 retval = do_mknod_internal(fs, parent_ino, name, &st); 799 if (retval) { 800 com_err(__func__, retval, 801 _("while creating special file " 802 "\"%s\""), name); 803 goto out; 804 } 805 break; 806 case S_IFLNK: 807 ln_target = malloc(st.st_size + 1); 808 if (ln_target == NULL) { 809 com_err(__func__, retval, 810 _("malloc failed")); 811 goto out; 812 } 813 read_cnt = readlink(name, ln_target, 814 st.st_size + 1); 815 if (read_cnt == -1) { 816 retval = errno; 817 com_err(__func__, retval, 818 _("while trying to read link \"%s\""), 819 name); 820 free(ln_target); 821 goto out; 822 } 823 if (read_cnt > st.st_size) { 824 com_err(__func__, retval, 825 _("symlink increased in size " 826 "between lstat() and readlink()")); 827 free(ln_target); 828 goto out; 829 } 830 ln_target[read_cnt] = '\0'; 831 retval = do_symlink_internal(fs, parent_ino, name, 832 ln_target, root); 833 free(ln_target); 834 if (retval) { 835 com_err(__func__, retval, 836 _("while writing symlink\"%s\""), 837 name); 838 goto out; 839 } 840 break; 841 #endif 842 case S_IFREG: 843 retval = do_write_internal(fs, parent_ino, name, name, 844 root); 845 if (retval) { 846 com_err(__func__, retval, 847 _("while writing file \"%s\""), name); 848 goto out; 849 } 850 break; 851 case S_IFDIR: 852 /* Don't choke on /lost+found */ 853 if (parent_ino == EXT2_ROOT_INO && 854 strcmp(name, "lost+found") == 0) 855 goto find_lnf; 856 retval = do_mkdir_internal(fs, parent_ino, name, 857 root); 858 if (retval) { 859 com_err(__func__, retval, 860 _("while making dir \"%s\""), name); 861 goto out; 862 } 863 find_lnf: 864 retval = ext2fs_namei(fs, root, parent_ino, 865 name, &ino); 866 if (retval) { 867 com_err(name, retval, 0); 868 goto out; 869 } 870 /* Populate the dir recursively*/ 871 retval = __populate_fs(fs, ino, name, root, hdlinks, 872 target, fs_callbacks); 873 if (retval) 874 goto out; 875 if (chdir("..")) { 876 retval = errno; 877 com_err(__func__, retval, 878 _("while changing directory")); 879 goto out; 880 } 881 break; 882 default: 883 com_err(__func__, 0, 884 _("ignoring entry \"%s\""), name); 885 } 886 887 retval = ext2fs_namei(fs, root, parent_ino, name, &ino); 888 if (retval) { 889 com_err(name, retval, _("while looking up \"%s\""), 890 name); 891 goto out; 892 } 893 894 retval = set_inode_extra(fs, ino, &st); 895 if (retval) { 896 com_err(__func__, retval, 897 _("while setting inode for \"%s\""), name); 898 goto out; 899 } 900 901 retval = set_inode_xattr(fs, ino, name); 902 if (retval) { 903 com_err(__func__, retval, 904 _("while setting xattrs for \"%s\""), name); 905 goto out; 906 } 907 908 if (fs_callbacks && fs_callbacks->end_create_new_inode) { 909 retval = fs_callbacks->end_create_new_inode(fs, 910 target->path, name, parent_ino, root, 911 st.st_mode & S_IFMT); 912 if (retval) 913 goto out; 914 } 915 916 /* Save the hardlink ino */ 917 if (save_inode) { 918 /* 919 * Check whether need more memory, and we don't need 920 * free() since the lifespan will be over after the fs 921 * populated. 922 */ 923 if (hdlinks->count == hdlinks->size) { 924 void *p = realloc(hdlinks->hdl, 925 (hdlinks->size + HDLINK_CNT) * 926 sizeof(struct hdlink_s)); 927 if (p == NULL) { 928 retval = EXT2_ET_NO_MEMORY; 929 com_err(name, retval, 930 _("while saving inode data")); 931 goto out; 932 } 933 hdlinks->hdl = p; 934 hdlinks->size += HDLINK_CNT; 935 } 936 hdlinks->hdl[hdlinks->count].src_dev = st.st_dev; 937 hdlinks->hdl[hdlinks->count].src_ino = st.st_ino; 938 hdlinks->hdl[hdlinks->count].dst_ino = ino; 939 hdlinks->count++; 940 } 941 target->path_len = cur_dir_path_len; 942 target->path[target->path_len] = 0; 943 } 944 945 out: 946 closedir(dh); 947 return retval; 948 } 949 950 errcode_t populate_fs2(ext2_filsys fs, ext2_ino_t parent_ino, 951 const char *source_dir, ext2_ino_t root, 952 struct fs_ops_callbacks *fs_callbacks) 953 { 954 struct file_info file_info; 955 struct hdlinks_s hdlinks; 956 errcode_t retval; 957 958 if (!(fs->flags & EXT2_FLAG_RW)) { 959 com_err(__func__, 0, "Filesystem opened readonly"); 960 return EROFS; 961 } 962 963 hdlinks.count = 0; 964 hdlinks.size = HDLINK_CNT; 965 hdlinks.hdl = realloc(NULL, hdlinks.size * sizeof(struct hdlink_s)); 966 if (hdlinks.hdl == NULL) { 967 retval = errno; 968 com_err(__func__, retval, _("while allocating memory")); 969 return retval; 970 } 971 972 file_info.path_len = 0; 973 file_info.path_max_len = 255; 974 file_info.path = calloc(file_info.path_max_len, 1); 975 976 retval = __populate_fs(fs, parent_ino, source_dir, root, &hdlinks, 977 &file_info, fs_callbacks); 978 979 free(file_info.path); 980 free(hdlinks.hdl); 981 return retval; 982 } 983 984 errcode_t populate_fs(ext2_filsys fs, ext2_ino_t parent_ino, 985 const char *source_dir, ext2_ino_t root) 986 { 987 return populate_fs2(fs, parent_ino, source_dir, root, NULL); 988 } 989