[Telemetry] Fix 'important' field of certain Values being non-boolean
[chromium-blink-merge.git] / storage / browser / fileapi / native_file_util.cc
blob3722913fe64af80ac3577f9044d418c02947ad52
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.
5 #include "storage/browser/fileapi/native_file_util.h"
7 #include "base/files/file.h"
8 #include "base/files/file_enumerator.h"
9 #include "base/files/file_util.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "storage/browser/fileapi/file_system_operation_context.h"
12 #include "storage/browser/fileapi/file_system_url.h"
13 #include "storage/common/fileapi/file_system_mount_option.h"
15 namespace storage {
17 namespace {
19 // Sets permissions on directory at |dir_path| based on the target platform.
20 // Returns true on success, or false otherwise.
22 // TODO(benchan): Find a better place outside webkit to host this function.
23 bool SetPlatformSpecificDirectoryPermissions(const base::FilePath& dir_path) {
24 #if defined(OS_CHROMEOS)
25 // System daemons on Chrome OS may run as a user different than the Chrome
26 // process but need to access files under the directories created here.
27 // Because of that, grant the execute permission on the created directory
28 // to group and other users.
29 if (HANDLE_EINTR(chmod(dir_path.value().c_str(),
30 S_IRWXU | S_IXGRP | S_IXOTH)) != 0) {
31 return false;
33 #endif
34 // Keep the directory permissions unchanged on non-Chrome OS platforms.
35 return true;
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;
46 base::File outfile(to,
47 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
48 if (!outfile.IsValid()) {
49 return false;
52 const int kBufferSize = 32768;
53 std::vector<char> buffer(kBufferSize);
55 for (;;) {
56 int bytes_read = infile.ReadAtCurrentPos(&buffer[0], kBufferSize);
57 if (bytes_read < 0)
58 return false;
59 if (bytes_read == 0)
60 break;
61 for (int bytes_written = 0; bytes_written < bytes_read; ) {
62 int bytes_written_partial = outfile.WriteAtCurrentPos(
63 &buffer[bytes_written], bytes_read - bytes_written);
64 if (bytes_written_partial < 0)
65 return false;
66 bytes_written += bytes_written_partial;
70 return outfile.Flush();
73 } // namespace
75 using base::PlatformFile;
77 class NativeFileEnumerator : public FileSystemFileUtil::AbstractFileEnumerator {
78 public:
79 NativeFileEnumerator(const base::FilePath& root_path,
80 bool recursive,
81 int file_type)
82 : file_enum_(root_path, recursive, file_type) {
85 ~NativeFileEnumerator() override {}
87 base::FilePath Next() override;
88 int64 Size() override;
89 base::Time LastModifiedTime() override;
90 bool IsDirectory() override;
92 private:
93 base::FileEnumerator file_enum_;
94 base::FileEnumerator::FileInfo file_util_info_;
97 base::FilePath NativeFileEnumerator::Next() {
98 base::FilePath rv = file_enum_.Next();
99 if (!rv.empty())
100 file_util_info_ = file_enum_.GetInfo();
101 return rv;
104 int64 NativeFileEnumerator::Size() {
105 return file_util_info_.GetSize();
108 base::Time NativeFileEnumerator::LastModifiedTime() {
109 return file_util_info_.GetLastModifiedTime();
112 bool NativeFileEnumerator::IsDirectory() {
113 return file_util_info_.IsDirectory();
116 NativeFileUtil::CopyOrMoveMode NativeFileUtil::CopyOrMoveModeForDestination(
117 const FileSystemURL& dest_url, bool copy) {
118 if (copy) {
119 return dest_url.mount_option().flush_policy() ==
120 FlushPolicy::FLUSH_ON_COMPLETION
121 ? COPY_SYNC
122 : COPY_NOSYNC;
124 return MOVE;
127 base::File NativeFileUtil::CreateOrOpen(const base::FilePath& path,
128 int file_flags) {
129 if (!base::DirectoryExists(path.DirName())) {
130 // If its parent does not exist, should return NOT_FOUND error.
131 return base::File(base::File::FILE_ERROR_NOT_FOUND);
134 // TODO(rvargas): Check |file_flags| instead. See bug 356358.
135 if (base::DirectoryExists(path))
136 return base::File(base::File::FILE_ERROR_NOT_A_FILE);
138 return base::File(path, file_flags);
141 base::File::Error NativeFileUtil::EnsureFileExists(
142 const base::FilePath& path,
143 bool* created) {
144 if (!base::DirectoryExists(path.DirName()))
145 // If its parent does not exist, should return NOT_FOUND error.
146 return base::File::FILE_ERROR_NOT_FOUND;
148 // Tries to create the |path| exclusively. This should fail
149 // with base::File::FILE_ERROR_EXISTS if the path already exists.
150 base::File file(path, base::File::FLAG_CREATE | base::File::FLAG_READ);
152 if (file.IsValid()) {
153 if (created)
154 *created = file.created();
155 return base::File::FILE_OK;
158 base::File::Error error_code = file.error_details();
159 if (error_code == base::File::FILE_ERROR_EXISTS) {
160 // Make sure created_ is false.
161 if (created)
162 *created = false;
163 error_code = base::File::FILE_OK;
165 return error_code;
168 base::File::Error NativeFileUtil::CreateDirectory(
169 const base::FilePath& path,
170 bool exclusive,
171 bool recursive) {
172 // If parent dir of file doesn't exist.
173 if (!recursive && !base::PathExists(path.DirName()))
174 return base::File::FILE_ERROR_NOT_FOUND;
176 bool path_exists = base::PathExists(path);
177 if (exclusive && path_exists)
178 return base::File::FILE_ERROR_EXISTS;
180 // If file exists at the path.
181 if (path_exists && !base::DirectoryExists(path))
182 return base::File::FILE_ERROR_EXISTS;
184 if (!base::CreateDirectory(path))
185 return base::File::FILE_ERROR_FAILED;
187 if (!SetPlatformSpecificDirectoryPermissions(path)) {
188 // Since some file systems don't support permission setting, we do not treat
189 // an error from the function as the failure of copying. Just log it.
190 LOG(WARNING) << "Setting directory permission failed: "
191 << path.AsUTF8Unsafe();
194 return base::File::FILE_OK;
197 base::File::Error NativeFileUtil::GetFileInfo(
198 const base::FilePath& path,
199 base::File::Info* file_info) {
200 if (!base::PathExists(path))
201 return base::File::FILE_ERROR_NOT_FOUND;
203 if (!base::GetFileInfo(path, file_info))
204 return base::File::FILE_ERROR_FAILED;
205 return base::File::FILE_OK;
208 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator>
209 NativeFileUtil::CreateFileEnumerator(const base::FilePath& root_path,
210 bool recursive) {
211 return make_scoped_ptr(new NativeFileEnumerator(
212 root_path,
213 recursive,
214 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES));
217 base::File::Error NativeFileUtil::Touch(
218 const base::FilePath& path,
219 const base::Time& last_access_time,
220 const base::Time& last_modified_time) {
221 if (!base::TouchFile(path, last_access_time, last_modified_time))
222 return base::File::FILE_ERROR_FAILED;
223 return base::File::FILE_OK;
226 base::File::Error NativeFileUtil::Truncate(const base::FilePath& path,
227 int64 length) {
228 base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_WRITE);
229 if (!file.IsValid())
230 return file.error_details();
232 if (!file.SetLength(length))
233 return base::File::FILE_ERROR_FAILED;
235 return base::File::FILE_OK;
238 bool NativeFileUtil::PathExists(const base::FilePath& path) {
239 return base::PathExists(path);
242 bool NativeFileUtil::DirectoryExists(const base::FilePath& path) {
243 return base::DirectoryExists(path);
246 base::File::Error NativeFileUtil::CopyOrMoveFile(
247 const base::FilePath& src_path,
248 const base::FilePath& dest_path,
249 FileSystemOperation::CopyOrMoveOption option,
250 CopyOrMoveMode mode) {
251 base::File::Info info;
252 base::File::Error error = NativeFileUtil::GetFileInfo(src_path, &info);
253 if (error != base::File::FILE_OK)
254 return error;
255 if (info.is_directory)
256 return base::File::FILE_ERROR_NOT_A_FILE;
257 base::Time last_modified = info.last_modified;
259 error = NativeFileUtil::GetFileInfo(dest_path, &info);
260 if (error != base::File::FILE_OK &&
261 error != base::File::FILE_ERROR_NOT_FOUND)
262 return error;
263 if (info.is_directory)
264 return base::File::FILE_ERROR_INVALID_OPERATION;
265 if (error == base::File::FILE_ERROR_NOT_FOUND) {
266 error = NativeFileUtil::GetFileInfo(dest_path.DirName(), &info);
267 if (error != base::File::FILE_OK)
268 return error;
269 if (!info.is_directory)
270 return base::File::FILE_ERROR_NOT_FOUND;
273 switch (mode) {
274 case COPY_NOSYNC:
275 if (!base::CopyFile(src_path, dest_path))
276 return base::File::FILE_ERROR_FAILED;
277 break;
278 case COPY_SYNC:
279 if (!CopyFileAndSync(src_path, dest_path))
280 return base::File::FILE_ERROR_FAILED;
281 break;
282 case MOVE:
283 if (!base::Move(src_path, dest_path))
284 return base::File::FILE_ERROR_FAILED;
285 break;
288 // Preserve the last modified time. Do not return error here even if
289 // the setting is failed, because the copy itself is successfully done.
290 if (option == FileSystemOperation::OPTION_PRESERVE_LAST_MODIFIED)
291 base::TouchFile(dest_path, last_modified, last_modified);
293 return base::File::FILE_OK;
296 base::File::Error NativeFileUtil::DeleteFile(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_FILE;
301 if (!base::DeleteFile(path, false))
302 return base::File::FILE_ERROR_FAILED;
303 return base::File::FILE_OK;
306 base::File::Error NativeFileUtil::DeleteDirectory(const base::FilePath& path) {
307 if (!base::PathExists(path))
308 return base::File::FILE_ERROR_NOT_FOUND;
309 if (!base::DirectoryExists(path))
310 return base::File::FILE_ERROR_NOT_A_DIRECTORY;
311 if (!base::IsDirectoryEmpty(path))
312 return base::File::FILE_ERROR_NOT_EMPTY;
313 if (!base::DeleteFile(path, false))
314 return base::File::FILE_ERROR_FAILED;
315 return base::File::FILE_OK;
318 } // namespace storage