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 "xwalk/application/common/application_resource.h"
9 #include "base/file_util.h"
10 #include "base/logging.h"
11 #include "base/threading/thread_restrictions.h"
14 namespace application {
16 ApplicationResource::ApplicationResource() : follow_symlinks_anywhere_(false) {
19 ApplicationResource::ApplicationResource(const std::string& application_id,
20 const base::FilePath& application_root,
21 const base::FilePath& relative_path)
22 : application_id_(application_id),
23 application_root_(application_root),
24 relative_path_(relative_path),
25 follow_symlinks_anywhere_(false) {
28 ApplicationResource::~ApplicationResource() {}
30 void ApplicationResource::set_follow_symlinks_anywhere() {
31 follow_symlinks_anywhere_ = true;
34 const base::FilePath& ApplicationResource::GetFilePath() const {
35 if (application_root_.empty() || relative_path_.empty()) {
36 DCHECK(full_resource_path_.empty());
37 return full_resource_path_;
40 // We've already checked, just return last value.
41 if (!full_resource_path_.empty())
42 return full_resource_path_;
44 full_resource_path_ = GetFilePath(
45 application_root_, relative_path_,
46 follow_symlinks_anywhere_ ?
47 FOLLOW_SYMLINKS_ANYWHERE : SYMLINKS_MUST_RESOLVE_WITHIN_ROOT);
48 return full_resource_path_;
52 base::FilePath ApplicationResource::GetFilePath(
53 const base::FilePath& application_root,
54 const base::FilePath& relative_path,
55 SymlinkPolicy symlink_policy) {
56 // We need to resolve the parent references in the application_root
57 // path on its own because IsParent doesn't like parent references.
58 base::FilePath clean_application_root(
59 base::MakeAbsoluteFilePath(application_root));
60 if (clean_application_root.empty())
61 return base::FilePath();
63 base::FilePath full_path = clean_application_root.Append(relative_path);
65 // If we are allowing the file to be a symlink outside of the root, then the
66 // path before resolving the symlink must still be within it.
67 if (symlink_policy == FOLLOW_SYMLINKS_ANYWHERE) {
68 std::vector<base::FilePath::StringType> components;
69 relative_path.GetComponents(&components);
72 for (std::vector<base::FilePath::StringType>::const_iterator
73 i = components.begin(); i != components.end(); i++) {
74 if (*i == base::FilePath::kParentDirectory) {
76 } else if (*i != base::FilePath::kCurrentDirectory) {
80 return base::FilePath();
85 // We must resolve the absolute path of the combined path when
86 // the relative path contains references to a parent folder (i.e., '..').
87 // We also check if the path exists because the posix version of
88 // MakeAbsoluteFilePath will fail if the path doesn't exist, and we want the
89 // same behavior on Windows... So until the posix and Windows version of
90 // MakeAbsoluteFilePath are unified, we need an extra call to PathExists,
92 // TODO(mad): Fix this once MakeAbsoluteFilePath is unified.
93 full_path = base::MakeAbsoluteFilePath(full_path);
94 if (base::PathExists(full_path) &&
95 (symlink_policy == FOLLOW_SYMLINKS_ANYWHERE ||
96 clean_application_root.IsParent(full_path))) {
100 return base::FilePath();
103 // Unit-testing helpers.
104 base::FilePath::StringType ApplicationResource::NormalizeSeperators(
105 const base::FilePath::StringType& path) const {
106 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
107 base::FilePath::StringType win_path = path;
108 for (size_t i = 0; i < win_path.length(); i++) {
109 if (base::FilePath::IsSeparator(win_path[i]))
110 win_path[i] = base::FilePath::kSeparators[0];
115 #endif // FILE_PATH_USES_WIN_SEPARATORS
118 bool ApplicationResource::ComparePathWithDefault(
119 const base::FilePath& path) const {
120 // Make sure we have a cached value to test against...
121 if (full_resource_path_.empty())
123 if (NormalizeSeperators(path.value()) ==
124 NormalizeSeperators(full_resource_path_.value())) {
131 } // namespace application