blob: 392e323d1edd40799ed262738b386a14aca18b85 [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 "posix_translation/mount_point_manager.h"
#include <utility>
#include "base/strings/string_util.h"
#include "common/arc_strace.h"
#include "common/alog.h"
#include "common/process_emulator.h"
#include "posix_translation/directory_manager.h"
#include "posix_translation/file_system_handler.h"
#include "posix_translation/path_util.h"
namespace posix_translation {
MountPointManager::MountPointManager() {}
MountPointManager::~MountPointManager() {
}
void MountPointManager::Add(const std::string& path,
FileSystemHandler* handler) {
ALOG_ASSERT(!path.empty());
ALOG_ASSERT(handler, "NULL FileSystemHandler is not allowed: %s",
path.c_str());
if (!mount_point_map_.insert(make_pair(
path, MountPoint(handler, arc::kRootUid))).second) {
LOG_ALWAYS_FATAL("%s: mount point already exists", path.c_str());
}
handler->OnMounted(path);
update_producer_.ProduceUpdate();
ARC_STRACE_REPORT("MountPointManager::Add: path=%s handler=%s",
path.c_str(), handler->name().c_str());
}
void MountPointManager::Remove(const std::string& path) {
MountPointMap::iterator i = mount_point_map_.find(path);
if (i != mount_point_map_.end()) {
FileSystemHandler* handler = i->second.handler;
ALOG_ASSERT(handler);
ARC_STRACE_REPORT("MountPointManager::Remove: path=%s handler=%s",
path.c_str(), handler->name().c_str());
mount_point_map_.erase(i);
handler->OnUnmounted(path);
update_producer_.ProduceUpdate();
} else {
ARC_STRACE_REPORT("MountPointManager::Remove: path=%s is NOT registered",
path.c_str());
}
}
void MountPointManager::ChangeOwner(const std::string& path, uid_t owner_uid) {
ALOG_ASSERT(!path.empty());
MountPointMap::iterator found = mount_point_map_.find(path);
// If the mount point does not exist yet, create it. This is for e.g.
// /data/data/<app-id>. This mount point does not exist before chown
// is called.
if (found == mount_point_map_.end()) {
uid_t dummy_uid;
FileSystemHandler* handler = GetFileSystemHandler(path, &dummy_uid);
ALOG_ASSERT(handler, "Could not find a FileSystemHandler for %s",
path.c_str());
Add(path, handler);
found = mount_point_map_.find(path);
ALOG_ASSERT(found != mount_point_map_.end());
}
found->second.owner_uid = owner_uid;
update_producer_.ProduceUpdate();
ARC_STRACE_REPORT("MountPointManager::ChangeOwner: path=%s uid=%d",
path.c_str(), owner_uid);
}
FileSystemHandler* MountPointManager::GetFileSystemHandler(
const std::string& path,
uid_t* owner_uid) const {
ALOG_ASSERT(owner_uid);
if (path.empty())
return NULL;
*owner_uid = arc::kRootUid;
// MountPointManager may have some mount points for non-directory
// files (e.g., /dev/null). Check it first.
MountPointMap::const_iterator found = mount_point_map_.find(path);
if (found != mount_point_map_.end()) {
*owner_uid = found->second.owner_uid;
return found->second.handler;
}
// We will find the deepest mount point for |path|. For example, for
// /system/lib/libdl.so, we should find /system/lib, not /system. To
// do this, we strip the basename one by one in the following loop.
std::string dir(path);
do {
util::EnsurePathEndsWithSlash(&dir);
// Check if |dir| is a mount point.
found = mount_point_map_.find(dir);
if (found != mount_point_map_.end()) {
*owner_uid = found->second.owner_uid;
return found->second.handler;
}
// Strip a basename.
util::GetDirNameInPlace(&dir);
} while (dir.length() > 1);
// TODO(satorux): Clean up the logic here. |dir| is either "/" or "." here.
// Normalizing the path before calling this function would make the logic
// cleaner. See also crbug.com/178515.
if (dir == "/") {
found = mount_point_map_.find(dir);
if (found != mount_point_map_.end()) {
*owner_uid = found->second.owner_uid;
return found->second.handler;
}
}
return NULL;
}
void MountPointManager::GetAllFileSystemHandlers(
std::vector<FileSystemHandler*>* out_handlers) {
for (MountPointMap::const_iterator it = mount_point_map_.begin();
it != mount_point_map_.end(); ++it) {
FileSystemHandler* handler = it->second.handler;
out_handlers->push_back(handler);
}
}
void MountPointManager::Clear() {
mount_point_map_.clear();
}
} // namespace posix_translation