FileUtils.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. #include "FileUtils.h"
  2. #include <AK/FileSystemPath.h>
  3. #include <AK/StringBuilder.h>
  4. #include <LibCore/CDirIterator.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <sys/stat.h>
  8. #include <unistd.h>
  9. namespace FileUtils {
  10. bool copy_file_or_directory(const String& src_path, const String& dst_path)
  11. {
  12. int duplicate_count = 0;
  13. while (access(get_duplicate_name(dst_path, duplicate_count).characters(), F_OK) == 0) {
  14. ++duplicate_count;
  15. }
  16. if (duplicate_count != 0) {
  17. return copy_file_or_directory(src_path, get_duplicate_name(dst_path, duplicate_count));
  18. }
  19. int src_fd = open(src_path.characters(), O_RDONLY);
  20. if (src_fd < 0) {
  21. return false;
  22. }
  23. struct stat src_stat;
  24. int rc = fstat(src_fd, &src_stat);
  25. if (rc < 0) {
  26. return false;
  27. }
  28. if (S_ISDIR(src_stat.st_mode)) {
  29. return copy_directory(src_path, dst_path);
  30. }
  31. return copy_file(src_path, dst_path, src_stat, src_fd);
  32. }
  33. bool copy_directory(const String& src_path, const String& dst_path)
  34. {
  35. int rc = mkdir(dst_path.characters(), 0755);
  36. if (rc < 0) {
  37. return false;
  38. }
  39. CDirIterator di(src_path, CDirIterator::SkipDots);
  40. if (di.has_error()) {
  41. return false;
  42. }
  43. while (di.has_next()) {
  44. String filename = di.next_path();
  45. bool is_copied = copy_file_or_directory(
  46. String::format("%s/%s", src_path.characters(), filename.characters()),
  47. String::format("%s/%s", dst_path.characters(), filename.characters()));
  48. if (!is_copied) {
  49. return false;
  50. }
  51. }
  52. return true;
  53. }
  54. bool copy_file(const String& src_path, const String& dst_path, const struct stat& src_stat, int src_fd)
  55. {
  56. int dst_fd = creat(dst_path.characters(), 0666);
  57. if (dst_fd < 0) {
  58. if (errno != EISDIR) {
  59. return false;
  60. }
  61. StringBuilder builder;
  62. builder.appendf("%s/%s", dst_path, FileSystemPath(src_path).basename());
  63. String dst_path = builder.to_string();
  64. dst_fd = creat(dst_path.characters(), 0666);
  65. if (dst_fd < 0) {
  66. return false;
  67. }
  68. }
  69. for (;;) {
  70. char buffer[BUFSIZ];
  71. ssize_t nread = read(src_fd, buffer, sizeof(buffer));
  72. if (nread < 0) {
  73. return false;
  74. }
  75. if (nread == 0)
  76. break;
  77. ssize_t remaining_to_write = nread;
  78. char* bufptr = buffer;
  79. while (remaining_to_write) {
  80. ssize_t nwritten = write(dst_fd, bufptr, remaining_to_write);
  81. if (nwritten < 0) {
  82. return false;
  83. }
  84. assert(nwritten > 0);
  85. remaining_to_write -= nwritten;
  86. bufptr += nwritten;
  87. }
  88. }
  89. auto my_umask = umask(0);
  90. umask(my_umask);
  91. int rc = fchmod(dst_fd, src_stat.st_mode & ~my_umask);
  92. if (rc < 0) {
  93. return false;
  94. }
  95. close(src_fd);
  96. close(dst_fd);
  97. return true;
  98. }
  99. String get_duplicate_name(const String& path, int duplicate_count)
  100. {
  101. if (duplicate_count == 0) {
  102. return path;
  103. }
  104. FileSystemPath fsp(path);
  105. StringBuilder duplicated_name;
  106. duplicated_name.append('/');
  107. for (int i = 0; i < fsp.parts().size() - 1; ++i) {
  108. duplicated_name.appendf("%s/", fsp.parts()[i].characters());
  109. }
  110. auto prev_duplicate_tag = String::format("(%d)", duplicate_count);
  111. auto title = fsp.title();
  112. if (title.ends_with(prev_duplicate_tag)) {
  113. // remove the previous duplicate tag "(n)" so we can add a new tag.
  114. title = title.substring(0, title.length() - prev_duplicate_tag.length());
  115. }
  116. duplicated_name.appendf("%s (%d)", fsp.title().characters(), duplicate_count);
  117. if (!fsp.extension().is_empty()) {
  118. duplicated_name.appendf(".%s", fsp.extension().characters());
  119. }
  120. return duplicated_name.build();
  121. }
  122. }