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 "extensions/common/extension_resource.h" 6 7 #include "base/file_util.h" 8 #include "base/logging.h" 9 #include "base/threading/thread_restrictions.h" 10 11 namespace extensions { 12 13 ExtensionResource::ExtensionResource() : follow_symlinks_anywhere_(false) { 14 } 15 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) { 23 } 24 25 ExtensionResource::~ExtensionResource() {} 26 27 void ExtensionResource::set_follow_symlinks_anywhere() { 28 follow_symlinks_anywhere_ = true; 29 } 30 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_; 35 } 36 37 // We've already checked, just return last value. 38 if (!full_resource_path_.empty()) 39 return full_resource_path_; 40 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_; 46 } 47 48 // static 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(); 59 60 base::FilePath full_path = clean_extension_root.Append(relative_path); 61 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); 67 int depth = 0; 68 69 for (std::vector<base::FilePath::StringType>::const_iterator 70 i = components.begin(); i != components.end(); i++) { 71 if (*i == base::FilePath::kParentDirectory) { 72 depth--; 73 } else if (*i != base::FilePath::kCurrentDirectory) { 74 depth++; 75 } 76 if (depth < 0) { 77 return base::FilePath(); 78 } 79 } 80 } 81 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, 88 // unfortunately. 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))) { 94 return full_path; 95 } 96 97 return base::FilePath(); 98 } 99 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]; 108 } 109 return win_path; 110 #else 111 return path; 112 #endif // FILE_PATH_USES_WIN_SEPARATORS 113 } 114 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()) 119 GetFilePath(); 120 if (NormalizeSeperators(path.value()) == 121 NormalizeSeperators(full_resource_path_.value())) { 122 return true; 123 } else { 124 return false; 125 } 126 } 127 128 } // namespace extensions 129