Home | History | Annotate | Download | only in common
      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