blob: 24f288a3beaa676eddafef4c3c7ae248029477dd [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "extensions/browser/path_util.h"
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/strings/sys_string_conversions.h"
#include "base/task_runner_util.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "build/build_config.h"
#include "extensions/browser/extension_file_task_runner.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/text/bytes_formatting.h"
#if defined(OS_MACOSX)
#include <CoreFoundation/CoreFoundation.h>
#include "base/mac/foundation_util.h"
#endif
namespace extensions {
namespace path_util {
namespace {
#if defined(OS_MACOSX)
// Retrieves the localized display name for the base name of the given path.
// If the path is not localized, this will just return the base name.
std::string GetDisplayBaseName(const base::FilePath& path) {
base::ScopedCFTypeRef<CFURLRef> url(CFURLCreateFromFileSystemRepresentation(
NULL, (const UInt8*)path.value().c_str(), path.value().length(), true));
if (!url)
return path.BaseName().value();
CFStringRef str;
if (LSCopyDisplayNameForURL(url, &str) != noErr)
return path.BaseName().value();
std::string result(base::SysCFStringRefToUTF8(str));
CFRelease(str);
return result;
}
#endif // defined(OS_MACOSX)
const base::FilePath::CharType kHomeShortcut[] = FILE_PATH_LITERAL("~");
void OnDirectorySizeCalculated(
int message_id,
base::OnceCallback<void(const base::string16&)> callback,
int64_t size_in_bytes) {
const int one_mebibyte_in_bytes = 1024 * 1024;
base::string16 response =
size_in_bytes < one_mebibyte_in_bytes
? l10n_util::GetStringUTF16(message_id)
: ui::FormatBytesWithUnits(size_in_bytes, ui::DATA_UNITS_MEBIBYTE,
true);
std::move(callback).Run(response);
}
} // namespace
base::FilePath PrettifyPath(const base::FilePath& source_path) {
base::FilePath home_path;
if (source_path.empty() ||
!base::PathService::Get(base::DIR_HOME, &home_path)) {
return source_path;
}
base::FilePath display_path = base::FilePath(kHomeShortcut);
if (source_path == home_path)
return display_path;
#if defined(OS_MACOSX)
DCHECK(source_path.IsAbsolute());
// Break down the incoming path into components, and grab the display name
// for every component. This will match app bundles, ".localized" folders,
// and localized subfolders of the user's home directory.
// Don't grab the display name of the first component, i.e., "/", as it'll
// show up as the HDD name.
std::vector<base::FilePath::StringType> components;
source_path.GetComponents(&components);
display_path = base::FilePath(components[0]);
base::FilePath actual_path = display_path;
for (std::vector<base::FilePath::StringType>::iterator i =
components.begin() + 1; i != components.end(); ++i) {
actual_path = actual_path.Append(*i);
if (actual_path == home_path) {
display_path = base::FilePath(kHomeShortcut);
home_path = base::FilePath();
continue;
}
std::string display = GetDisplayBaseName(actual_path);
display_path = display_path.Append(display);
}
DCHECK_EQ(actual_path.value(), source_path.value());
return display_path;
#else // defined(OS_MACOSX)
if (home_path.AppendRelativePath(source_path, &display_path))
return display_path;
return source_path;
#endif // defined(OS_MACOSX)
}
void CalculateAndFormatExtensionDirectorySize(
const base::FilePath& extension_path,
int message_id,
base::OnceCallback<void(const base::string16&)> callback) {
base::PostTaskAndReplyWithResult(
GetExtensionFileTaskRunner().get(), FROM_HERE,
base::BindOnce(&base::ComputeDirectorySize, extension_path),
base::BindOnce(&OnDirectorySizeCalculated, message_id,
std::move(callback)));
}
base::FilePath ResolveHomeDirectory(const base::FilePath& path) {
#if defined(OS_WIN)
return path;
#else
const auto& value = path.value();
// Look for a path starting with the "~" character. It must be alone or
// followed by a separator.
if (value.empty() || value[0] != FILE_PATH_LITERAL('~') ||
(value.length() > 1 && !base::FilePath::IsSeparator(value[1]))) {
return path;
}
base::FilePath result;
base::PathService::Get(base::DIR_HOME, &result);
// The user could specify "~" or "~/", so be safe.
if (value.length() > 2) {
result = result.Append(value.substr(2));
}
return result;
#endif
}
} // namespace path_util
} // namespace extensions