native_file_util.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. // Copyright (c) 2012 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 "storage/browser/file_system/native_file_util.h"
  5. #include <stdint.h>
  6. #include <memory>
  7. #include "base/files/file_enumerator.h"
  8. #include "base/files/file_util.h"
  9. #include "base/time/time.h"
  10. #include "build/build_config.h"
  11. #include "build/chromeos_buildflags.h"
  12. #include "storage/browser/file_system/file_system_operation_context.h"
  13. #include "storage/browser/file_system/file_system_url.h"
  14. #include "storage/common/file_system/file_system_mount_option.h"
  15. #if BUILDFLAG(IS_WIN)
  16. #include "windows.h"
  17. #endif // BUILDFLAG(IS_WIN)
  18. namespace storage {
  19. namespace {
  20. // Sets permissions on directory at |dir_path| based on the target platform.
  21. // Returns true on success, or false otherwise.
  22. //
  23. // TODO(benchan): Find a better place outside webkit to host this function.
  24. bool SetPlatformSpecificDirectoryPermissions(const base::FilePath& dir_path) {
  25. #if BUILDFLAG(IS_CHROMEOS_ASH)
  26. // System daemons on Chrome OS may run as a user different than the Chrome
  27. // process but need to access files under the directories created here.
  28. // Because of that, grant the execute permission on the created directory
  29. // to group and other users.
  30. if (HANDLE_EINTR(
  31. chmod(dir_path.value().c_str(), S_IRWXU | S_IXGRP | S_IXOTH)) != 0) {
  32. return false;
  33. }
  34. #endif
  35. // Keep the directory permissions unchanged on non-Chrome OS platforms.
  36. return true;
  37. }
  38. // Copies a file |from| to |to|, and ensure the written content is synced to
  39. // the disk. This is essentially base::CopyFile followed by fsync().
  40. bool CopyFileAndSync(const base::FilePath& from, const base::FilePath& to) {
  41. base::File infile(from, base::File::FLAG_OPEN | base::File::FLAG_READ);
  42. if (!infile.IsValid()) {
  43. return false;
  44. }
  45. base::File outfile(to,
  46. base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
  47. if (!outfile.IsValid()) {
  48. return false;
  49. }
  50. const int kBufferSize = 32768;
  51. std::vector<char> buffer(kBufferSize);
  52. for (;;) {
  53. int bytes_read = infile.ReadAtCurrentPos(&buffer[0], kBufferSize);
  54. if (bytes_read < 0)
  55. return false;
  56. if (bytes_read == 0)
  57. break;
  58. for (int bytes_written = 0; bytes_written < bytes_read;) {
  59. int bytes_written_partial = outfile.WriteAtCurrentPos(
  60. &buffer[bytes_written], bytes_read - bytes_written);
  61. if (bytes_written_partial < 0)
  62. return false;
  63. bytes_written += bytes_written_partial;
  64. }
  65. }
  66. return outfile.Flush();
  67. }
  68. } // namespace
  69. using base::PlatformFile;
  70. class NativeFileEnumerator : public FileSystemFileUtil::AbstractFileEnumerator {
  71. public:
  72. NativeFileEnumerator(const base::FilePath& root_path,
  73. bool recursive,
  74. int file_type)
  75. : file_enum_(root_path, recursive, file_type) {}
  76. ~NativeFileEnumerator() override = default;
  77. base::FilePath Next() override;
  78. int64_t Size() override;
  79. base::Time LastModifiedTime() override;
  80. bool IsDirectory() override;
  81. private:
  82. base::FileEnumerator file_enum_;
  83. base::FileEnumerator::FileInfo file_util_info_;
  84. };
  85. base::FilePath NativeFileEnumerator::Next() {
  86. base::FilePath rv = file_enum_.Next();
  87. if (!rv.empty())
  88. file_util_info_ = file_enum_.GetInfo();
  89. return rv;
  90. }
  91. int64_t NativeFileEnumerator::Size() {
  92. return file_util_info_.GetSize();
  93. }
  94. base::Time NativeFileEnumerator::LastModifiedTime() {
  95. return file_util_info_.GetLastModifiedTime();
  96. }
  97. bool NativeFileEnumerator::IsDirectory() {
  98. return file_util_info_.IsDirectory();
  99. }
  100. NativeFileUtil::CopyOrMoveMode NativeFileUtil::CopyOrMoveModeForDestination(
  101. const FileSystemURL& dest_url,
  102. bool copy) {
  103. if (copy) {
  104. return dest_url.mount_option().flush_policy() ==
  105. FlushPolicy::FLUSH_ON_COMPLETION
  106. ? COPY_SYNC
  107. : COPY_NOSYNC;
  108. }
  109. return MOVE;
  110. }
  111. base::File NativeFileUtil::CreateOrOpen(const base::FilePath& path,
  112. uint32_t file_flags) {
  113. if (!base::DirectoryExists(path.DirName())) {
  114. // If its parent does not exist, should return NOT_FOUND error.
  115. return base::File(base::File::FILE_ERROR_NOT_FOUND);
  116. }
  117. // TODO(rvargas): Check |file_flags| instead. See bug 356358.
  118. if (base::DirectoryExists(path))
  119. return base::File(base::File::FILE_ERROR_NOT_A_FILE);
  120. return base::File(path, file_flags);
  121. }
  122. base::File::Error NativeFileUtil::EnsureFileExists(const base::FilePath& path,
  123. bool* created) {
  124. if (!base::DirectoryExists(path.DirName()))
  125. // If its parent does not exist, should return NOT_FOUND error.
  126. return base::File::FILE_ERROR_NOT_FOUND;
  127. // If |path| is a directory, return an error.
  128. if (base::DirectoryExists(path))
  129. return base::File::FILE_ERROR_NOT_A_FILE;
  130. // Tries to create the |path| exclusively. This should fail
  131. // with base::File::FILE_ERROR_EXISTS if the path already exists.
  132. base::File file(path, base::File::FLAG_CREATE | base::File::FLAG_READ);
  133. if (file.IsValid()) {
  134. if (created)
  135. *created = file.created();
  136. return base::File::FILE_OK;
  137. }
  138. base::File::Error error_code = file.error_details();
  139. if (error_code == base::File::FILE_ERROR_EXISTS) {
  140. // Make sure created_ is false.
  141. if (created)
  142. *created = false;
  143. error_code = base::File::FILE_OK;
  144. }
  145. return error_code;
  146. }
  147. base::File::Error NativeFileUtil::CreateDirectory(const base::FilePath& path,
  148. bool exclusive,
  149. bool recursive) {
  150. // If parent dir of file doesn't exist.
  151. if (!recursive && !base::PathExists(path.DirName()))
  152. return base::File::FILE_ERROR_NOT_FOUND;
  153. bool path_exists = base::PathExists(path);
  154. if (exclusive && path_exists)
  155. return base::File::FILE_ERROR_EXISTS;
  156. // If file exists at the path.
  157. if (path_exists && !base::DirectoryExists(path))
  158. return base::File::FILE_ERROR_NOT_A_DIRECTORY;
  159. if (!base::CreateDirectory(path))
  160. return base::File::FILE_ERROR_FAILED;
  161. if (!SetPlatformSpecificDirectoryPermissions(path)) {
  162. // Since some file systems don't support permission setting, we do not treat
  163. // an error from the function as the failure of copying. Just log it.
  164. LOG(WARNING) << "Setting directory permission failed: "
  165. << path.AsUTF8Unsafe();
  166. }
  167. return base::File::FILE_OK;
  168. }
  169. base::File::Error NativeFileUtil::GetFileInfo(const base::FilePath& path,
  170. base::File::Info* file_info) {
  171. if (!base::PathExists(path))
  172. return base::File::FILE_ERROR_NOT_FOUND;
  173. if (!base::GetFileInfo(path, file_info))
  174. return base::File::FILE_ERROR_FAILED;
  175. return base::File::FILE_OK;
  176. }
  177. std::unique_ptr<FileSystemFileUtil::AbstractFileEnumerator>
  178. NativeFileUtil::CreateFileEnumerator(const base::FilePath& root_path,
  179. bool recursive) {
  180. return std::make_unique<NativeFileEnumerator>(
  181. root_path, recursive,
  182. base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
  183. }
  184. base::File::Error NativeFileUtil::Touch(const base::FilePath& path,
  185. const base::Time& last_access_time,
  186. const base::Time& last_modified_time) {
  187. if (!base::TouchFile(path, last_access_time, last_modified_time))
  188. return base::File::FILE_ERROR_FAILED;
  189. return base::File::FILE_OK;
  190. }
  191. base::File::Error NativeFileUtil::Truncate(const base::FilePath& path,
  192. int64_t length) {
  193. base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_WRITE);
  194. if (!file.IsValid())
  195. return file.error_details();
  196. if (!file.SetLength(length))
  197. return base::File::FILE_ERROR_FAILED;
  198. return base::File::FILE_OK;
  199. }
  200. bool NativeFileUtil::PathExists(const base::FilePath& path) {
  201. return base::PathExists(path);
  202. }
  203. bool NativeFileUtil::DirectoryExists(const base::FilePath& path) {
  204. return base::DirectoryExists(path);
  205. }
  206. base::File::Error NativeFileUtil::CopyOrMoveFile(
  207. const base::FilePath& src_path,
  208. const base::FilePath& dest_path,
  209. FileSystemOperation::CopyOrMoveOptionSet options,
  210. CopyOrMoveMode mode) {
  211. base::File::Info info;
  212. base::File::Error error = NativeFileUtil::GetFileInfo(src_path, &info);
  213. if (error != base::File::FILE_OK)
  214. return error;
  215. if (info.is_directory && mode != MOVE)
  216. return base::File::FILE_ERROR_NOT_A_FILE;
  217. bool src_is_directory = info.is_directory;
  218. base::Time last_modified = info.last_modified;
  219. error = NativeFileUtil::GetFileInfo(dest_path, &info);
  220. if (error != base::File::FILE_OK && error != base::File::FILE_ERROR_NOT_FOUND)
  221. return error;
  222. if (error == base::File::FILE_OK) {
  223. if (info.is_directory != src_is_directory)
  224. return base::File::FILE_ERROR_INVALID_OPERATION;
  225. #if BUILDFLAG(IS_WIN)
  226. // Overwriting an empty directory with another directory isn't supported
  227. // natively on Windows, so treat this an unsupported. A higher layer is
  228. // responsible for handling it.
  229. if (info.is_directory)
  230. return base::File::FILE_ERROR_NOT_A_FILE;
  231. #endif
  232. }
  233. if (error == base::File::FILE_ERROR_NOT_FOUND) {
  234. error = NativeFileUtil::GetFileInfo(dest_path.DirName(), &info);
  235. if (error != base::File::FILE_OK)
  236. return error;
  237. if (!info.is_directory)
  238. return base::File::FILE_ERROR_NOT_FOUND;
  239. }
  240. // Cache permissions of dest file before copy/move overwrites the file.
  241. bool should_retain_file_permissions = false;
  242. #if BUILDFLAG(IS_POSIX)
  243. int dest_mode;
  244. if (options.Has(FileSystemOperation::CopyOrMoveOption::
  245. kPreserveDestinationPermissions)) {
  246. // Will be false if the destination file doesn't exist.
  247. should_retain_file_permissions =
  248. base::GetPosixFilePermissions(dest_path, &dest_mode);
  249. }
  250. #elif BUILDFLAG(IS_WIN)
  251. DWORD dest_attributes;
  252. if (options.Has(FileSystemOperation::CopyOrMoveOption::
  253. kPreserveDestinationPermissions)) {
  254. dest_attributes = ::GetFileAttributes(dest_path.value().c_str());
  255. should_retain_file_permissions = dest_attributes != INVALID_FILE_ATTRIBUTES;
  256. }
  257. #endif // BUILDFLAG(IS_POSIX)
  258. switch (mode) {
  259. case COPY_NOSYNC:
  260. if (!base::CopyFile(src_path, dest_path))
  261. return base::File::FILE_ERROR_FAILED;
  262. break;
  263. case COPY_SYNC:
  264. if (!CopyFileAndSync(src_path, dest_path))
  265. return base::File::FILE_ERROR_FAILED;
  266. break;
  267. case MOVE:
  268. if (!base::Move(src_path, dest_path))
  269. return base::File::FILE_ERROR_FAILED;
  270. break;
  271. }
  272. // Preserve the last modified time. Do not return error here even if
  273. // the setting is failed, because the copy itself is successfully done.
  274. if (options.Has(
  275. FileSystemOperation::CopyOrMoveOption::kPreserveLastModified)) {
  276. base::TouchFile(dest_path, last_modified, last_modified);
  277. }
  278. if (should_retain_file_permissions) {
  279. #if BUILDFLAG(IS_POSIX)
  280. base::SetPosixFilePermissions(dest_path, dest_mode);
  281. #elif BUILDFLAG(IS_WIN)
  282. ::SetFileAttributes(dest_path.value().c_str(), dest_attributes);
  283. #endif // BUILDFLAG(IS_POSIX)
  284. }
  285. return base::File::FILE_OK;
  286. }
  287. base::File::Error NativeFileUtil::DeleteFile(const base::FilePath& path) {
  288. if (!base::PathExists(path))
  289. return base::File::FILE_ERROR_NOT_FOUND;
  290. if (base::DirectoryExists(path))
  291. return base::File::FILE_ERROR_NOT_A_FILE;
  292. if (!base::DeleteFile(path))
  293. return base::File::FILE_ERROR_FAILED;
  294. return base::File::FILE_OK;
  295. }
  296. base::File::Error NativeFileUtil::DeleteDirectory(const base::FilePath& path) {
  297. if (!base::PathExists(path))
  298. return base::File::FILE_ERROR_NOT_FOUND;
  299. if (!base::DirectoryExists(path))
  300. return base::File::FILE_ERROR_NOT_A_DIRECTORY;
  301. if (!base::IsDirectoryEmpty(path))
  302. return base::File::FILE_ERROR_NOT_EMPTY;
  303. if (!base::DeleteFile(path))
  304. return base::File::FILE_ERROR_FAILED;
  305. return base::File::FILE_OK;
  306. }
  307. } // namespace storage