/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* See the License for the specific language governing permissions and
* limitations under the License
*/
+#include <fstream>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <linux/fs.h>
+#include <linux/fiemap.h>
+
+#include <vconf.h>
+#include <klay/exception.h>
#include <klay/filesystem.h>
#include <klay/audit/logger.h>
+#include "ext4-tool.h"
+#include "block-device.h"
+#include "progress-bar.h"
#include "rmi/secure-erase.h"
+#define PRIVILEGE_PLATFORM "http://tizen.org/privilege/internal/default/platform"
+
namespace ode {
-SecureErase::SecureErase(ODEControlContext& ctx) :
- context(ctx)
+namespace {
+
+std::unique_ptr<ProgressBar> progressBar;
+
+static int totalFileCount = 0;
+static int erasedFileCount = 0;
+
+static int getTotalFileCount(const std::string &name)
+{
+ int total = 0;
+ runtime::DirectoryIterator iter(name), end;
+
+ while (iter != end) {
+ std::string next = name + "/" + iter->getName();
+ runtime::File file(next);
+ if (!file.exists()) {
+ return -1;
+ }
+
+ if (file.isFile()) {
+ total++;
+ } else if (file.isDirectory()) {
+ int subTotal = getTotalFileCount(next);
+ if (subTotal != -1)
+ total += subTotal;
+ }
+ ++iter;
+ }
+
+ return total;
+}
+
+} /* namespace */
+
+SecureErase::SecureErase(ODEControlContext &ctx) :
+ context(ctx), devicePath("")
{
- context.registerParametricMethod(this, "", (int)(SecureErase::erase)(std::string));
- context.registerParametricMethod(this, "", (int)(SecureErase::clean)(std::string));
+ context.expose(this, PRIVILEGE_PLATFORM, (int)(SecureErase::erase)(std::string));
+ context.expose(this, PRIVILEGE_PLATFORM, (int)(SecureErase::clean)(std::string));
+
+ progressBar.reset(new ProgressBar([](int v) {
+ ::vconf_set_str(VCONFKEY_ODE_ERASE_PROGRESS, std::to_string(v).c_str());
+ }));
}
SecureErase::~SecureErase()
{
}
-int SecureErase::erase(const std::string& name)
+int SecureErase::erase(const std::string &name)
{
- return -1;
+ auto eraseWorker = [name, this]() {
+ try {
+ runtime::File file(name);
+
+ BlockDevice blockDevice(name);
+ devicePath = blockDevice.getName();
+
+ if (file.isFile()) {
+ totalFileCount = 1;
+ fileErase(name);
+ } else if (file.isDirectory()) {
+ totalFileCount = getTotalFileCount(name);
+ erasedFileCount = 0;
+ directoryErase(name);
+ } else if (file.isDevice()) {
+ Ext4Tool ext4Tool(name);
+ unsigned int totalBlock = ext4Tool.getTotalBlockCount();
+ unsigned int blockSize = (unsigned int)blockDevice.getSize();
+
+ for (unsigned int i = 0; i < totalBlock; i++) {
+ Block block(i * blockSize, blockSize);
+ blockDevice.discard(block);
+ progressBar->update(i, totalBlock, 1);
+ }
+ }
+ dropCachePage();
+ progressBar->done();
+ } catch (runtime::Exception &e) {}
+ };
+
+ std::thread asyncWork(eraseWorker);
+ asyncWork.detach();
+
+ return 0;
}
-int SecureErase::clean(const std::string& name)
+int SecureErase::clean(const std::string &name)
{
- return -1;
+ try {
+ runtime::File file(name, O_WRONLY);
+ if (!file.exists() || !file.isDevice())
+ return -1;
+ } catch (runtime::Exception &e) {}
+
+ auto cleanWorker = [name, this]() {
+ try {
+ BlockDevice blockDevice(name);
+ unsigned totalBlock, blockSize;
+
+ Ext4Tool ext4Tool(name);
+ totalBlock = ext4Tool.getTotalBlockCount();
+ blockSize = (unsigned int) blockDevice.getSize();
+
+ for (unsigned int i = 0; i < totalBlock; i++) {
+ if (!ext4Tool.isUsedBlock(i)) {
+ Block block(i * blockSize, blockSize);
+ blockDevice.discard(block);
+ }
+
+ progressBar->update(i, totalBlock, 1);
+ }
+ dropCachePage();
+ progressBar->done();
+ } catch (runtime::Exception &e) {}
+ };
+
+ std::thread asyncWork(cleanWorker);
+ asyncWork.detach();
+
+ return 0;
}
+int SecureErase::fileErase(const std::string &name)
+{
+ int ret = 0, fd = 0;
+ int extentBlockCount = 0;
+ char buf[4096] = "";
+ struct fiemap *fmap = (struct fiemap *)buf;
+ struct fiemap_extent *fm_ext = NULL;
+ int count = (sizeof(buf) - sizeof(*fmap)) / sizeof(struct fiemap_extent);
+
+ /* [TBD] stop the related process */
+
+ BlockDevice blockDevice(devicePath);
+
+ ::memset(fmap, 0, sizeof(struct fiemap));
+
+ fd = ::open(name.c_str(), O_RDONLY);
+ if (fd < 0) {
+ return -1;
+ }
+
+ fmap->fm_length = ~0ULL;
+ fmap->fm_flags = 0;
+ fmap->fm_extent_count = count;
+
+ ret = ::ioctl(fd, FS_IOC_FIEMAP, (unsigned long)fmap);
+ if (ret < 0) {
+ ::close(fd);
+ return -1;
+ }
+
+ ::close(fd);
+
+ fm_ext = &fmap->fm_extents[0];
+ extentBlockCount = (int)fmap->fm_mapped_extents;
+
+ for (int i = 0; i < extentBlockCount; i++) {
+ Block block(fm_ext[i].fe_physical, fm_ext[i].fe_length);
+ ret = blockDevice.secDiscard(block);
+ if (ret < 0) {
+ return -1;
+ }
+
+ if (totalFileCount == 1) {
+ progressBar->update(i, extentBlockCount, 1);
+ }
+ }
+ return ret;
+}
+
+int SecureErase::directoryErase(const std::string &name)
+{
+ runtime::DirectoryIterator iter(name), end;
+ while (iter != end) {
+ std::string next = name + "/" + iter->getName();
+ runtime::File file(next);
+ if (!file.exists()) {
+ return -1;
+ }
+
+ if (file.isFile()) {
+ fileErase(next);
+ ::remove(next.c_str());
+ erasedFileCount++;
+ progressBar->update(erasedFileCount, totalFileCount, 1);
+ } else if (file.isDirectory()) {
+ directoryErase(next);
+ }
+ ++iter;
+ }
+
+ fileErase(name);
+ ::rmdir(name.c_str());
+ return 0;
+}
+
+void SecureErase::dropCachePage()
+{
+ std::ofstream file;
+
+ file.open("/proc/sys/vm/drop_caches");
+ if (file.fail()) {
+ throw runtime::Exception("Failed to access drop_caches file");
+ }
+ file << "3\n";
+ file.close();
+ ::sync();
+
+ return;
+}
} // namespace ode