[Filesystem] Filehandle class added. Some refactoring. 42/176442/12
authorArkadiusz Pietraszek <a.pietraszek@partner.samsung.com>
Thu, 19 Apr 2018 08:05:18 +0000 (10:05 +0200)
committerPiotr Kosko <p.kosko@samsung.com>
Fri, 11 May 2018 11:39:53 +0000 (11:39 +0000)
ACR:
http://suprem.sec.samsung.net/jira/browse/TWDAPI-121

Change-Id: I3380297e0fc4f03032a9892e47392564786871bd
Signed-off-by: Szymon Jastrzebski <s.jastrzebsk@partner.samsung.com>
Signed-off-by: Arkadiusz Pietraszek <a.pietraszek@partner.samsung.com>
Signed-off-by: Jakub Skowron <j.skowron@samsung.com>
Signed-off-by: Pawel Wasowski <p.wasowski2@partner.samsung.com>
src/filesystem/filesystem_instance.cc
src/filesystem/filesystem_instance.h

index 1e2f0443c1151720fea8791234daecc7ee8bdcbf..33d0673bf92265435d640f30f946c94c5ca4adb5 100644 (file)
 
 #include "filesystem/filesystem_instance.h"
 
+#include <linux/limits.h>
 #include <cstdint>
 #include <functional>
 #include <stdexcept>
 
 #include <sys/stat.h>
+#include <system_error>
 #include "common/logger.h"
 #include "common/picojson.h"
 #include "common/platform_exception.h"
@@ -40,6 +42,16 @@ const std::string kPrivilegeFilesystemWrite = "http://tizen.org/privilege/filesy
 
 using namespace common;
 using namespace extension::filesystem;
+using namespace std::string_literals;
+
+FileHandle::~FileHandle() {
+  ScopeLogger();
+
+  if (file_handle && std::fclose(file_handle)) {
+    int errsv = errno;
+    LoggerE("close file failed, error message: %s", strerror(errsv));
+  }
+}
 
 FilesystemInstance::FilesystemInstance() {
   ScopeLogger();
@@ -185,17 +197,36 @@ static auto from_utf8 = &decode_binary_from_string;
 }
 
 static constexpr std::size_t NPOS = (std::size_t)(-1);
+
+/**
+ * On failure throws std::system_error
+ */
+static std::size_t file_size(FILE* file) {
+  ScopeLogger();
+
+  struct ::stat buf;
+  int status = ::fstat(::fileno(file), &buf);
+  if (status != 0) {
+    throw std::system_error{errno, std::generic_category(), "failed to get file size"};
+  }
+
+  return buf.st_size;
+}
+
+static std::vector<std::uint8_t> read_file(FILE* file, std::size_t length = NPOS);
+
 /**
  * Returns a buffer. If length is NPOS, then it reads whole file, up to the end.
  * On failure throws std::runtime_error
  */
