Change not to construct classes in global
[platform/core/security/ode.git] / server / secure-erase.cpp
index a0afbec..e8b66ad 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  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::stringname)
+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::stringname)
+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