blob: 9b0c3472943d200cc5551fe43b623dbb2eb06dd9 [file] [log] [blame]
// Copyright 2018 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
#include "starboard/common/string.h"
#include "starboard/configuration_constants.h"
#include "starboard/directory.h"
#include "starboard/file.h"
#include "starboard/memory.h"
namespace base {
// FileEnumerator::FileInfo ----------------------------------------------------
FileEnumerator::FileInfo::FileInfo() {
memset(&sb_info_, 0, sizeof(sb_info_));
}
bool FileEnumerator::FileInfo::IsDirectory() const {
return sb_info_.is_directory;
}
FilePath FileEnumerator::FileInfo::GetName() const {
return filename_;
}
int64_t FileEnumerator::FileInfo::GetSize() const {
return sb_info_.size;
}
base::Time FileEnumerator::FileInfo::GetLastModifiedTime() const {
return base::Time::FromDeltaSinceWindowsEpoch(
base::TimeDelta::FromMicroseconds(sb_info_.last_modified));
}
// FileEnumerator --------------------------------------------------------------
FileEnumerator::FileEnumerator(const FilePath& root_path,
bool recursive,
int file_type)
: FileEnumerator(root_path,
recursive,
file_type,
FilePath::StringType(),
FolderSearchPolicy::MATCH_ONLY) {}
FileEnumerator::FileEnumerator(const FilePath& root_path,
bool recursive,
int file_type,
const FilePath::StringType& pattern)
: FileEnumerator(root_path,
recursive,
file_type,
pattern,
FolderSearchPolicy::MATCH_ONLY) {}
FileEnumerator::FileEnumerator(const FilePath& root_path,
bool recursive,
int file_type,
const FilePath::StringType& pattern,
FolderSearchPolicy folder_search_policy)
: FileEnumerator(root_path,
recursive,
file_type,
pattern,
folder_search_policy,
ErrorPolicy::IGNORE_ERRORS) {}
FileEnumerator::FileEnumerator(const FilePath& root_path,
bool recursive,
int file_type,
const FilePath::StringType& pattern,
FolderSearchPolicy folder_search_policy,
ErrorPolicy error_policy)
: current_directory_entry_(0),
root_path_(root_path),
recursive_(recursive),
file_type_(file_type),
pattern_(pattern),
folder_search_policy_(folder_search_policy),
error_policy_(error_policy) {
// INCLUDE_DOT_DOT must not be specified if recursive.
DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
// The Windows version of this code appends the pattern to the root_path,
// potentially only matching against items in the top-most directory.
// Do the same here.
if (pattern.empty()) {
pattern_ = FilePath::StringType();
}
pending_paths_.push(root_path);
}
FileEnumerator::~FileEnumerator() = default;
// static
std::vector<FileEnumerator::FileInfo> FileEnumerator::ReadDirectory(
const FilePath& source) {
internal::AssertBlockingAllowed();
SbFileError error;
SbDirectory dir = SbDirectoryOpen(source.value().c_str(), &error);
if (!SbDirectoryIsValid(dir)) {
error_ = static_cast<File::Error>(error);
return std::vector<FileEnumerator::FileInfo>();
}
auto GenerateEntry = [source](std::string filename) {
FileEnumerator::FileInfo info;
info.filename_ = FilePath(filename);
FilePath full_name = source.Append(filename);
// TODO: Make sure this follows symlinks on relevant platforms.
if (!SbFileGetPathInfo(full_name.value().c_str(), &info.sb_info_)) {
DPLOG(ERROR) << "Couldn't SbFileGetInfo on " << full_name.value();
memset(&info.sb_info_, 0, sizeof(info.sb_info_));
}
return info;
};
std::vector<FileEnumerator::FileInfo> ret;
// We test if SbDirectoryGetNext returns the parent directory, i.e. |..|,
// because whether or not it is returned is platform-dependent and we need to
// be able to guarantee it is returned when the INCLUDE_DOT_DOT bitflag is
// set.
bool found_dot_dot = false;
std::vector<char> entry(kSbFileMaxName);
while (SbDirectoryGetNext(dir, entry.data(), entry.size())) {
const char dot_dot_str[] = "..";
if (!strncmp(entry.data(), dot_dot_str, sizeof(dot_dot_str))) {
found_dot_dot = true;
}
ret.push_back(GenerateEntry(entry.data()));
}
if ((INCLUDE_DOT_DOT & file_type_) && !found_dot_dot) {
ret.push_back(GenerateEntry(".."));
}
SbDirectoryClose(dir);
return ret;
}
FilePath FileEnumerator::Next() {
internal::AssertBlockingAllowed();
++current_directory_entry_;
// While we've exhausted the entries in the current directory, do the next
while (current_directory_entry_ >= directory_entries_.size()) {
if (pending_paths_.empty()) {
return FilePath();
}
root_path_ = pending_paths_.top();
root_path_ = root_path_.StripTrailingSeparators();
pending_paths_.pop();
std::vector<FileInfo> entries = ReadDirectory(root_path_);
directory_entries_.clear();
current_directory_entry_ = 0;
for (const auto& file_info : entries) {
FilePath full_path = root_path_.Append(file_info.filename_);
if (ShouldSkip(full_path)) {
continue;
}
if (pattern_.size()) {
NOTREACHED() << "Patterns not supported in Starboard.";
continue;
}
if (recursive_ && file_info.sb_info_.is_directory) {
pending_paths_.push(full_path);
}
if ((file_info.sb_info_.is_directory && (file_type_ & DIRECTORIES)) ||
(!file_info.sb_info_.is_directory && (file_type_ & FILES)) ||
(file_type_ & NAMES_ONLY)) {
directory_entries_.push_back(file_info);
}
}
}
return root_path_.Append(
directory_entries_[current_directory_entry_].filename_);
}
FileEnumerator::FileInfo FileEnumerator::GetInfo() const {
DCHECK(!(file_type_ & FileType::NAMES_ONLY));
return directory_entries_[current_directory_entry_];
}
} // namespace base