directory_impl.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. // Copyright 2015 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/services/filesystem/directory_impl.h"
  5. #include <memory>
  6. #include <string>
  7. #include <utility>
  8. #include <vector>
  9. #include "base/files/file.h"
  10. #include "base/files/file_enumerator.h"
  11. #include "base/files/file_util.h"
  12. #include "base/files/scoped_temp_dir.h"
  13. #include "build/build_config.h"
  14. #include "components/services/filesystem/util.h"
  15. #include "mojo/public/cpp/bindings/self_owned_receiver.h"
  16. namespace filesystem {
  17. DirectoryImpl::DirectoryImpl(base::FilePath directory_path,
  18. scoped_refptr<SharedTempDir> temp_dir)
  19. : directory_path_(directory_path), temp_dir_(std::move(temp_dir)) {}
  20. DirectoryImpl::~DirectoryImpl() {}
  21. void DirectoryImpl::Read(ReadCallback callback) {
  22. std::vector<mojom::DirectoryEntryPtr> entries;
  23. base::FileEnumerator directory_enumerator(
  24. directory_path_, false,
  25. base::FileEnumerator::DIRECTORIES | base::FileEnumerator::FILES);
  26. for (base::FilePath name = directory_enumerator.Next(); !name.empty();
  27. name = directory_enumerator.Next()) {
  28. base::FileEnumerator::FileInfo info = directory_enumerator.GetInfo();
  29. mojom::DirectoryEntryPtr entry = mojom::DirectoryEntry::New();
  30. entry->type = info.IsDirectory() ? mojom::FsFileType::DIRECTORY
  31. : mojom::FsFileType::REGULAR_FILE;
  32. entry->name = info.GetName();
  33. entries.push_back(std::move(entry));
  34. }
  35. std::move(callback).Run(base::File::Error::FILE_OK,
  36. entries.empty()
  37. ? absl::nullopt
  38. : absl::make_optional(std::move(entries)));
  39. }
  40. // TODO(erg): Consider adding an implementation of Stat()/Touch() to the
  41. // directory, too. Right now, the base::File abstractions do not really deal
  42. // with directories properly, so these are broken for now.
  43. void DirectoryImpl::OpenFileHandle(const std::string& raw_path,
  44. uint32_t open_flags,
  45. OpenFileHandleCallback callback) {
  46. base::File file = OpenFileHandleImpl(raw_path, open_flags);
  47. base::File::Error error = GetError(file);
  48. std::move(callback).Run(error, std::move(file));
  49. }
  50. void DirectoryImpl::OpenFileHandles(
  51. std::vector<mojom::FileOpenDetailsPtr> details,
  52. OpenFileHandlesCallback callback) {
  53. std::vector<mojom::FileOpenResultPtr> results(details.size());
  54. size_t i = 0;
  55. for (const auto& detail : details) {
  56. mojom::FileOpenResultPtr result(mojom::FileOpenResult::New());
  57. result->path = detail->path;
  58. result->file_handle = OpenFileHandleImpl(detail->path, detail->open_flags);
  59. result->error = GetError(result->file_handle);
  60. results[i++] = std::move(result);
  61. }
  62. std::move(callback).Run(std::move(results));
  63. }
  64. void DirectoryImpl::OpenDirectory(
  65. const std::string& raw_path,
  66. mojo::PendingReceiver<mojom::Directory> receiver,
  67. uint32_t open_flags,
  68. OpenDirectoryCallback callback) {
  69. base::FilePath path;
  70. base::File::Error error = ValidatePath(raw_path, directory_path_, &path);
  71. if (error != base::File::Error::FILE_OK) {
  72. std::move(callback).Run(error);
  73. return;
  74. }
  75. if (!base::DirectoryExists(path)) {
  76. if (base::PathExists(path)) {
  77. std::move(callback).Run(base::File::Error::FILE_ERROR_NOT_A_DIRECTORY);
  78. return;
  79. }
  80. if (!(open_flags & mojom::kFlagOpenAlways ||
  81. open_flags & mojom::kFlagCreate)) {
  82. // The directory doesn't exist, and we weren't passed parameters to
  83. // create it.
  84. std::move(callback).Run(base::File::Error::FILE_ERROR_NOT_FOUND);
  85. return;
  86. }
  87. if (!base::CreateDirectoryAndGetError(path, &error)) {
  88. std::move(callback).Run(error);
  89. return;
  90. }
  91. }
  92. if (receiver) {
  93. mojo::MakeSelfOwnedReceiver(
  94. std::make_unique<DirectoryImpl>(path, temp_dir_), std::move(receiver));
  95. }
  96. std::move(callback).Run(base::File::Error::FILE_OK);
  97. }
  98. void DirectoryImpl::Rename(const std::string& raw_old_path,
  99. const std::string& raw_new_path,
  100. RenameCallback callback) {
  101. base::FilePath old_path;
  102. base::File::Error error =
  103. ValidatePath(raw_old_path, directory_path_, &old_path);
  104. if (error != base::File::Error::FILE_OK) {
  105. std::move(callback).Run(error);
  106. return;
  107. }
  108. base::FilePath new_path;
  109. error = ValidatePath(raw_new_path, directory_path_, &new_path);
  110. if (error != base::File::Error::FILE_OK) {
  111. std::move(callback).Run(error);
  112. return;
  113. }
  114. if (!base::Move(old_path, new_path)) {
  115. std::move(callback).Run(base::File::Error::FILE_ERROR_FAILED);
  116. return;
  117. }
  118. std::move(callback).Run(base::File::Error::FILE_OK);
  119. }
  120. void DirectoryImpl::Replace(const std::string& raw_old_path,
  121. const std::string& raw_new_path,
  122. ReplaceCallback callback) {
  123. base::FilePath old_path;
  124. base::File::Error error =
  125. ValidatePath(raw_old_path, directory_path_, &old_path);
  126. if (error != base::File::Error::FILE_OK) {
  127. std::move(callback).Run(error);
  128. return;
  129. }
  130. base::FilePath new_path;
  131. error = ValidatePath(raw_new_path, directory_path_, &new_path);
  132. if (error != base::File::Error::FILE_OK) {
  133. std::move(callback).Run(error);
  134. return;
  135. }
  136. base::File::Error file_error;
  137. if (!base::ReplaceFile(old_path, new_path, &file_error)) {
  138. std::move(callback).Run(file_error);
  139. return;
  140. }
  141. std::move(callback).Run(base::File::Error::FILE_OK);
  142. }
  143. void DirectoryImpl::Delete(const std::string& raw_path,
  144. uint32_t delete_flags,
  145. DeleteCallback callback) {
  146. base::FilePath path;
  147. base::File::Error error = ValidatePath(raw_path, directory_path_, &path);
  148. if (error != base::File::Error::FILE_OK) {
  149. std::move(callback).Run(error);
  150. return;
  151. }
  152. bool success;
  153. if (delete_flags & mojom::kDeleteFlagRecursive)
  154. success = base::DeletePathRecursively(path);
  155. else
  156. success = base::DeleteFile(path);
  157. if (!success) {
  158. std::move(callback).Run(base::File::Error::FILE_ERROR_FAILED);
  159. return;
  160. }
  161. std::move(callback).Run(base::File::Error::FILE_OK);
  162. }
  163. void DirectoryImpl::Exists(const std::string& raw_path,
  164. ExistsCallback callback) {
  165. base::FilePath path;
  166. base::File::Error error = ValidatePath(raw_path, directory_path_, &path);
  167. if (error != base::File::Error::FILE_OK) {
  168. std::move(callback).Run(error, false);
  169. return;
  170. }
  171. bool exists = base::PathExists(path);
  172. std::move(callback).Run(base::File::Error::FILE_OK, exists);
  173. }
  174. void DirectoryImpl::IsWritable(const std::string& raw_path,
  175. IsWritableCallback callback) {
  176. base::FilePath path;
  177. base::File::Error error = ValidatePath(raw_path, directory_path_, &path);
  178. if (error != base::File::Error::FILE_OK) {
  179. std::move(callback).Run(error, false);
  180. return;
  181. }
  182. std::move(callback).Run(base::File::Error::FILE_OK,
  183. base::PathIsWritable(path));
  184. }
  185. void DirectoryImpl::Flush(FlushCallback callback) {
  186. // On Windows no need to sync directories. Their metadata will be updated when
  187. // files are created, without an explicit sync.
  188. #if !BUILDFLAG(IS_WIN)
  189. base::File file(directory_path_,
  190. base::File::FLAG_OPEN | base::File::FLAG_READ);
  191. if (!file.IsValid()) {
  192. std::move(callback).Run(GetError(file));
  193. return;
  194. }
  195. if (!file.Flush()) {
  196. std::move(callback).Run(base::File::Error::FILE_ERROR_FAILED);
  197. return;
  198. }
  199. #endif
  200. std::move(callback).Run(base::File::Error::FILE_OK);
  201. }
  202. void DirectoryImpl::StatFile(const std::string& raw_path,
  203. StatFileCallback callback) {
  204. base::FilePath path;
  205. base::File::Error error = ValidatePath(raw_path, directory_path_, &path);
  206. if (error != base::File::Error::FILE_OK) {
  207. std::move(callback).Run(error, nullptr);
  208. return;
  209. }
  210. base::File base_file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
  211. if (!base_file.IsValid()) {
  212. std::move(callback).Run(GetError(base_file), nullptr);
  213. return;
  214. }
  215. base::File::Info info;
  216. if (!base_file.GetInfo(&info)) {
  217. std::move(callback).Run(base::File::Error::FILE_ERROR_FAILED, nullptr);
  218. return;
  219. }
  220. std::move(callback).Run(base::File::Error::FILE_OK,
  221. MakeFileInformation(info));
  222. }
  223. void DirectoryImpl::Clone(mojo::PendingReceiver<mojom::Directory> receiver) {
  224. mojo::MakeSelfOwnedReceiver(
  225. std::make_unique<DirectoryImpl>(directory_path_, temp_dir_),
  226. std::move(receiver));
  227. }
  228. void DirectoryImpl::ReadEntireFile(const std::string& raw_path,
  229. ReadEntireFileCallback callback) {
  230. base::FilePath path;
  231. base::File::Error error = ValidatePath(raw_path, directory_path_, &path);
  232. if (error != base::File::Error::FILE_OK) {
  233. std::move(callback).Run(error, std::vector<uint8_t>());
  234. return;
  235. }
  236. if (base::DirectoryExists(path)) {
  237. std::move(callback).Run(base::File::Error::FILE_ERROR_NOT_A_FILE,
  238. std::vector<uint8_t>());
  239. return;
  240. }
  241. base::File base_file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
  242. if (!base_file.IsValid()) {
  243. std::move(callback).Run(GetError(base_file), std::vector<uint8_t>());
  244. return;
  245. }
  246. std::vector<uint8_t> contents;
  247. const int kBufferSize = 1 << 16;
  248. std::unique_ptr<char[]> buf(new char[kBufferSize]);
  249. int len;
  250. while ((len = base_file.ReadAtCurrentPos(buf.get(), kBufferSize)) > 0)
  251. contents.insert(contents.end(), buf.get(), buf.get() + len);
  252. std::move(callback).Run(base::File::Error::FILE_OK, contents);
  253. }
  254. void DirectoryImpl::WriteFile(const std::string& raw_path,
  255. const std::vector<uint8_t>& data,
  256. WriteFileCallback callback) {
  257. base::FilePath path;
  258. base::File::Error error = ValidatePath(raw_path, directory_path_, &path);
  259. if (error != base::File::Error::FILE_OK) {
  260. std::move(callback).Run(error);
  261. return;
  262. }
  263. if (base::DirectoryExists(path)) {
  264. std::move(callback).Run(base::File::Error::FILE_ERROR_NOT_A_FILE);
  265. return;
  266. }
  267. base::File base_file(path,
  268. base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
  269. if (!base_file.IsValid()) {
  270. std::move(callback).Run(GetError(base_file));
  271. return;
  272. }
  273. // If we're given empty data, we don't write and just truncate the file.
  274. if (data.size()) {
  275. const int data_size = static_cast<int>(data.size());
  276. if (base_file.Write(0, reinterpret_cast<const char*>(&data.front()),
  277. data_size) == -1) {
  278. std::move(callback).Run(GetError(base_file));
  279. return;
  280. }
  281. }
  282. std::move(callback).Run(base::File::Error::FILE_OK);
  283. }
  284. base::File DirectoryImpl::OpenFileHandleImpl(const std::string& raw_path,
  285. uint32_t open_flags) {
  286. base::FilePath path;
  287. base::File::Error error = ValidatePath(raw_path, directory_path_, &path);
  288. if (error != base::File::Error::FILE_OK)
  289. return base::File(static_cast<base::File::Error>(error));
  290. if (base::DirectoryExists(path)) {
  291. // We must not return directories as files. In the file abstraction, we
  292. // can fetch raw file descriptors over mojo pipes, and passing a file
  293. // descriptor to a directory is a sandbox escape on Windows.
  294. return base::File(base::File::FILE_ERROR_NOT_A_FILE);
  295. }
  296. return base::File(path, open_flags);
  297. }
  298. } // namespace filesystem