From: Arkadiusz Pietraszek Date: Thu, 19 Apr 2018 08:05:18 +0000 (+0200) Subject: [Filesystem] Filehandle class added. Some refactoring. X-Git-Tag: submit/tizen/20180518.121229~9 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F42%2F176442%2F12;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git [Filesystem] Filehandle class added. Some refactoring. ACR: http://suprem.sec.samsung.net/jira/browse/TWDAPI-121 Change-Id: I3380297e0fc4f03032a9892e47392564786871bd Signed-off-by: Szymon Jastrzebski Signed-off-by: Arkadiusz Pietraszek Signed-off-by: Jakub Skowron Signed-off-by: Pawel Wasowski --- diff --git a/src/filesystem/filesystem_instance.cc b/src/filesystem/filesystem_instance.cc index 1e2f0443..33d0673b 100644 --- a/src/filesystem/filesystem_instance.cc +++ b/src/filesystem/filesystem_instance.cc @@ -16,11 +16,13 @@ #include "filesystem/filesystem_instance.h" +#include #include #include #include #include +#include #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 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 read_file(std::string path, std::size_t offset, +static std::vector 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 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 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 out_buf(length); @@ -225,7 +267,8 @@ static std::vector 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 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(); size_t offset = static_cast(args.get("offset").get()); bool truncate = static_cast(args.get("truncate").get()); + const char* mode = truncate ? "w" : "r+"; const std::string& encoding = args.contains("encoding") ? args.get("encoding").get() : "utf-8"; @@ -412,11 +469,11 @@ void FilesystemInstance::FileWriteString(const picojson::value& args, picojson:: if (encoding == "iso-8859-1") { std::vector 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(); size_t offset = static_cast(args.get("offset").get()); bool truncate = static_cast(args.get("truncate").get()); + const char* mode = truncate ? "w" : "r+"; try { std::vector 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(); size_t offset = static_cast(args.get("offset").get()); bool truncate = static_cast(args.get("truncate").get()); + const char* mode = truncate ? "w" : "r+"; std::vector 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()); diff --git a/src/filesystem/filesystem_instance.h b/src/filesystem/filesystem_instance.h index 07fb8fa8..3457b0e4 100644 --- a/src/filesystem/filesystem_instance.h +++ b/src/filesystem/filesystem_instance.h @@ -17,6 +17,17 @@ #ifndef FILESYSTEM_FILESYSTEM_INSTANCE_H_ #define FILESYSTEM_FILESYSTEM_INSTANCE_H_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "common/extension.h" #include "common/filesystem/filesystem_storage.h" #include "filesystem/filesystem_manager.h" @@ -25,12 +36,32 @@ namespace extension { namespace filesystem { +class FileHandle; + +typedef std::map> 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);