Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / components / filesystem / directory_impl.cc
blob3d63f0e147e847ec80b237110f6e82087a25b445
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.
5 #include "components/filesystem/directory_impl.h"
7 #include "base/files/file.h"
8 #include "base/files/file_enumerator.h"
9 #include "base/files/file_util.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "build/build_config.h"
14 #include "components/filesystem/file_impl.h"
15 #include "components/filesystem/util.h"
17 namespace filesystem {
19 DirectoryImpl::DirectoryImpl(mojo::InterfaceRequest<Directory> request,
20 base::FilePath directory_path,
21 scoped_ptr<base::ScopedTempDir> temp_dir)
22 : binding_(this, request.Pass()),
23 directory_path_(directory_path),
24 temp_dir_(temp_dir.Pass()) {
27 DirectoryImpl::~DirectoryImpl() {
30 void DirectoryImpl::Read(const ReadCallback& callback) {
31 mojo::Array<DirectoryEntryPtr> entries(0);
32 base::FileEnumerator directory_enumerator(
33 directory_path_, false,
34 base::FileEnumerator::DIRECTORIES | base::FileEnumerator::FILES);
35 for (base::FilePath name = directory_enumerator.Next(); !name.empty();
36 name = directory_enumerator.Next()) {
37 base::FileEnumerator::FileInfo info = directory_enumerator.GetInfo();
38 DirectoryEntryPtr entry = DirectoryEntry::New();
39 entry->type = info.IsDirectory()
40 ? FS_FILE_TYPE_DIRECTORY : FS_FILE_TYPE_REGULAR_FILE;
41 entry->name = info.GetName().AsUTF8Unsafe();
42 entries.push_back(entry.Pass());
45 callback.Run(FILE_ERROR_OK, entries.Pass());
48 // TODO(erg): Consider adding an implementation of Stat()/Touch() to the
49 // directory, too. Right now, the base::File abstractions do not really deal
50 // with directories properly, so these are broken for now.
52 // TODO(vtl): Move the implementation to a thread pool.
53 void DirectoryImpl::OpenFile(const mojo::String& raw_path,
54 mojo::InterfaceRequest<File> file,
55 uint32_t open_flags,
56 const OpenFileCallback& callback) {
57 base::FilePath path;
58 if (FileError error = ValidatePath(raw_path, directory_path_, &path)) {
59 callback.Run(error);
60 return;
63 #if defined(OS_WIN)
64 // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
65 if (DirectoryExists(path))
66 open_flags |= base::File::FLAG_BACKUP_SEMANTICS;
67 #endif // OS_WIN
69 base::File base_file(path, open_flags);
70 if (!base_file.IsValid()) {
71 callback.Run(FILE_ERROR_FAILED);
72 return;
75 base::File::Info info;
76 if (!base_file.GetInfo(&info)) {
77 callback.Run(FILE_ERROR_FAILED);
78 return;
81 if (info.is_directory) {
82 // We must not return directories as files. In the file abstraction, we can
83 // fetch raw file descriptors over mojo pipes, and passing a file
84 // descriptor to a directory is a sandbox escape on Windows.
85 callback.Run(FILE_ERROR_NOT_A_FILE);
86 return;
89 if (file.is_pending()) {
90 new FileImpl(file.Pass(), base_file.Pass());
92 callback.Run(FILE_ERROR_OK);
95 void DirectoryImpl::OpenDirectory(const mojo::String& raw_path,
96 mojo::InterfaceRequest<Directory> directory,
97 uint32_t open_flags,
98 const OpenDirectoryCallback& callback) {
99 base::FilePath path;
100 if (FileError error = ValidatePath(raw_path, directory_path_, &path)) {
101 callback.Run(error);
102 return;
105 if (!base::DirectoryExists(path)) {
106 if (base::PathExists(path)) {
107 callback.Run(FILE_ERROR_NOT_A_DIRECTORY);
108 return;
111 if (!(open_flags & kFlagOpenAlways || open_flags & kFlagCreate)) {
112 // The directory doesn't exist, and we weren't passed parameters to
113 // create it.
114 callback.Run(FILE_ERROR_NOT_FOUND);
115 return;
118 base::File::Error error;
119 if (!base::CreateDirectoryAndGetError(path, &error)) {
120 callback.Run(static_cast<filesystem::FileError>(error));
121 return;
125 if (directory.is_pending())
126 new DirectoryImpl(directory.Pass(), path,
127 scoped_ptr<base::ScopedTempDir>());
128 callback.Run(FILE_ERROR_OK);
131 void DirectoryImpl::Rename(const mojo::String& raw_old_path,
132 const mojo::String& raw_new_path,
133 const RenameCallback& callback) {
134 base::FilePath old_path;
135 if (FileError error =
136 ValidatePath(raw_old_path, directory_path_, &old_path)) {
137 callback.Run(error);
138 return;
141 base::FilePath new_path;
142 if (FileError error =
143 ValidatePath(raw_new_path, directory_path_, &new_path)) {
144 callback.Run(error);
145 return;
148 if (!base::Move(old_path, new_path)) {
149 callback.Run(FILE_ERROR_FAILED);
150 return;
153 callback.Run(FILE_ERROR_OK);
156 void DirectoryImpl::Delete(const mojo::String& raw_path,
157 uint32_t delete_flags,
158 const DeleteCallback& callback) {
159 base::FilePath path;
160 if (FileError error = ValidatePath(raw_path, directory_path_, &path)) {
161 callback.Run(error);
162 return;
165 bool recursive = delete_flags & kDeleteFlagRecursive;
166 if (!base::DeleteFile(path, recursive)) {
167 callback.Run(FILE_ERROR_FAILED);
168 return;
171 callback.Run(FILE_ERROR_OK);
174 void DirectoryImpl::Exists(const mojo::String& raw_path,
175 const ExistsCallback& callback) {
176 base::FilePath path;
177 if (FileError error = ValidatePath(raw_path, directory_path_, &path)) {
178 callback.Run(error, false);
179 return;
182 bool exists = base::PathExists(path);
183 callback.Run(FILE_ERROR_OK, exists);
186 void DirectoryImpl::IsWritable(const mojo::String& raw_path,
187 const IsWritableCallback& callback) {
188 base::FilePath path;
189 if (FileError error = ValidatePath(raw_path, directory_path_, &path)) {
190 callback.Run(error, false);
191 return;
194 callback.Run(FILE_ERROR_OK, base::PathIsWritable(path));
197 void DirectoryImpl::Flush(const FlushCallback& callback) {
198 base::File file(directory_path_, base::File::FLAG_READ);
199 if (!file.IsValid()) {
200 callback.Run(FILE_ERROR_FAILED);
201 return;
204 if (!file.Flush()) {
205 callback.Run(FILE_ERROR_FAILED);
206 return;
209 callback.Run(FILE_ERROR_OK);
212 } // namespace filesystem