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
,
56 const OpenFileCallback
& callback
) {
58 if (FileError error
= ValidatePath(raw_path
, directory_path_
, &path
)) {
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
;
69 base::File
base_file(path
, open_flags
);
70 if (!base_file
.IsValid()) {
71 callback
.Run(FILE_ERROR_FAILED
);
75 base::File::Info info
;
76 if (!base_file
.GetInfo(&info
)) {
77 callback
.Run(FILE_ERROR_FAILED
);
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
);
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
,
98 const OpenDirectoryCallback
& callback
) {
100 if (FileError error
= ValidatePath(raw_path
, directory_path_
, &path
)) {
105 if (!base::DirectoryExists(path
)) {
106 if (base::PathExists(path
)) {
107 callback
.Run(FILE_ERROR_NOT_A_DIRECTORY
);
111 if (!(open_flags
& kFlagOpenAlways
|| open_flags
& kFlagCreate
)) {
112 // The directory doesn't exist, and we weren't passed parameters to
114 callback
.Run(FILE_ERROR_NOT_FOUND
);
118 base::File::Error error
;
119 if (!base::CreateDirectoryAndGetError(path
, &error
)) {
120 callback
.Run(static_cast<filesystem::FileError
>(error
));
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
)) {
141 base::FilePath new_path
;
142 if (FileError error
=
143 ValidatePath(raw_new_path
, directory_path_
, &new_path
)) {
148 if (!base::Move(old_path
, new_path
)) {
149 callback
.Run(FILE_ERROR_FAILED
);
153 callback
.Run(FILE_ERROR_OK
);
156 void DirectoryImpl::Delete(const mojo::String
& raw_path
,
157 uint32_t delete_flags
,
158 const DeleteCallback
& callback
) {
160 if (FileError error
= ValidatePath(raw_path
, directory_path_
, &path
)) {
165 bool recursive
= delete_flags
& kDeleteFlagRecursive
;
166 if (!base::DeleteFile(path
, recursive
)) {
167 callback
.Run(FILE_ERROR_FAILED
);
171 callback
.Run(FILE_ERROR_OK
);
174 void DirectoryImpl::Exists(const mojo::String
& raw_path
,
175 const ExistsCallback
& callback
) {
177 if (FileError error
= ValidatePath(raw_path
, directory_path_
, &path
)) {
178 callback
.Run(error
, false);
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
) {
189 if (FileError error
= ValidatePath(raw_path
, directory_path_
, &path
)) {
190 callback
.Run(error
, false);
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
);
205 callback
.Run(FILE_ERROR_FAILED
);
209 callback
.Run(FILE_ERROR_OK
);
212 } // namespace filesystem