-static std::vector<std::uint8_t> read_file(std::string path, std::size_t offset,
+static std::vector<std::uint8_t> read_file(std::string path, long offset = 0,
                                            std::size_t length = NPOS) {
   ScopeLogger();
 
   FILE* file = std::fopen(path.c_str(), "r");
   if (!file) {
-    throw std::runtime_error("cannot open file to read");
+    std::string err_msg = std::string("cannot open file to read") + strerror(errno);
+    throw std::system_error{errno, std::generic_category(), err_msg};
   }
 
   SCOPE_EXIT {
@@ -205,17 +236,28 @@ static std::vector<std::uint8_t> read_file(std::string path, std::size_t offset,
     }
   };
 
-  if (std::fseek(file, offset, SEEK_SET) != 0) {
-    throw std::runtime_error("cannot perform seek");
+  if (0 != offset && 0 != std::fseek(file, offset, SEEK_SET)) {
+    std::string err_msg = std::string("cannot perform seek") + strerror(errno);
+    throw std::system_error{errno, std::generic_category(), err_msg};
+  }
+
+  if (NPOS == length) {
+    length = file_size(file) - offset;
   }
 
+  return read_file(file, length);
+}
+
+/**
+ * Returns a buffer. If length is NPOS, then it reads whole file, up to the end.
+ * On failure throws std::runtime_error
+ */
+static std::vector<std::uint8_t> read_file(FILE* file, std::size_t length /*= NPOS*/) {
+  ScopeLogger();
+
   // By default reads whole file. Get the file size.
-  if (length == NPOS) {
-    struct ::stat buf;
-    if (::fstat(::fileno(file), &buf) != 0) {
-      throw std::runtime_error("cannot fstat");
-    }
-    length = buf.st_size - offset;
+  if (NPOS == length) {
+    length = file_size(file);
   }
 
   std::vector<std::uint8_t> out_buf(length);
@@ -225,7 +267,8 @@ static std::vector<std::uint8_t> read_file(std::string path, std::size_t offset,
     data_p += std::fread(data_p, 1, end_p - data_p, file);
 
     if (std::ferror(file)) {
-      throw std::runtime_error("error during file read");
+      std::string err_msg = std::string("error during file read") + strerror(errno);
+      throw std::runtime_error(err_msg);
     }
 
     if (std::feof(file)) {
@@ -239,14 +282,38 @@ static std::vector<std::uint8_t> read_file(std::string path, std::size_t offset,
 /**
  * On failure throws std::runtime_error
  */
-void write_file(const std::uint8_t* data, std::size_t len, std::string path, std::size_t offset,
-                bool truncate) {
+void write_file(const std::uint8_t* data, std::size_t len, FILE* file) {
   ScopeLogger();
 
-  FILE* file = fopen(path.c_str(), truncate ? "w" : "r+");
+  const std::uint8_t* data_p = data;
+  const std::uint8_t* end_p = data + len;
+  while (data_p != end_p) {
+    data_p += fwrite(data_p, 1, end_p - data_p, file);
+
+    if (std::ferror(file)) {
+      std::string err_msg = std::string("error during file write") + strerror(errno);
+      throw std::runtime_error(err_msg);
+    }
+  }
+
+  if (std::fflush(file)) {
+    std::string err_msg = std::string("error during file write") + strerror(errno);
+    throw std::runtime_error(err_msg);
+  }
+}
+
+/**
+ * On failure throws std::runtime_error
+ */
+void write_file(const std::uint8_t* data, std::size_t len, std::string path, long offset,
+                const char* mode) {
+  ScopeLogger();
+
+  FILE* file = std::fopen(path.c_str(), mode);
 
   if (!file) {
-    throw std::runtime_error("cannot open file to write");
+    std::string err_msg = std::string("cannot open file to write") + strerror(errno);
+    throw std::runtime_error(err_msg);
   }
 
   SCOPE_EXIT {
@@ -256,23 +323,12 @@ void write_file(const std::uint8_t* data, std::size_t len, std::string path, std
     }
   };
 
-  if (std::fseek(file, offset, SEEK_SET) != 0) {
-    throw std::runtime_error("cannot perform seek");
+  if (offset != 0 && std::fseek(file, offset, SEEK_SET) != 0) {
+    std::string err_msg = std::string("cannot perform seek") + strerror(errno);
+    throw std::system_error{errno, std::generic_category(), err_msg};
   }
 
-  const std::uint8_t* data_p = data;
-  const std::uint8_t* end_p = data + len;
-  while (data_p != end_p) {
-    data_p += fwrite(data_p, 1, end_p - data_p, file);
-
-    if (std::ferror(file)) {
-      throw std::runtime_error("error during file write");
-    }
-  }
-
-  if (std::fflush(file)) {
-    throw std::runtime_error("error during file write");
-  }
+  write_file(data, len, file);
 }
 
 namespace base64 {
@@ -405,6 +461,7 @@ void FilesystemInstance::FileWriteString(const picojson::value& args, picojson::
   const std::string& str = args.get("data").get<std::string>();
   size_t offset = static_cast<size_t>(args.get("offset").get<double>());
   bool truncate = static_cast<bool>(args.get("truncate").get<bool>());
+  const char* mode = truncate ? "w" : "r+";
   const std::string& encoding =
       args.contains("encoding") ? args.get("encoding").get<std::string>() : "utf-8";
 
@@ -412,11 +469,11 @@ void FilesystemInstance::FileWriteString(const picojson::value& args, picojson::
     if (encoding == "iso-8859-1") {
       std::vector<std::uint8_t> data;
       latin1::from_utf8(str, data);
-      write_file(data.data(), data.size(), location, offset, truncate);
+      write_file(data.data(), data.size(), location, offset, mode);
     } else {  // default: UTF-8
       const std::uint8_t* buf = (const std::uint8_t*)str.c_str();
       std::size_t len = str.length();
-      write_file(buf, len, location, offset, truncate);
+      write_file(buf, len, location, offset, mode);
     }
   } catch (std::runtime_error& e) {
     LoggerE("Cannot write to file %s, cause: %s", location.c_str(), e.what());
@@ -439,11 +496,12 @@ void FilesystemInstance::FileWriteBytes(const picojson::value& args, picojson::o
   const std::string& str = args.get("data").get<std::string>();
   size_t offset = static_cast<size_t>(args.get("offset").get<double>());
   bool truncate = static_cast<bool>(args.get("truncate").get<bool>());
+  const char* mode = truncate ? "w" : "r+";
 
   try {
     std::vector<std::uint8_t> data;
     decode_binary_from_string(str, data);
-    write_file(data.data(), data.size(), location, offset, truncate);
+    write_file(data.data(), data.size(), location, offset, mode);
   } catch (std::runtime_error& e) {
     LoggerE("Cannot write to %s, cause: %s", location.c_str(), e.what());
     PrepareError(FilesystemError::Other, out);
@@ -465,6 +523,7 @@ void FilesystemInstance::FileWriteBase64(const picojson::value& args, picojson::
   const std::string& str = args.get("data").get<std::string>();
   size_t offset = static_cast<size_t>(args.get("offset").get<double>());
   bool truncate = static_cast<bool>(args.get("truncate").get<bool>());
+  const char* mode = truncate ? "w" : "r+";
 
   std::vector<std::uint8_t> data;
   try {
@@ -476,7 +535,7 @@ void FilesystemInstance::FileWriteBase64(const picojson::value& args, picojson::
   }
 
   try {
-    write_file(data.data(), data.size(), location, offset, truncate);
+    write_file(data.data(), data.size(), location, offset, mode);
     ReportSuccess(picojson::value{(double)data.size()}, out);
   } catch (std::runtime_error& e) {
     LoggerE("Cannot write to %s, cause: %s", location.c_str(), e.what());
index 07fb8fa8460e4f27013c02dd005ae92b4852a91b..3457b0e49aabdeb8d28ae80cc210a9348515b35f 100644 (file)
 #ifndef FILESYSTEM_FILESYSTEM_INSTANCE_H_
 #define FILESYSTEM_FILESYSTEM_INSTANCE_H_
 
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <cerrno>
+#include <condition_variable>
+#include <cstdio>
+#include <deque>
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <thread>
 #include "common/extension.h"
 #include "common/filesystem/filesystem_storage.h"
 #include "filesystem/filesystem_manager.h"
 namespace extension {
 namespace filesystem {
 
+class FileHandle;
+
+typedef std::map<int, std::shared_ptr<FileHandle>> FileHandleMap;
+
+class FileHandle {
+ public:
+  FileHandle(FILE* file_handle) : file_handle(file_handle){};
+  ~FileHandle();
+
+  FileHandle(const FileHandle&) = delete;
+  FileHandle(FileHandle&&) = delete;
+  FileHandle& operator=(const FileHandle&) = delete;
+  FileHandle& operator=(FileHandle&&) = delete;
+
+ private:
+  FILE* file_handle;
+};
+
 class FilesystemInstance : public common::ParsedInstance, FilesystemStateChangeListener {
  public:
   FilesystemInstance();
   virtual ~FilesystemInstance();
 
  private:
+  FileHandleMap opened_files;
+
   void FileCreateSync(const picojson::value& args, picojson::object& out);
   void FileRename(const picojson::value& args, picojson::object& out);
   void FileStat(const picojson::value& args, picojson::object& out);