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