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 "extensions/common/extension_resource.h"
7 #include "base/file_util.h"
8 #include "base/logging.h"
9 #include "base/threading/thread_restrictions.h"
11 namespace extensions
{
13 ExtensionResource::ExtensionResource() : follow_symlinks_anywhere_(false) {
16 ExtensionResource::ExtensionResource(const std::string
& extension_id
,
17 const base::FilePath
& extension_root
,
18 const base::FilePath
& relative_path
)
19 : extension_id_(extension_id
),
20 extension_root_(extension_root
),
21 relative_path_(relative_path
),
22 follow_symlinks_anywhere_(false) {
25 ExtensionResource::~ExtensionResource() {}
27 void ExtensionResource::set_follow_symlinks_anywhere() {
28 follow_symlinks_anywhere_
= true;
31 const base::FilePath
& ExtensionResource::GetFilePath() const {
32 if (extension_root_
.empty() || relative_path_
.empty()) {
33 DCHECK(full_resource_path_
.empty());
34 return full_resource_path_
;
37 // We've already checked, just return last value.
38 if (!full_resource_path_
.empty())
39 return full_resource_path_
;
41 full_resource_path_
= GetFilePath(
42 extension_root_
, relative_path_
,
43 follow_symlinks_anywhere_
?
44 FOLLOW_SYMLINKS_ANYWHERE
: SYMLINKS_MUST_RESOLVE_WITHIN_ROOT
);
45 return full_resource_path_
;
49 base::FilePath
ExtensionResource::GetFilePath(
50 const base::FilePath
& extension_root
,
51 const base::FilePath
& relative_path
,
52 SymlinkPolicy symlink_policy
) {
53 // We need to resolve the parent references in the extension_root
54 // path on its own because IsParent doesn't like parent references.
55 base::FilePath
clean_extension_root(
56 base::MakeAbsoluteFilePath(extension_root
));
57 if (clean_extension_root
.empty())
58 return base::FilePath();
60 base::FilePath full_path
= clean_extension_root
.Append(relative_path
);
62 // If we are allowing the file to be a symlink outside of the root, then the
63 // path before resolving the symlink must still be within it.
64 if (symlink_policy
== FOLLOW_SYMLINKS_ANYWHERE
) {
65 std::vector
<base::FilePath::StringType
> components
;
66 relative_path
.GetComponents(&components
);
69 for (std::vector
<base::FilePath::StringType
>::const_iterator
70 i
= components
.begin(); i
!= components
.end(); i
++) {
71 if (*i
== base::FilePath::kParentDirectory
) {
73 } else if (*i
!= base::FilePath::kCurrentDirectory
) {
77 return base::FilePath();
82 // We must resolve the absolute path of the combined path when
83 // the relative path contains references to a parent folder (i.e., '..').
84 // We also check if the path exists because the posix version of
85 // MakeAbsoluteFilePath will fail if the path doesn't exist, and we want the
86 // same behavior on Windows... So until the posix and Windows version of
87 // MakeAbsoluteFilePath are unified, we need an extra call to PathExists,
89 // TODO(mad): Fix this once MakeAbsoluteFilePath is unified.
90 full_path
= base::MakeAbsoluteFilePath(full_path
);
91 if (base::PathExists(full_path
) &&
92 (symlink_policy
== FOLLOW_SYMLINKS_ANYWHERE
||
93 clean_extension_root
.IsParent(full_path
))) {
97 return base::FilePath();
100 // Unit-testing helpers.
101 base::FilePath::StringType
ExtensionResource::NormalizeSeperators(
102 const base::FilePath::StringType
& path
) const {
103 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
104 base::FilePath::StringType win_path
= path
;
105 for (size_t i
= 0; i
< win_path
.length(); i
++) {
106 if (base::FilePath::IsSeparator(win_path
[i
]))
107 win_path
[i
] = base::FilePath::kSeparators
[0];
112 #endif // FILE_PATH_USES_WIN_SEPARATORS
115 bool ExtensionResource::ComparePathWithDefault(
116 const base::FilePath
& path
) const {
117 // Make sure we have a cached value to test against...
118 if (full_resource_path_
.empty())
120 if (NormalizeSeperators(path
.value()) ==
121 NormalizeSeperators(full_resource_path_
.value())) {
128 } // namespace extensions