DeprecatedFile.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*
  2. * Copyright (c) 2018-2022, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/LexicalPath.h>
  7. #include <AK/Platform.h>
  8. #include <AK/ScopeGuard.h>
  9. #include <LibCore/DeprecatedFile.h>
  10. #include <LibCore/DirIterator.h>
  11. #include <LibCore/System.h>
  12. #include <LibFileSystem/FileSystem.h>
  13. #include <errno.h>
  14. #include <fcntl.h>
  15. #include <libgen.h>
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <sys/stat.h>
  19. #include <unistd.h>
  20. #include <utime.h>
  21. #ifdef AK_OS_SERENITY
  22. # include <serenity.h>
  23. #endif
  24. namespace Core {
  25. ErrorOr<NonnullRefPtr<DeprecatedFile>> DeprecatedFile::open(DeprecatedString filename, OpenMode mode, mode_t permissions)
  26. {
  27. auto file = DeprecatedFile::construct(move(filename));
  28. if (!file->open_impl(mode, permissions))
  29. return Error::from_errno(file->error());
  30. return file;
  31. }
  32. DeprecatedFile::DeprecatedFile(DeprecatedString filename, Object* parent)
  33. : IODevice(parent)
  34. , m_filename(move(filename))
  35. {
  36. }
  37. DeprecatedFile::~DeprecatedFile()
  38. {
  39. if (m_should_close_file_descriptor == ShouldCloseFileDescriptor::Yes && mode() != OpenMode::NotOpen)
  40. close();
  41. }
  42. bool DeprecatedFile::open(int fd, OpenMode mode, ShouldCloseFileDescriptor should_close)
  43. {
  44. set_fd(fd);
  45. set_mode(mode);
  46. m_should_close_file_descriptor = should_close;
  47. return true;
  48. }
  49. bool DeprecatedFile::open(OpenMode mode)
  50. {
  51. return open_impl(mode, 0666);
  52. }
  53. bool DeprecatedFile::open_impl(OpenMode mode, mode_t permissions)
  54. {
  55. VERIFY(!m_filename.is_null());
  56. int flags = 0;
  57. if (has_flag(mode, OpenMode::ReadOnly) && has_flag(mode, OpenMode::WriteOnly)) {
  58. flags |= O_RDWR | O_CREAT;
  59. } else if (has_flag(mode, OpenMode::ReadOnly)) {
  60. flags |= O_RDONLY;
  61. } else if (has_flag(mode, OpenMode::WriteOnly)) {
  62. flags |= O_WRONLY | O_CREAT;
  63. bool should_truncate = !(has_flag(mode, OpenMode::Append) || has_flag(mode, OpenMode::MustBeNew));
  64. if (should_truncate)
  65. flags |= O_TRUNC;
  66. }
  67. if (has_flag(mode, OpenMode::Append))
  68. flags |= O_APPEND;
  69. if (has_flag(mode, OpenMode::Truncate))
  70. flags |= O_TRUNC;
  71. if (has_flag(mode, OpenMode::MustBeNew))
  72. flags |= O_EXCL;
  73. if (!has_flag(mode, OpenMode::KeepOnExec))
  74. flags |= O_CLOEXEC;
  75. int fd = ::open(m_filename.characters(), flags, permissions);
  76. if (fd < 0) {
  77. set_error(errno);
  78. return false;
  79. }
  80. set_fd(fd);
  81. set_mode(mode);
  82. return true;
  83. }
  84. int DeprecatedFile::leak_fd()
  85. {
  86. m_should_close_file_descriptor = ShouldCloseFileDescriptor::No;
  87. return fd();
  88. }
  89. bool DeprecatedFile::is_device() const
  90. {
  91. struct stat st;
  92. if (fstat(fd(), &st) < 0)
  93. return false;
  94. return S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode);
  95. }
  96. bool DeprecatedFile::is_block_device() const
  97. {
  98. struct stat stat;
  99. if (fstat(fd(), &stat) < 0)
  100. return false;
  101. return S_ISBLK(stat.st_mode);
  102. }
  103. bool DeprecatedFile::is_char_device() const
  104. {
  105. struct stat stat;
  106. if (fstat(fd(), &stat) < 0)
  107. return false;
  108. return S_ISCHR(stat.st_mode);
  109. }
  110. bool DeprecatedFile::is_directory() const
  111. {
  112. struct stat st;
  113. if (fstat(fd(), &st) < 0)
  114. return false;
  115. return S_ISDIR(st.st_mode);
  116. }
  117. bool DeprecatedFile::is_link() const
  118. {
  119. struct stat stat;
  120. if (fstat(fd(), &stat) < 0)
  121. return false;
  122. return S_ISLNK(stat.st_mode);
  123. }
  124. DeprecatedString DeprecatedFile::real_path_for(DeprecatedString const& filename)
  125. {
  126. if (filename.is_null())
  127. return {};
  128. auto* path = realpath(filename.characters(), nullptr);
  129. DeprecatedString real_path(path);
  130. free(path);
  131. return real_path;
  132. }
  133. DeprecatedString DeprecatedFile::current_working_directory()
  134. {
  135. char* cwd = getcwd(nullptr, 0);
  136. if (!cwd) {
  137. perror("getcwd");
  138. return {};
  139. }
  140. auto cwd_as_string = DeprecatedString(cwd);
  141. free(cwd);
  142. return cwd_as_string;
  143. }
  144. DeprecatedString DeprecatedFile::absolute_path(DeprecatedString const& path)
  145. {
  146. if (!Core::System::stat(path).is_error())
  147. return DeprecatedFile::real_path_for(path);
  148. if (path.starts_with("/"sv))
  149. return LexicalPath::canonicalized_path(path);
  150. auto working_directory = DeprecatedFile::current_working_directory();
  151. auto full_path = LexicalPath::join(working_directory, path);
  152. return LexicalPath::canonicalized_path(full_path.string());
  153. }
  154. Optional<DeprecatedString> DeprecatedFile::resolve_executable_from_environment(StringView filename)
  155. {
  156. if (filename.is_empty())
  157. return {};
  158. // Paths that aren't just a file name generally count as already resolved.
  159. if (filename.contains('/')) {
  160. if (access(DeprecatedString { filename }.characters(), X_OK) != 0)
  161. return {};
  162. return filename;
  163. }
  164. auto const* path_str = getenv("PATH");
  165. StringView path;
  166. if (path_str)
  167. path = { path_str, strlen(path_str) };
  168. if (path.is_empty())
  169. path = DEFAULT_PATH_SV;
  170. auto directories = path.split_view(':');
  171. for (auto directory : directories) {
  172. auto file = DeprecatedString::formatted("{}/{}", directory, filename);
  173. if (access(file.characters(), X_OK) == 0)
  174. return file;
  175. }
  176. return {};
  177. };
  178. }