Directory.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /*
  2. * Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "Directory.h"
  7. #include "DirIterator.h"
  8. #include "System.h"
  9. #include <dirent.h>
  10. namespace Core {
  11. // We assume that the fd is a valid directory.
  12. Directory::Directory(int fd, LexicalPath path)
  13. : m_path(move(path))
  14. , m_directory_fd(fd)
  15. {
  16. }
  17. Directory::Directory(Directory&& other)
  18. : m_path(move(other.m_path))
  19. , m_directory_fd(other.m_directory_fd)
  20. {
  21. other.m_directory_fd = -1;
  22. }
  23. Directory::~Directory()
  24. {
  25. if (m_directory_fd != -1)
  26. MUST(System::close(m_directory_fd));
  27. }
  28. ErrorOr<void> Directory::chown(uid_t uid, gid_t gid)
  29. {
  30. if (m_directory_fd == -1)
  31. return Error::from_syscall("fchown"sv, -EBADF);
  32. TRY(Core::System::fchown(m_directory_fd, uid, gid));
  33. return {};
  34. }
  35. ErrorOr<bool> Directory::is_valid_directory(int fd)
  36. {
  37. auto stat = TRY(System::fstat(fd));
  38. return stat.st_mode & S_IFDIR;
  39. }
  40. ErrorOr<Directory> Directory::adopt_fd(int fd, LexicalPath path)
  41. {
  42. // This will also fail if the fd is invalid in the first place.
  43. if (!TRY(Directory::is_valid_directory(fd)))
  44. return Error::from_errno(ENOTDIR);
  45. return Directory { fd, move(path) };
  46. }
  47. ErrorOr<Directory> Directory::create(ByteString path, CreateDirectories create_directories, mode_t creation_mode)
  48. {
  49. return create(LexicalPath { move(path) }, create_directories, creation_mode);
  50. }
  51. ErrorOr<Directory> Directory::create(LexicalPath path, CreateDirectories create_directories, mode_t creation_mode)
  52. {
  53. if (create_directories == CreateDirectories::Yes)
  54. TRY(ensure_directory(path, creation_mode));
  55. // FIXME: doesn't work on Linux probably
  56. auto fd = TRY(System::open(path.string(), O_CLOEXEC));
  57. return adopt_fd(fd, move(path));
  58. }
  59. ErrorOr<void> Directory::ensure_directory(LexicalPath const& path, mode_t creation_mode)
  60. {
  61. if (path.basename() == "/" || path.basename() == ".")
  62. return {};
  63. TRY(ensure_directory(path.parent(), creation_mode));
  64. auto return_value = System::mkdir(path.string(), creation_mode);
  65. // We don't care if the directory already exists.
  66. if (return_value.is_error() && return_value.error().code() != EEXIST)
  67. return return_value;
  68. return {};
  69. }
  70. ErrorOr<NonnullOwnPtr<File>> Directory::open(StringView filename, File::OpenMode mode) const
  71. {
  72. auto fd = TRY(System::openat(m_directory_fd, filename, File::open_mode_to_options(mode)));
  73. return File::adopt_fd(fd, mode);
  74. }
  75. ErrorOr<struct stat> Directory::stat(StringView filename, int flags) const
  76. {
  77. return System::fstatat(m_directory_fd, filename, flags);
  78. }
  79. ErrorOr<struct stat> Directory::stat() const
  80. {
  81. return System::fstat(m_directory_fd);
  82. }
  83. ErrorOr<void> Directory::for_each_entry(DirIterator::Flags flags, Core::Directory::ForEachEntryCallback callback)
  84. {
  85. DirIterator iterator { path().string(), flags };
  86. if (iterator.has_error())
  87. return iterator.error();
  88. while (iterator.has_next()) {
  89. if (iterator.has_error())
  90. return iterator.error();
  91. auto entry = iterator.next();
  92. if (!entry.has_value())
  93. break;
  94. auto decision = TRY(callback(entry.value(), *this));
  95. if (decision == IterationDecision::Break)
  96. break;
  97. }
  98. return {};
  99. }
  100. ErrorOr<void> Directory::for_each_entry(AK::StringView path, DirIterator::Flags flags, Core::Directory::ForEachEntryCallback callback)
  101. {
  102. auto directory = TRY(Directory::create(path, CreateDirectories::No));
  103. return directory.for_each_entry(flags, move(callback));
  104. }
  105. }