Directory.cpp 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  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, Optional<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<bool> Directory::is_valid_directory(int fd)
  29. {
  30. auto stat = TRY(System::fstat(fd));
  31. return stat.st_mode & S_IFDIR;
  32. }
  33. ErrorOr<Directory> Directory::adopt_fd(int fd, Optional<LexicalPath> path)
  34. {
  35. // This will also fail if the fd is invalid in the first place.
  36. if (!TRY(Directory::is_valid_directory(fd)))
  37. return Error::from_errno(ENOTDIR);
  38. return Directory { fd, move(path) };
  39. }
  40. ErrorOr<Directory> Directory::create(String path, CreateDirectories create_directories)
  41. {
  42. return create(LexicalPath { move(path) }, create_directories);
  43. }
  44. ErrorOr<Directory> Directory::create(LexicalPath path, CreateDirectories create_directories)
  45. {
  46. if (create_directories == CreateDirectories::Yes)
  47. TRY(ensure_directory(path));
  48. // FIXME: doesn't work on Linux probably
  49. auto fd = TRY(System::open(path.string(), O_CLOEXEC));
  50. return adopt_fd(fd, move(path));
  51. }
  52. ErrorOr<void> Directory::ensure_directory(LexicalPath const& path)
  53. {
  54. if (path.basename() == "/")
  55. return {};
  56. TRY(ensure_directory(path.parent()));
  57. auto return_value = System::mkdir(path.string(), 0755);
  58. // We don't care if the directory already exists.
  59. if (return_value.is_error() && return_value.error().code() != EEXIST)
  60. return return_value;
  61. return {};
  62. }
  63. ErrorOr<LexicalPath> Directory::path() const
  64. {
  65. if (!m_path.has_value())
  66. return Error::from_string_literal("Directory wasn't created with a path");
  67. return m_path.value();
  68. }
  69. ErrorOr<NonnullOwnPtr<Stream::File>> Directory::open(StringView filename, Stream::OpenMode mode) const
  70. {
  71. auto fd = TRY(System::openat(m_directory_fd, filename, Stream::File::open_mode_to_options(mode)));
  72. return Stream::File::adopt_fd(fd, mode);
  73. }
  74. ErrorOr<struct stat> Directory::stat() const
  75. {
  76. return System::fstat(m_directory_fd);
  77. }
  78. ErrorOr<DirIterator> Directory::create_iterator() const
  79. {
  80. return DirIterator { TRY(path()).string() };
  81. }
  82. }