blob: 253187cf80415494b78a6829f6eeae8a98d2ec7e [file] [log] [blame]
// Copyright 2018 The Chromium OS 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 "cryptohome/arc_disk_quota.h"
#include <base/files/file_enumerator.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/logging.h>
namespace cryptohome {
ArcDiskQuota::ArcDiskQuota(HomeDirs* homedirs,
Platform* platform,
const base::FilePath& home)
: homedirs_(homedirs), platform_(platform), home_(home) {}
ArcDiskQuota::~ArcDiskQuota() = default;
void ArcDiskQuota::Initialize() {
device_ = GetDevice();
}
bool ArcDiskQuota::IsQuotaSupported() const {
if (device_.empty()) {
LOG(ERROR) << "No quota mount is found.";
return false;
}
// TODO(risan): Support quota for more than 1 Android user,
// after that, the following check could be removed.
int cnt = homedirs_->GetUnmountedAndroidDataCount();
if (cnt != 0) {
LOG(ERROR) << "Quota is supported only if there are no unmounted Android "
"users. Found extra unmounted "
<< cnt << " Android users.";
return false;
}
return true;
}
int64_t ArcDiskQuota::GetCurrentSpaceForUid(uid_t android_uid) const {
if (android_uid < kAndroidUidStart || android_uid > kAndroidUidEnd) {
LOG(ERROR) << "Android uid " << android_uid
<< " is outside the allowed query range";
return -1;
}
if (device_.empty()) {
LOG(ERROR) << "No quota mount is found";
return -1;
}
uid_t real_uid = android_uid + kArcContainerShiftUid;
int64_t current_space =
platform_->GetQuotaCurrentSpaceForUid(device_, real_uid);
if (current_space == -1) {
PLOG(ERROR) << "Failed to get disk stats for uid: " << real_uid;
return -1;
}
return current_space;
}
int64_t ArcDiskQuota::GetCurrentSpaceForGid(gid_t android_gid) const {
if (android_gid < kAndroidGidStart || android_gid > kAndroidGidEnd) {
LOG(ERROR) << "Android gid " << android_gid
<< " is outside the allowed query range";
return -1;
}
if (device_.empty()) {
LOG(ERROR) << "No quota mount is found";
return -1;
}
gid_t real_gid = android_gid + kArcContainerShiftGid;
int64_t current_space =
platform_->GetQuotaCurrentSpaceForGid(device_, real_gid);
if (current_space == -1) {
PLOG(ERROR) << "Failed to get disk stats for gid: " << real_gid;
return -1;
}
return current_space;
}
base::FilePath ArcDiskQuota::GetDevice() {
std::string device;
if (!platform_->FindFilesystemDevice(home_, &device)) {
LOG(ERROR) << "Home device is not found.";
return base::FilePath();
}
// Check if the device is mounted with quota option.
if (platform_->GetQuotaCurrentSpaceForUid(base::FilePath(device), 0) < 0) {
LOG(ERROR) << "Device is not mounted with quota feature enabled.";
return base::FilePath();
}
return base::FilePath(device);
}
} // namespace cryptohome