2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "filesystem/filesystem_instance.h"
19 #include <linux/limits.h>
25 #include <system_error>
26 #include "common/logger.h"
27 #include "common/picojson.h"
28 #include "common/platform_exception.h"
29 #include "common/scope_exit.h"
30 #include "common/task-queue.h"
31 #include "common/tools.h"
32 #include "filesystem_manager.h"
35 namespace filesystem {
39 using common::tools::GetErrorString;
41 // The privileges that required in Filesystem API
42 const std::string kPrivilegeFilesystemRead = "http://tizen.org/privilege/filesystem.read";
43 const std::string kPrivilegeFilesystemWrite = "http://tizen.org/privilege/filesystem.write";
45 const std::string kISOEncoding = "ISO-8859-1";
46 const std::string kUTF8Encoding = "UTF-8";
48 std::string GetFopenMode(const picojson::value& args) {
50 const std::string& open_mode = args.get("openMode").get<std::string>();
52 if ("rw" == open_mode) {
54 } else if ("rwo" == open_mode) {
61 bool WriteAccessRequested(const picojson::value& args) {
63 const std::string& open_mode = args.get("openMode").get<std::string>();
65 return "a" == open_mode || "rw" == open_mode || "rwo" == open_mode || "w" == open_mode;
68 bool ReadAccessRequested(const picojson::value& args) {
70 const std::string& open_mode = args.get("openMode").get<std::string>();
72 return "r" == open_mode || "rw" == open_mode || "rwo" == open_mode;
75 bool ShouldMakeParents(const picojson::value& args) {
77 const std::string& path = args.get("path").get<std::string>();
79 if (FilesystemUtils::CheckIfExists(FilesystemUtils::Dirname(path), &buf)) {
82 bool make_parents = args.get("makeParents").get<bool>();
83 const std::string& open_mode = args.get("openMode").get<std::string>();
84 return make_parents && ("w" == open_mode || "a" == open_mode || "rwo" == open_mode);
88 using namespace common;
89 using namespace extension::filesystem;
90 using namespace std::string_literals;
92 FileHandle::~FileHandle() {
95 if (file_handle && std::fclose(file_handle)) {
96 LoggerE("close file failed, error message: %s", GetErrorString(errno).c_str());
100 FilesystemInstance::FilesystemInstance() {
103 using std::placeholders::_1;
104 using std::placeholders::_2;
106 #define REGISTER_SYNC(c, x) RegisterSyncHandler(c, std::bind(&FilesystemInstance::x, this, _1, _2));
108 REGISTER_SYNC("File_stat", FileStat);
109 REGISTER_SYNC("File_statSync", FileStatSync);
110 REGISTER_SYNC("File_createSync", FileCreateSync);
111 REGISTER_SYNC("File_readDir", ReadDir);
112 REGISTER_SYNC("File_rename", FileRename);
113 REGISTER_SYNC("File_readBytes", FileReadBytes);
114 REGISTER_SYNC("File_readString", FileReadString);
115 REGISTER_SYNC("File_writeBytes", FileWriteBytes);
116 REGISTER_SYNC("File_writeBase64", FileWriteBase64);
117 REGISTER_SYNC("File_writeString", FileWriteString);
118 REGISTER_SYNC("Filesystem_fetchAllStorages", FilesystemFetchAllStorages)
119 REGISTER_SYNC("FileSystemManager_addStorageStateChangeListener", StartListening);
120 REGISTER_SYNC("FileSystemManager_removeStorageStateChangeListener", StopListening);
121 REGISTER_SYNC("FileSystemManager_fetchStorages", FileSystemManagerFetchStorages);
122 REGISTER_SYNC("FileSystemManager_mkdir", FileSystemManagerMakeDirectory);
123 REGISTER_SYNC("FileSystemManager_mkdirSync", FileSystemManagerMakeDirectorySync);
124 REGISTER_SYNC("File_unlinkFile", UnlinkFile);
125 REGISTER_SYNC("File_removeDirectory", RemoveDirectory);
126 REGISTER_SYNC("File_copyTo", CopyTo);
127 REGISTER_SYNC("FileSystemManager_getCanonicalPath", FileSystemManagerGetCanonicalPath);
129 REGISTER_SYNC("FileSystemManager_openFile", FileSystemManagerOpenFile);
130 REGISTER_SYNC("FileSystemManager_createDirectory", FileSystemManagerCreateDirectory);
131 REGISTER_SYNC("FileSystemManager_deleteFile", FileSystemManagerDeleteFile);
132 REGISTER_SYNC("FileSystemManager_deleteDirectory", FileSystemManagerDeleteDirectory);
133 REGISTER_SYNC("FileSystemManager_copyFile", FileSystemManagerCopyFile);
134 REGISTER_SYNC("FileSystemManager_copyDirectory", FileSystemManagerCopyDirectory);
135 REGISTER_SYNC("FileSystemManager_moveFile", FileSystemManagerMoveFile);
136 REGISTER_SYNC("FileSystemManager_moveDirectory", FileSystemManagerMoveDirectory);
137 REGISTER_SYNC("FileSystemManager_rename", FileSystemManagerRename);
138 REGISTER_SYNC("FileSystemManager_listDirectory", FileSystemManagerListDirectory);
139 REGISTER_SYNC("FileSystemManager_isFile", FileSystemManagerIsFile);
140 REGISTER_SYNC("FileSystemManager_isDirectory", FileSystemManagerIsDirectory);
141 REGISTER_SYNC("FileSystemManager_pathExists", FileSystemManagerPathExists);
142 REGISTER_SYNC("FileSystemManager_getLimits", FileSystemManagerGetLimits);
144 REGISTER_SYNC("FileHandle_seek", FileHandleSeek);
145 REGISTER_SYNC("FileHandle_readString", FileHandleReadString);
146 REGISTER_SYNC("FileHandle_writeString", FileHandleWriteString);
147 REGISTER_SYNC("FileHandle_readData", FileHandleReadData);
148 REGISTER_SYNC("FileHandle_writeData", FileHandleWriteData);
149 REGISTER_SYNC("FileHandle_flush", FileHandleFlush);
150 REGISTER_SYNC("FileHandle_sync", FileHandleSync);
151 REGISTER_SYNC("FileHandle_close", FileHandleClose);
154 FilesystemManager::GetInstance().AddListener(this);
157 FilesystemInstance::~FilesystemInstance() {
160 FilesystemManager::GetInstance().StopListening();
161 FilesystemManager::GetInstance().RemoveListener();
164 #define CHECK_EXIST(args, name, out) \
165 if (!args.contains(name)) { \
166 LogAndReportError(TypeMismatchException(name " is required argument"), out); \
170 void FilesystemInstance::FileCreateSync(const picojson::value& args, picojson::object& out) {
173 "DEPRECATION WARNING: File.createFile() is deprecated since Tizen 5.0. Use "
174 "FileSystemManager.openFile() instead.");
176 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
177 CHECK_EXIST(args, "location", out)
178 const std::string& location = args.get("location").get<std::string>();
179 CHECK_STORAGE_ACCESS(location, &out);
181 auto onSuccess = [&](const FilesystemStat& data) {
182 ScopeLogger("Entered into asynchronous function, onSuccess");
183 ReportSuccess(data.toJSON(), out);
186 auto onError = [&](FilesystemError e) {
187 ScopeLogger("Entered into asynchronous function, onError");
188 PrepareError(e, out);
191 FilesystemManager::GetInstance().CreateFile(location, onSuccess, onError);
194 void FilesystemInstance::FileRename(const picojson::value& args, picojson::object& out) {
197 "DEPRECATION WARNING: File.moveTo() is deprecated since Tizen 5.0. Use "
198 "FileSystemManager.moveFile() or FileSystemManager.moveDirectory() instead.");
200 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
201 CHECK_EXIST(args, "callbackId", out)
203 CHECK_EXIST(args, "oldPath", out)
204 const std::string& oldPath = args.get("oldPath").get<std::string>();
205 CHECK_STORAGE_ACCESS(oldPath, &out);
206 CHECK_EXIST(args, "newPath", out)
207 const std::string& newPath = args.get("newPath").get<std::string>();
208 CHECK_STORAGE_ACCESS(newPath, &out);
210 double callback_id = args.get("callbackId").get<double>();
212 auto onSuccess = [this, callback_id](const FilesystemStat& data) {
213 ScopeLogger("Entered into asynchronous function, onSuccess");
214 picojson::value response = picojson::value(picojson::object());
215 picojson::object& obj = response.get<picojson::object>();
216 obj["callbackId"] = picojson::value(callback_id);
217 ReportSuccess(data.toJSON(), obj);
218 Instance::PostMessage(this, response.serialize().c_str());
221 auto onError = [this, callback_id](FilesystemError e) {
222 ScopeLogger("Entered into asynchronous function, onError");
223 picojson::value response = picojson::value(picojson::object());
224 picojson::object& obj = response.get<picojson::object>();
225 obj["callbackId"] = picojson::value(callback_id);
226 PrepareError(e, obj);
227 Instance::PostMessage(this, response.serialize().c_str());
230 FilesystemManager& fsm = FilesystemManager::GetInstance();
231 common::TaskQueue::GetInstance().Queue(
232 std::bind(&FilesystemManager::Rename, &fsm, oldPath, newPath, onSuccess, onError));
235 /* Write to str buf bytes as if they were UTF-8 codepoints */
236 static void encode_binary_in_string(const std::vector<std::uint8_t>& buf, std::string& str) {
238 str.reserve(str.size() + buf.size());
240 for (std::uint8_t byte : buf) {
245 str += 0xC0 | (byte >> 6);
246 str += 0x80 | (byte & 0x3F);
250 /* Decode (max 2-byte) UTF-8 characters to buf, throws std::runtime_error */
251 static void decode_binary_from_string(const std::string& str, std::vector<std::uint8_t>& buf) {
253 buf.reserve(buf.size() + str.size());
255 const std::uint8_t* it = (std::uint8_t*)str.data();
256 const std::uint8_t* end = it + str.size();
259 buf.push_back(*it++);
264 throw std::runtime_error("internal error (invalid UTF-8 sequence)");
267 unsigned int x = ((b1 & 0x1F) << 6) | (b2 & 0x3F);
273 static auto to_utf8 = &encode_binary_in_string;
274 /* It does not check if UTF-8 values are representable by ISO-8859-1. Make proper checks and
275 * substitute invalid characters in JavaScript before passing through crosswalk */
276 static auto from_utf8 = &decode_binary_from_string;
279 static constexpr std::size_t NPOS = (std::size_t)(-1);
282 * On failure throws std::system_error
284 static std::size_t file_size(FILE* file) {
288 int status = ::fstat(::fileno(file), &buf);
290 throw std::system_error{errno, std::generic_category(), "failed to get file size"};
297 * Returns the amount of bytes to the EOF starting from current file-position indicator.
299 * On failure throws std::system_error
301 static std::size_t file_bytes_to_eof(FILE* file) {
304 std::size_t total_fize_size = file_size(file);
305 long file_position = ftell(file);
306 if (-1 == file_position) {
307 throw std::system_error{errno, std::generic_category(),
308 "Failed to get file position"s + GetErrorString(errno)};
310 return total_fize_size - static_cast<size_t>(file_position);
313 static std::vector<std::uint8_t> read_file(FILE* file, std::size_t length = NPOS,
314 std::size_t* read_bytes = nullptr);
317 * Returns a buffer. If length is NPOS, then it reads whole file, up to the end.
318 * On failure throws std::runtime_error
320 static std::vector<std::uint8_t> read_file(std::string path, long offset = 0,
321 std::size_t length = NPOS) {
324 FILE* file = std::fopen(path.c_str(), "r");
326 std::string err_msg = std::string("Cannot open file to read. ") + GetErrorString(errno);
327 throw std::system_error{errno, std::generic_category(), err_msg};
331 int status = std::fclose(file);
333 LoggerE("Cannot close file!");
337 if (0 != offset && 0 != std::fseek(file, offset, SEEK_SET)) {
338 std::string err_msg = std::string("Cannot perform seek. ") + GetErrorString(errno);
339 throw std::system_error{errno, std::generic_category(), err_msg};
342 if (NPOS == length) {
343 length = file_size(file) - offset;
346 return read_file(file, length);
350 * Returns a buffer. If length is NPOS, then it reads whole file, up to the end.
351 * On failure throws std::runtime_error
353 static std::vector<std::uint8_t> read_file(FILE* file, std::size_t length /*= NPOS*/,
354 std::size_t* read_bytes /* = nullptr*/) {
357 // By default reads whole file. Get the file size.
358 if (NPOS == length) {
359 length = file_size(file);
362 std::vector<std::uint8_t> out_buf;
364 out_buf.resize(length);
365 } catch (std::bad_alloc& err) {
366 throw std::runtime_error{"Could not allocate memory"};
368 std::uint8_t* data_p = out_buf.data();
369 std::uint8_t* end_p = data_p + length;
370 while (data_p != end_p) {
371 data_p += std::fread(data_p, 1, end_p - data_p, file);
373 if (std::ferror(file)) {
374 std::string err_msg = std::string("Error during file read. ") + GetErrorString(errno);
375 throw std::runtime_error(err_msg);
378 if (std::feof(file)) {
379 LoggerD("File is at end before buffer is filled. Finish.");
383 // read_file function is used in API since version 1.0.
384 // read_bytes was added in Tizen 5.0, with default value equal to nullptr, the behaviour is not
386 // It is used to return the actual number of read bytes, because requested length might be bigger
387 // than possible bytes to be read.
388 if (nullptr != read_bytes) {
389 *read_bytes = std::distance(out_buf.data(), data_p);
395 * On failure throws std::runtime_error
397 void write_file(const std::uint8_t* data, std::size_t len, FILE* file) {
400 const std::uint8_t* data_p = data;
401 const std::uint8_t* end_p = data + len;
402 while (data_p != end_p) {
403 data_p += fwrite(data_p, 1, end_p - data_p, file);
405 if (std::ferror(file)) {
406 std::string err_msg = std::string("Error during file write. ") + GetErrorString(errno);
407 throw std::runtime_error(err_msg);
411 if (std::fflush(file)) {
412 std::string err_msg = std::string("Error during file write. ") + GetErrorString(errno);
413 throw std::runtime_error(err_msg);
418 * On failure throws std::runtime_error
420 void write_file(const std::uint8_t* data, std::size_t len, std::string path, long offset,
424 FILE* file = std::fopen(path.c_str(), mode);
427 std::string err_msg = std::string("Cannot open file to write. ") + GetErrorString(errno);
428 throw std::runtime_error(err_msg);
432 int status = std::fclose(file);
434 LoggerE("Cannot close file!");
438 if (offset != 0 && std::fseek(file, offset, SEEK_SET) != 0) {
439 std::string err_msg = std::string("Cannot perform seek. ") + GetErrorString(errno);
440 throw std::system_error{errno, std::generic_category(), err_msg};
443 write_file(data, len, file);
446 #define FIRST_BIT_MASK 0x80
447 #define SECOND_BIT_MASK 0x40
448 #define THIRD_BIT_MASK 0x20
449 #define FOURTH_BIT_MASK 0x10
450 #define FIFTH_BIT_MASK 0x08
452 enum class ByteOfUTF8Classification {
461 ByteOfUTF8Classification is_utf8_byte(uint8_t byte) {
462 if (FIRST_BIT_MASK & byte) {
463 if (SECOND_BIT_MASK & byte) {
464 if (THIRD_BIT_MASK & byte) {
465 if (FOURTH_BIT_MASK & byte) {
466 if (FIFTH_BIT_MASK & byte) {
467 return ByteOfUTF8Classification::NOT_VALID;
469 return ByteOfUTF8Classification::FIRST_OF_4_BYTES;
472 return ByteOfUTF8Classification::FIRST_OF_3_BYTES;
475 return ByteOfUTF8Classification::FIRST_OF_2_BYTES;
478 return ByteOfUTF8Classification::EXTENSION_BYTE;
481 return ByteOfUTF8Classification::ONE_BYTE_CHAR;
485 void skip_partial_character(std::vector<std::uint8_t>& buf) {
486 auto buf_position = buf.begin();
488 while (buf.end() != buf_position &&
489 (ByteOfUTF8Classification::EXTENSION_BYTE == is_utf8_byte(*buf_position))) {
490 buf_position = buf.erase(buf_position);
491 LoggerD("Removed UTF-8 Extension Byte from begining of read buffer");
495 bool validate_and_check_character_count(std::vector<std::uint8_t>& buf, unsigned long& char_count,
496 short& no_of_extensions_expected) {
499 no_of_extensions_expected = 0;
500 auto buf_position = buf.begin();
502 skip_partial_character(buf);
504 while (buf.end() != buf_position) {
505 switch (is_utf8_byte(*buf_position)) {
506 case ByteOfUTF8Classification::EXTENSION_BYTE:
507 no_of_extensions_expected--;
508 if (0 > no_of_extensions_expected) {
510 } else if (0 == no_of_extensions_expected) {
514 case ByteOfUTF8Classification::ONE_BYTE_CHAR:
515 if (0 != no_of_extensions_expected) {
520 case ByteOfUTF8Classification::FIRST_OF_2_BYTES:
521 if (0 != no_of_extensions_expected) {
524 no_of_extensions_expected = 1;
526 case ByteOfUTF8Classification::FIRST_OF_3_BYTES:
527 if (0 != no_of_extensions_expected) {
530 no_of_extensions_expected = 2;
532 case ByteOfUTF8Classification::FIRST_OF_4_BYTES:
533 if (0 != no_of_extensions_expected) {
536 no_of_extensions_expected = 3;
538 case ByteOfUTF8Classification::NOT_VALID:
541 LoggerE("Abnormal value returned from is_utf8_byte function");
549 * add_utf8_chars_to_buffer
550 * Method returns false if byte read is not a valid utf8 char
552 bool add_utf8_chars_to_buffer(FILE* file, std::vector<std::uint8_t>& buf, int chars_to_read,
553 short& extension_bytes_expected) {
555 LoggerD("chars_to_read: %i", chars_to_read);
556 LoggerD("extension_bytes_expected: %i", extension_bytes_expected);
557 while (chars_to_read) {
558 if (extension_bytes_expected) {
559 character = getc(file);
560 if (EOF == character) {
563 buf.push_back(character);
564 if (!--extension_bytes_expected) {
569 character = getc(file);
570 if (EOF == character) {
573 buf.push_back(character);
574 switch (is_utf8_byte(character)) {
575 case ByteOfUTF8Classification::ONE_BYTE_CHAR:
578 case ByteOfUTF8Classification::FIRST_OF_2_BYTES:
579 extension_bytes_expected = 1;
581 case ByteOfUTF8Classification::FIRST_OF_3_BYTES:
582 extension_bytes_expected = 2;
584 case ByteOfUTF8Classification::FIRST_OF_4_BYTES:
585 extension_bytes_expected = 3;
587 case ByteOfUTF8Classification::EXTENSION_BYTE:
588 LoggerD("unexpected EXTENSION_BYTE");
590 case ByteOfUTF8Classification::NOT_VALID:
591 LoggerE("unexpected NOT_VALID byte while reading utf-8");
594 LoggerE("Abnormal. Last read char: %c: ", character);
602 static const char int_to_char[] =
603 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
604 static const std::uint8_t INV = 255;
605 static const std::uint8_t PAD = 254;
606 static const std::uint8_t char_to_int[] = {
607 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
608 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
609 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60,
610 61, 255, 255, 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
611 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255,
612 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
613 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
614 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
615 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
616 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
617 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
618 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
619 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
620 255, 255, 255, 255, 255, 255, 255, 255, 255};
623 * On error throws std::runtime_error
625 static std::vector<std::uint8_t> decode(const char* str, std::size_t len) {
626 std::vector<std::uint8_t> out;
627 if (len % 4 != 0) throw std::runtime_error("string length is not multiple of 4");
628 if (len == 0) return out;
630 const std::uint8_t* p = (std::uint8_t*)str;
631 const std::uint8_t* end = p + len - 4; // last four can have padding in it
632 std::uint8_t b1, b2, b3, b4;
633 out.reserve(len / 4 * 3);
635 b1 = char_to_int[*p++];
636 b2 = char_to_int[*p++];
637 b3 = char_to_int[*p++];
638 b4 = char_to_int[*p++];
640 if (b1 > 63 || b2 > 63 || b3 > 63 || b4 > 63) throw std::runtime_error("invalid character");
642 out.push_back((b1 << 2) | (b2 >> 4));
643 out.push_back((b2 << 4) | (b3 >> 2));
644 out.push_back((b3 << 6) | b4);
646 b1 = char_to_int[*p++];
647 b2 = char_to_int[*p++];
648 b3 = char_to_int[*p++];
649 b4 = char_to_int[*p++];
651 if (b1 == PAD || b1 == INV || b2 == PAD || b2 == INV || b3 == INV || b4 == INV)
652 throw std::runtime_error("invalid character");
654 out.push_back((b1 << 2) | (b2 >> 4));
656 if (b4 != PAD) throw std::runtime_error("invalid character");
658 out.push_back((b2 << 4) | (b3 >> 2));
659 if (b4 != PAD) out.push_back((b3 << 6) | b4);
664 } // namespace base64
666 void FilesystemInstance::FileReadString(const picojson::value& args, picojson::object& out) {
669 "DEPRECATION WARNING: This method is deprecated since Tizen 5.0.Use FileHandle.readString() "
670 "or FileHandle.readStringNonBlocking() instead.");
672 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
673 CHECK_EXIST(args, "location", out)
674 CHECK_EXIST(args, "offset", out)
676 const std::string& location = args.get("location").get<std::string>();
677 size_t offset = static_cast<size_t>(args.get("offset").get<double>());
678 size_t length = args.contains("length") ? (size_t)args.get("length").get<double>() : NPOS;
679 const std::string& encoding =
680 args.contains("encoding") ? args.get("encoding").get<std::string>() : "utf-8";
683 std::vector<std::uint8_t> buf = read_file(location, offset, length);
685 if (encoding == "iso-8859-1") {
686 out["result"] = picojson::value(picojson::string_type, true);
687 latin1::to_utf8(buf, out["result"].get<std::string>());
689 } else { // default: UTF-8
691 const char* str = (const char*)buf.data();
692 ReportSuccess(picojson::value{str}, out);
694 } catch (std::runtime_error& e) {
695 LoggerE("Cannot read file %s, cause: %s", location.c_str(), e.what());
696 PrepareError(FilesystemError::Other, out);
700 void FilesystemInstance::FileReadBytes(const picojson::value& args, picojson::object& out) {
703 "DEPRECATION WARNING: This method is deprecated since Tizen 5.0. Use FileHandle.readData() "
704 "or FileHandle.readDataNonBlocking() instead.");
706 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
707 CHECK_EXIST(args, "location", out)
708 CHECK_EXIST(args, "offset", out)
709 CHECK_EXIST(args, "length", out)
711 const std::string& location = args.get("location").get<std::string>();
712 size_t offset = static_cast<size_t>(args.get("offset").get<double>());
713 size_t length = static_cast<size_t>(args.get("length").get<double>());
716 std::vector<std::uint8_t> out_data = read_file(location, offset, length);
718 out["result"] = picojson::value(picojson::string_type, true);
719 encode_binary_in_string(out_data, out["result"].get<std::string>());
721 } catch (std::runtime_error& e) {
722 LoggerE("Cannot read file %s, cause: %s", location.c_str(), e.what());
723 PrepareError(FilesystemError::Other, out);
727 void FilesystemInstance::FileWriteString(const picojson::value& args, picojson::object& out) {
730 "DEPRECATION WARNING: FileStream.write() is deprecated since Tizen 5.0. Use "
731 "FileHandle.writeString() or FileHandle.writeStringNonBlocking() instead.");
733 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
734 CHECK_EXIST(args, "location", out)
735 CHECK_EXIST(args, "data", out)
736 CHECK_EXIST(args, "offset", out)
737 CHECK_EXIST(args, "truncate", out)
739 const std::string& location = args.get("location").get<std::string>();
740 const std::string& str = args.get("data").get<std::string>();
741 size_t offset = static_cast<size_t>(args.get("offset").get<double>());
742 bool truncate = static_cast<bool>(args.get("truncate").get<bool>());
743 const char* mode = truncate ? "w" : "r+";
744 const std::string& encoding =
745 args.contains("encoding") ? args.get("encoding").get<std::string>() : "utf-8";
748 if (encoding == "iso-8859-1") {
749 std::vector<std::uint8_t> data;
750 latin1::from_utf8(str, data);
751 write_file(data.data(), data.size(), location, offset, mode);
752 } else { // default: UTF-8
753 const std::uint8_t* buf = (const std::uint8_t*)str.c_str();
754 std::size_t len = str.length();
755 write_file(buf, len, location, offset, mode);
757 } catch (std::runtime_error& e) {
758 LoggerE("Cannot write to file %s, cause: %s", location.c_str(), e.what());
759 PrepareError(FilesystemError::Other, out);
766 void FilesystemInstance::FileWriteBytes(const picojson::value& args, picojson::object& out) {
769 "DEPRECATION WARNING: FileStream.writeBytes() is deprecated since Tizen 5.0. To read and Use "
770 "FileHandle.writeData() or FileHandle.writeDataNonBlocking() instead.");
772 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
773 CHECK_EXIST(args, "location", out)
774 CHECK_EXIST(args, "data", out)
775 CHECK_EXIST(args, "offset", out)
776 CHECK_EXIST(args, "truncate", out)
778 const std::string& location = args.get("location").get<std::string>();
779 const std::string& str = args.get("data").get<std::string>();
780 size_t offset = static_cast<size_t>(args.get("offset").get<double>());
781 bool truncate = static_cast<bool>(args.get("truncate").get<bool>());
782 const char* mode = truncate ? "w" : "r+";
785 std::vector<std::uint8_t> data;
786 decode_binary_from_string(str, data);
787 write_file(data.data(), data.size(), location, offset, mode);
788 } catch (std::runtime_error& e) {
789 LoggerE("Cannot write to %s, cause: %s", location.c_str(), e.what());
790 PrepareError(FilesystemError::Other, out);
797 void FilesystemInstance::FileWriteBase64(const picojson::value& args, picojson::object& out) {
800 "DEPRECATION WARNING: FileStream.writeBase64() is deprecated since Tizen 5.0. Use "
801 "FileHandle.writeData() or FileHandle.writeDataNonBlocking() in combination with atob() and "
802 "btoa() functions instead.");
804 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
805 CHECK_EXIST(args, "location", out)
806 CHECK_EXIST(args, "data", out)
807 CHECK_EXIST(args, "offset", out)
808 CHECK_EXIST(args, "truncate", out)
810 const std::string& location = args.get("location").get<std::string>();
811 const std::string& str = args.get("data").get<std::string>();
812 size_t offset = static_cast<size_t>(args.get("offset").get<double>());
813 bool truncate = static_cast<bool>(args.get("truncate").get<bool>());
814 const char* mode = truncate ? "w" : "r+";
816 std::vector<std::uint8_t> data;
818 data = base64::decode(str.c_str(), str.length());
819 } catch (std::runtime_error& e) {
820 LoggerE("Can't decode base64: %s", e.what());
821 ReportError(InvalidValuesException(std::string("Can't decode base64: ") + e.what()), out);
826 write_file(data.data(), data.size(), location, offset, mode);
827 ReportSuccess(picojson::value{(double)data.size()}, out);
828 } catch (std::runtime_error& e) {
829 LoggerE("Cannot write to %s, cause: %s", location.c_str(), e.what());
830 PrepareError(FilesystemError::Other, out);
834 void FilesystemInstance::FileStat(const picojson::value& args, picojson::object& out) {
836 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
837 CHECK_EXIST(args, "location", out)
838 const std::string& location = args.get("location").get<std::string>();
839 CHECK_STORAGE_ACCESS(location, &out);
841 CHECK_EXIST(args, "callbackId", out)
842 double callback_id = args.get("callbackId").get<double>();
844 auto onSuccess = [this, callback_id](const FilesystemStat& data) {
845 ScopeLogger("Entered into asynchronous function, onSuccess");
846 picojson::value response = picojson::value(picojson::object());
847 picojson::object& obj = response.get<picojson::object>();
848 obj["callbackId"] = picojson::value(callback_id);
849 ReportSuccess(data.toJSON(), obj);
850 Instance::PostMessage(this, response.serialize().c_str());
853 auto onError = [this, callback_id](FilesystemError e) {
854 ScopeLogger("Entered into asynchronous function, onError");
855 picojson::value response = picojson::value(picojson::object());
856 picojson::object& obj = response.get<picojson::object>();
857 obj["callbackId"] = picojson::value(callback_id);
858 PrepareError(e, obj);
859 Instance::PostMessage(this, response.serialize().c_str());
862 FilesystemManager& fsm = FilesystemManager::GetInstance();
863 common::TaskQueue::GetInstance().Async(
864 std::bind(&FilesystemManager::StatPath, &fsm, location, onSuccess, onError));
867 void FilesystemInstance::FileStatSync(const picojson::value& args, picojson::object& out) {
869 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
870 CHECK_EXIST(args, "location", out)
871 const std::string& location = args.get("location").get<std::string>();
872 CHECK_STORAGE_ACCESS(location, &out);
874 auto onSuccess = [&](const FilesystemStat& data) {
875 ScopeLogger("Entered into asynchronous function, onSuccess");
876 ReportSuccess(data.toJSON(), out);
879 auto onError = [&](FilesystemError e) {
880 ScopeLogger("Entered into asynchronous function, onError");
881 PrepareError(e, out);
884 FilesystemManager::GetInstance().StatPath(location, onSuccess, onError);
887 void FilesystemInstance::FilesystemFetchAllStorages(const picojson::value& args,
888 picojson::object& out) {
891 auto onSuccess = [&](const common::VirtualStorages& result) {
892 ScopeLogger("Entered into asynchronous function, onSuccess");
893 picojson::array roots;
894 for (const auto& root : result) {
895 roots.push_back(root->ToJson());
897 ReportSuccess(picojson::value(roots), out);
900 auto onError = [&](FilesystemError e) {
901 ScopeLogger("Entered into asynchronous function, onError");
902 PrepareError(e, out);
905 FilesystemManager::GetInstance().FetchAllStorages(onSuccess, onError);
908 void FilesystemInstance::FileSystemManagerFetchStorages(const picojson::value& args,
909 picojson::object& out) {
912 auto onSuccess = [&](const common::Storages& result) {
913 ScopeLogger("Entered into asynchronous function, onSuccess");
914 picojson::array storages;
915 storages.reserve(result.size());
916 for (const auto storage : result) {
917 storages.push_back(storage->ToJson());
919 ReportSuccess(picojson::value(storages), out);
922 auto onError = [&](FilesystemError e) {
923 ScopeLogger("Entered into asynchronous function, onError");
924 PrepareError(e, out);
927 FilesystemManager::GetInstance().FetchStorages(onSuccess, onError);
929 void FilesystemInstance::StartListening(const picojson::value& args, picojson::object& out) {
931 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
932 FilesystemManager::GetInstance().StartListening();
936 void FilesystemInstance::StopListening(const picojson::value& args, picojson::object& out) {
938 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
939 FilesystemManager::GetInstance().StopListening();
943 void FilesystemInstance::onFilesystemStateChangeSuccessCallback(const common::Storage& storage) {
946 picojson::value event = picojson::value(picojson::object());
947 picojson::object& obj = event.get<picojson::object>();
948 obj["label"] = picojson::value(storage.name_);
949 obj["type"] = picojson::value(common::Storage::ToString(storage.type()));
950 obj["state"] = picojson::value(common::Storage::ToString(storage.state()));
951 obj["listenerId"] = picojson::value("StorageStateChangeListener");
952 Instance::PostMessage(this, event.serialize().c_str());
955 void FilesystemInstance::onFilesystemStateChangeErrorCallback() {
957 picojson::value event = picojson::value(picojson::object());
958 picojson::object& obj = event.get<picojson::object>();
959 LogAndReportError(UnknownException(std::string("Failed to registerd listener")), obj);
960 obj["listenerId"] = picojson::value("StorageStateChangeListener");
961 LoggerD("Posting: %s", event.serialize().c_str());
962 Instance::PostMessage(this, event.serialize().c_str());
965 void FilesystemInstance::FileSystemManagerMakeDirectory(const picojson::value& args,
966 picojson::object& out) {
968 CHECK_EXIST(args, "callbackId", out)
969 CHECK_EXIST(args, "location", out)
971 double callback_id = args.get("callbackId").get<double>();
972 const std::string& location = args.get("location").get<std::string>();
974 auto onResult = [this, callback_id](FilesystemError e) {
975 ScopeLogger("Entered into asynchronous function, onResult");
976 picojson::value response = picojson::value(picojson::object());
977 picojson::object& obj = response.get<picojson::object>();
978 obj["callbackId"] = picojson::value(callback_id);
979 if (e == FilesystemError::DirectoryExists)
982 PrepareError(e, obj);
983 Instance::PostMessage(this, response.serialize().c_str());
986 auto onAction = [location, onResult]() {
987 ScopeLogger("Entered into asynchronous function, onAction");
988 FilesystemManager::GetInstance().MakeDirectory(location, onResult);
991 common::TaskQueue::GetInstance().Async(onAction);
994 void FilesystemInstance::FileSystemManagerMakeDirectorySync(const picojson::value& args,
995 picojson::object& out) {
998 "DEPRECATION WARNING: File.createDirectory() is deprecated since Tizen 5.0. Use "
999 "FileSystemManager.createDirectory() instead.");
1001 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1002 CHECK_EXIST(args, "location", out)
1003 const std::string& location = args.get("location").get<std::string>();
1004 CHECK_STORAGE_ACCESS(location, &out);
1006 auto onResult = [&](FilesystemError e) {
1007 ScopeLogger("Entered into asynchronous function, onResult");
1008 if (e == FilesystemError::DirectoryExists)
1011 PrepareError(e, out);
1014 FilesystemManager::GetInstance().MakeDirectory(location, onResult);
1017 void FilesystemInstance::ReadDir(const picojson::value& args, picojson::object& out) {
1020 "DEPRECATION WARNING: File.listFiles() is deprecated since Tizen 5.0. Use "
1021 "FileSystemManager.listDirectory() instead.");
1023 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1024 CHECK_EXIST(args, "pathToDir", out)
1025 CHECK_EXIST(args, "callbackId", out)
1027 double callback_id = args.get("callbackId").get<double>();
1028 const std::string& pathToDir = args.get("pathToDir").get<std::string>();
1030 auto onSuccess = [this, callback_id](const std::vector<std::string>& paths) {
1031 ScopeLogger("Entered into asynchronous function, onSuccess");
1032 picojson::value result = picojson::value(picojson::array());
1034 picojson::array& statPaths = result.get<picojson::array>();
1035 picojson::value response = picojson::value(picojson::object());
1036 picojson::object& obj = response.get<picojson::object>();
1037 obj["callbackId"] = picojson::value(callback_id);
1038 for (auto path : paths) {
1039 FilesystemStat stat = FilesystemStat::getStat(path);
1041 if (FilesystemError::None == stat.error) {
1042 statPaths.push_back(stat.toJSON());
1044 LoggerW("File stat for path: %s failed with error: %d. Ignoring this entry.", path.c_str(),
1045 static_cast<std::underlying_type<FilesystemError>::type>(stat.error));
1048 ReportSuccess(result, obj);
1049 Instance::PostMessage(this, response.serialize().c_str());
1052 auto onError = [this, callback_id](FilesystemError e) {
1053 ScopeLogger("Entered into asynchronous function, onError");
1054 picojson::value response = picojson::value(picojson::object());
1055 picojson::object& obj = response.get<picojson::object>();
1056 obj["callbackId"] = picojson::value(callback_id);
1057 PrepareError(e, obj);
1058 Instance::PostMessage(this, response.serialize().c_str());
1061 FilesystemManager& fm = FilesystemManager::GetInstance();
1062 common::TaskQueue::GetInstance().Async(
1063 std::bind(&FilesystemManager::ReadDir, &fm, pathToDir, onSuccess, onError));
1066 void FilesystemInstance::UnlinkFile(const picojson::value& args, picojson::object& out) {
1069 "DEPRECATION WARNING: File.deleteFile() is deprecated since Tizen 5.0. Use "
1070 "FileSystemManager.deleteFile() instead.");
1072 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1073 CHECK_EXIST(args, "pathToFile", out)
1074 double callback_id = args.get("callbackId").get<double>();
1075 const std::string& pathToFile = args.get("pathToFile").get<std::string>();
1076 CHECK_STORAGE_ACCESS(pathToFile, &out);
1078 auto onSuccess = [this, callback_id]() {
1079 ScopeLogger("Entered into asynchronous function, onSuccess");
1080 picojson::value result = picojson::value();
1081 picojson::value response = picojson::value(picojson::object());
1082 picojson::object& obj = response.get<picojson::object>();
1083 obj["callbackId"] = picojson::value(callback_id);
1084 ReportSuccess(result, obj);
1085 Instance::PostMessage(this, response.serialize().c_str());
1088 auto onError = [this, callback_id](FilesystemError e) {
1089 ScopeLogger("Entered into asynchronous function, onError");
1090 picojson::value response = picojson::value(picojson::object());
1091 picojson::object& obj = response.get<picojson::object>();
1092 obj["callbackId"] = picojson::value(callback_id);
1093 PrepareError(e, obj);
1094 Instance::PostMessage(this, response.serialize().c_str());
1097 FilesystemManager& fm = FilesystemManager::GetInstance();
1098 common::TaskQueue::GetInstance().Async(
1099 std::bind(&FilesystemManager::UnlinkFile, &fm, pathToFile, onSuccess, onError));
1102 void FilesystemInstance::RemoveDirectory(const picojson::value& args, picojson::object& out) {
1105 "DEPRECATION WARNING: File.deleteDirectory() is deprecated since Tizen 5.0. Use "
1106 "FileSystemManager.deleteDirectory() instead.");
1108 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1109 CHECK_EXIST(args, "pathToDelete", out)
1110 double callback_id = args.get("callbackId").get<double>();
1111 const std::string& pathToDelete = args.get("pathToDelete").get<std::string>();
1112 CHECK_STORAGE_ACCESS(pathToDelete, &out);
1114 auto onSuccess = [this, callback_id]() {
1115 ScopeLogger("Entered into asynchronous function, onSuccess");
1116 picojson::value result = picojson::value();
1117 picojson::value response = picojson::value(picojson::object());
1118 picojson::object& obj = response.get<picojson::object>();
1119 obj["callbackId"] = picojson::value(callback_id);
1120 ReportSuccess(result, obj);
1121 Instance::PostMessage(this, response.serialize().c_str());
1124 auto onError = [this, callback_id](FilesystemError e) {
1125 ScopeLogger("Entered into asynchronous function, onError");
1126 picojson::value response = picojson::value(picojson::object());
1127 picojson::object& obj = response.get<picojson::object>();
1128 obj["callbackId"] = picojson::value(callback_id);
1129 PrepareError(e, obj);
1130 Instance::PostMessage(this, response.serialize().c_str());
1133 FilesystemManager& fm = FilesystemManager::GetInstance();
1134 common::TaskQueue::GetInstance().Queue(
1135 std::bind(&FilesystemManager::RemoveDirectory, &fm, pathToDelete, onSuccess, onError));
1138 void FilesystemInstance::CopyTo(const picojson::value& args, picojson::object& out) {
1141 "DEPRECATION WARNING: File.copyTo() is deprecated since Tizen 5.0. Use "
1142 "FileSystemManager.CopyFile() or FileSystemManager.CopyDirectory() instead.");
1144 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1145 CHECK_EXIST(args, "callbackId", out)
1147 CHECK_EXIST(args, "originFilePath", out)
1148 const std::string& originPath = args.get("originFilePath").get<std::string>();
1149 CHECK_STORAGE_ACCESS(originPath, &out);
1150 CHECK_EXIST(args, "destinationFilePath", out)
1151 const std::string& destinationPath = args.get("destinationFilePath").get<std::string>();
1152 CHECK_STORAGE_ACCESS(destinationPath, &out);
1154 CHECK_EXIST(args, "overwrite", out)
1156 double callback_id = args.get("callbackId").get<double>();
1157 const bool& overwrite = args.get("overwrite").get<bool>();
1159 auto onSuccess = [this, callback_id]() {
1160 ScopeLogger("Entered into asynchronous function, onSuccess");
1161 picojson::value result = picojson::value();
1162 picojson::value response = picojson::value(picojson::object());
1163 picojson::object& obj = response.get<picojson::object>();
1164 obj["callbackId"] = picojson::value(callback_id);
1165 ReportSuccess(result, obj);
1166 Instance::PostMessage(this, response.serialize().c_str());
1169 auto onError = [this, callback_id](FilesystemError e) {
1170 ScopeLogger("Entered into asynchronous function, onError");
1171 picojson::value response = picojson::value(picojson::object());
1172 picojson::object& obj = response.get<picojson::object>();
1173 obj["callbackId"] = picojson::value(callback_id);
1174 PrepareError(e, obj);
1175 Instance::PostMessage(this, response.serialize().c_str());
1178 FilesystemManager& fm = FilesystemManager::GetInstance();
1179 common::TaskQueue::GetInstance().Queue(std::bind(&FilesystemManager::CopyTo, &fm, originPath,
1180 destinationPath, overwrite, onSuccess, onError));
1183 void FilesystemInstance::PrepareError(const FilesystemError& error, picojson::object& out) {
1186 case FilesystemError::None:
1187 LogAndReportError(UnknownException("PLATFORM ERROR"), out);
1189 case FilesystemError::NotFound:
1190 LogAndReportError(NotFoundException("PLATFORM ERROR"), out,
1191 ("NotFoundException - PLATFORM ERROR"));
1193 case FilesystemError::FileExists:
1194 LogAndReportError(IOException("File already exists"), out,
1195 ("IOException - File already exists"));
1197 case FilesystemError::DirectoryExists:
1198 LogAndReportError(IOException("Directory already exists"), out,
1199 ("IOException - Directory already exists"));
1201 case FilesystemError::PermissionDenied:
1202 LogAndReportError(IOException("Permission denied"), out, ("IOException - Permission denied"));
1204 case FilesystemError::IOError:
1205 LogAndReportError(IOException("IO Error"), out, ("IOException - IO Error"));
1207 case FilesystemError::Other:
1208 LogAndReportError(UnknownException("PLATFORM ERROR other"), out,
1209 ("UnknownException - PLATFORM ERROR other"));
1211 case FilesystemError::InvalidValue:
1212 LogAndReportError(InvalidValuesException("PLATFORM ERROR"), out,
1213 ("InvalidValuesException - PLATFORM ERROR"));
1216 LogAndReportError(UnknownException("PLATFORM ERROR default"), out,
1217 ("UnknownException - PLATFORM ERROR default"));
1222 void FilesystemInstance::FileSystemManagerGetCanonicalPath(const picojson::value& args,
1223 picojson::object& out) {
1225 // TODO: any privilege needed?
1226 CHECK_EXIST(args, "path", out);
1228 const std::string& path = args.get("path").get<std::string>();
1230 auto onSuccess = [&](const std::string& canonicalPath) {
1231 ScopeLogger("Entered into asynchronous function, onSuccess");
1232 ReportSuccess(picojson::value(canonicalPath), out);
1235 auto onError = [&](FilesystemError e) {
1236 ScopeLogger("Entered into asynchronous function, onError");
1237 PrepareError(e, out);
1240 FilesystemManager::GetInstance().GetCanonicalPath(path, onSuccess, onError);
1245 FILE* OpenFile(const std::string& path, const std::string& fopen_mode) {
1246 FILE* file = std::fopen(path.c_str(), fopen_mode.c_str());
1248 throw std::system_error{errno, std::generic_category(), "Could not open file"};
1254 FILE* MakeParentsAndOpenFile(const std::string& path, const std::string& fopen_mode) {
1256 * If fopen fails, created parent directories have to be removed.
1257 * Save the path to the first nonexistent parent directory in the file path,
1258 * to know where to start recursive removal
1260 std::string first_nonexistent_parent = FilesystemUtils::Dirname(path);
1264 !FilesystemUtils::CheckIfExists(FilesystemUtils::Dirname(first_nonexistent_parent), &buf)) {
1265 first_nonexistent_parent = FilesystemUtils::Dirname(first_nonexistent_parent);
1268 FilesystemUtils::Mkdir(FilesystemUtils::Dirname(path), true);
1270 FILE* file = std::fopen(path.c_str(), fopen_mode.c_str());
1275 std::system_error fopen_error =
1276 std::system_error(errno, std::generic_category(), "Could not open file");
1279 FilesystemUtils::RemoveDirectoryRecursively(first_nonexistent_parent);
1280 } catch (const std::system_error& error) {
1281 LoggerD("Failed to remove created parent directories: %s", error.what());
1289 void FilesystemInstance::FileSystemManagerOpenFile(const picojson::value& args,
1290 picojson::object& out) {
1292 const int unique_id = static_cast<int>(args.get("id").get<double>());
1293 if (opened_files.find(unique_id) != opened_files.end()) {
1294 LogAndReportError(IOException("Internal error (id is already in use)"), out);
1298 bool access_checked = false;
1299 if (WriteAccessRequested(args)) {
1300 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1301 access_checked = true;
1304 if (ReadAccessRequested(args)) {
1305 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1306 access_checked = true;
1309 // File open mode received from JS layer can be different than expected by
1310 // WriteAccessRequested and ReadAccessRequested functions. In case like that
1311 // privilege would not be checked and user could gain unauthorized access to file.
1312 // To prevent this situation we only accept specific open modes.
1313 if (false == access_checked) {
1314 const std::string& open_mode = args.get("openMode").get<std::string>();
1315 LogAndReportError(TypeMismatchException("Invalid open mode: " + open_mode), out);
1319 const std::string& path = args.get("path").get<std::string>();
1321 CHECK_STORAGE_ACCESS(path, &out);
1322 const std::string open_mode = GetFopenMode(args);
1323 FILE* file = nullptr;
1325 if (ShouldMakeParents(args)) {
1326 file = MakeParentsAndOpenFile(path, open_mode);
1328 file = OpenFile(path, open_mode);
1330 } catch (const std::system_error& error) {
1331 FilesystemUtils::TranslateException(error, out);
1335 opened_files.emplace(std::make_pair(unique_id, std::make_shared<FileHandle>(file)));
1339 void FilesystemInstance::FileSystemManagerCreateDirectory(const picojson::value& args,
1340 picojson::object& out) {
1342 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1344 double callback_id = args.get("callbackId").get<double>();
1345 const std::string& path = args.get("path").get<std::string>();
1346 bool make_parents = args.get("makeParents").get<bool>();
1347 CHECK_STORAGE_ACCESS(path, &out);
1349 common::TaskQueue::GetInstance().Async([this, callback_id, path, make_parents] {
1350 picojson::value response = picojson::value(picojson::object());
1351 picojson::object& obj = response.get<picojson::object>();
1352 obj["callbackId"] = picojson::value(callback_id);
1355 FilesystemUtils::Mkdir(path, make_parents);
1356 ReportSuccess(picojson::value(path), obj);
1357 } catch (const std::system_error& e) {
1358 FilesystemUtils::TranslateException(e, obj);
1360 this->PostMessage(response.serialize().c_str());
1366 void FilesystemInstance::FileSystemManagerDeleteFile(const picojson::value& args,
1367 picojson::object& out) {
1369 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1371 double callback_id = args.get("callbackId").get<double>();
1372 const std::string& path = args.get("path").get<std::string>();
1374 CHECK_STORAGE_ACCESS(path, &out);
1375 common::TaskQueue::GetInstance().Async([this, callback_id, path] {
1376 picojson::value response = picojson::value(picojson::object());
1377 picojson::object& obj = response.get<picojson::object>();
1378 obj["callbackId"] = picojson::value(callback_id);
1380 this->PostMessage(response.serialize().c_str());
1385 if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfFile(buf)) {
1386 LogAndReportError(NotFoundException("Given path does not point to file."), obj);
1389 FilesystemUtils::Unlink(path);
1390 ReportSuccess(picojson::value(FilesystemUtils::Dirname(path)), obj);
1391 } catch (const std::system_error& e) {
1392 FilesystemUtils::TranslateException(e, obj);
1399 void FilesystemInstance::FileSystemManagerDeleteDirectory(const picojson::value& args,
1400 picojson::object& out) {
1402 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1404 double callback_id = args.get("callbackId").get<double>();
1405 const std::string& path = args.get("path").get<std::string>();
1407 CHECK_STORAGE_ACCESS(path, &out);
1408 bool recursive = args.get("recursive").get<bool>();
1410 common::TaskQueue::GetInstance().Queue([this, callback_id, path, recursive] {
1412 picojson::value response = picojson::value(picojson::object());
1413 picojson::object& obj = response.get<picojson::object>();
1414 obj["callbackId"] = picojson::value(callback_id);
1416 this->PostMessage(response.serialize().c_str());
1421 if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfDir(buf)) {
1422 LogAndReportError(NotFoundException("Given path does not point to directory."), obj);
1426 FilesystemUtils::RemoveDirectoryRecursively(path);
1428 FilesystemUtils::RemoveDirectory(path);
1430 ReportSuccess(picojson::value(FilesystemUtils::Dirname(path)), obj);
1431 } catch (const std::system_error& e) {
1432 FilesystemUtils::TranslateException(e, obj);
1439 void FilesystemInstance::FileSystemManagerCopyFile(const picojson::value& args,
1440 picojson::object& out) {
1442 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1443 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1445 double callback_id = args.get("callbackId").get<double>();
1446 const std::string& path = args.get("path").get<std::string>();
1447 CHECK_STORAGE_ACCESS(path, &out);
1448 const std::string& destination_path = args.get("destinationPath").get<std::string>();
1449 CHECK_STORAGE_ACCESS(destination_path, &out);
1450 bool overwrite = args.get("overwrite").get<bool>();
1452 common::TaskQueue::GetInstance().Queue([this, callback_id, path, destination_path, overwrite] {
1453 picojson::value response = picojson::value(picojson::object());
1454 picojson::object& obj = response.get<picojson::object>();
1455 obj["callbackId"] = picojson::value(callback_id);
1457 this->PostMessage(response.serialize().c_str());
1462 if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfFile(buf)) {
1463 LogAndReportError(NotFoundException("Given path does not point to file."), obj);
1467 if (FilesystemUtils::CheckIfExists(destination_path, &buf) && !overwrite) {
1469 IOException("Given path points to an existing resource, overwriting is not allowed."),
1473 FilesystemUtils::CopyFile(path, destination_path, overwrite);
1474 ReportSuccess(picojson::value(destination_path), obj);
1475 } catch (const std::system_error& e) {
1476 FilesystemUtils::TranslateException(e, obj);
1483 void FilesystemInstance::FileSystemManagerCopyDirectory(const picojson::value& args,
1484 picojson::object& out) {
1486 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1487 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1488 const std::string& path = args.get("path").get<std::string>();
1489 CHECK_STORAGE_ACCESS(path, &out);
1490 const std::string& destination_path = args.get("destinationPath").get<std::string>();
1491 CHECK_STORAGE_ACCESS(destination_path, &out);
1492 double callback_id = args.get("callbackId").get<double>();
1493 bool overwrite = args.get("overwrite").get<bool>();
1495 common::TaskQueue::GetInstance().Queue([this, callback_id, path, destination_path, overwrite] {
1497 picojson::value response = picojson::value(picojson::object());
1498 picojson::object& obj = response.get<picojson::object>();
1499 obj["callbackId"] = picojson::value(callback_id);
1501 this->PostMessage(response.serialize().c_str());
1506 if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfDir(buf)) {
1507 LogAndReportError(NotFoundException("Given path does not point to directory."), obj);
1511 bool exists = FilesystemUtils::CheckIfExists(destination_path, &buf);
1512 if (exists && !FilesystemUtils::CheckIfDir(buf)) {
1513 LogAndReportError(IOException("File with conflicting name already exists."), obj);
1515 } else if (!exists) {
1516 FilesystemUtils::Mkdir(destination_path);
1518 FilesystemUtils::CopyDirectory(path, destination_path, overwrite);
1519 ReportSuccess(picojson::value(destination_path), obj);
1520 } catch (const std::system_error& e) {
1521 FilesystemUtils::TranslateException(e, obj);
1528 void FilesystemInstance::FileSystemManagerMoveFile(const picojson::value& args,
1529 picojson::object& out) {
1531 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1532 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1534 const std::string& path = args.get("path").get<std::string>();
1535 CHECK_STORAGE_ACCESS(path, &out);
1536 const std::string& destination_path = args.get("destinationPath").get<std::string>();
1537 CHECK_STORAGE_ACCESS(destination_path, &out);
1538 double callback_id = args.get("callbackId").get<double>();
1539 bool overwrite = args.get("overwrite").get<bool>();
1541 common::TaskQueue::GetInstance().Queue([this, callback_id, path, destination_path, overwrite] {
1543 picojson::value response = picojson::value(picojson::object());
1544 picojson::object& obj = response.get<picojson::object>();
1545 obj["callbackId"] = picojson::value(callback_id);
1547 this->PostMessage(response.serialize().c_str());
1552 if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfFile(buf)) {
1553 LogAndReportError(NotFoundException("Given path does not point to file."), obj);
1557 if (!FilesystemUtils::CheckIfExists(destination_path, &buf) ||
1558 !FilesystemUtils::CheckIfDir(buf)) {
1559 LogAndReportError(NotFoundException("Given path does not point to directory."), obj);
1564 std::string new_path = destination_path + '/' + FilesystemUtils::PosixBasename(path);
1565 if (!overwrite && FilesystemUtils::CheckIfExists(new_path, &buf)) {
1566 LogAndReportError(IOException("File or directory with conflicting name already exists."),
1570 FilesystemUtils::MoveFile(path, new_path, overwrite);
1571 ReportSuccess(picojson::value(new_path), obj);
1572 } catch (const std::system_error& e) {
1573 FilesystemUtils::TranslateException(e, obj);
1580 void FilesystemInstance::FileSystemManagerMoveDirectory(const picojson::value& args,
1581 picojson::object& out) {
1584 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1585 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1586 double callback_id = args.get("callbackId").get<double>();
1587 const std::string& path = args.get("path").get<std::string>();
1588 CHECK_STORAGE_ACCESS(path, &out);
1589 const std::string& destination_path = args.get("destinationPath").get<std::string>();
1590 CHECK_STORAGE_ACCESS(destination_path, &out);
1591 bool overwrite = args.get("overwrite").get<bool>();
1593 common::TaskQueue::GetInstance().Queue([this, callback_id, path, destination_path, overwrite] {
1594 picojson::value response = picojson::value(picojson::object());
1595 picojson::object& obj = response.get<picojson::object>();
1596 obj["callbackId"] = picojson::value(callback_id);
1598 this->PostMessage(response.serialize().c_str());
1603 if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfDir(buf)) {
1604 LogAndReportError(NotFoundException("Given path does not point to directory."), obj);
1608 if (!FilesystemUtils::CheckIfExists(destination_path, &buf) ||
1609 !FilesystemUtils::CheckIfDir(buf)) {
1610 LogAndReportError(NotFoundException("Given path does not point to directory."), obj);
1614 std::string new_path = destination_path + '/' + FilesystemUtils::PosixBasename(path);
1615 if (FilesystemUtils::CheckIfExists(new_path, &buf) && !FilesystemUtils::CheckIfDir(buf)) {
1616 LogAndReportError(IOException("File or directory with conflicting name already exists."),
1620 FilesystemUtils::MoveDirectory(path, destination_path, overwrite);
1621 ReportSuccess(picojson::value(new_path), obj);
1622 } catch (const std::system_error& e) {
1623 FilesystemUtils::TranslateException(e, obj);
1630 void FilesystemInstance::FileSystemManagerRename(const picojson::value& args,
1631 picojson::object& out) {
1633 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1634 const std::string& path = args.get("path").get<std::string>();
1636 CHECK_STORAGE_ACCESS(path, &out);
1637 double callback_id = args.get("callbackId").get<double>();
1638 const std::string& new_name = args.get("newName").get<std::string>();
1640 common::TaskQueue::GetInstance().Async([this, callback_id, new_name, path] {
1642 picojson::value response = picojson::value(picojson::object());
1643 picojson::object& obj = response.get<picojson::object>();
1644 obj["callbackId"] = picojson::value(callback_id);
1646 this->PostMessage(response.serialize().c_str());
1651 bool exists = FilesystemUtils::CheckIfExists(path, &buf);
1653 LogAndReportError(NotFoundException("Given path does not point to file or directory."),
1657 std::string new_path{FilesystemUtils::Dirname(path) + "/" + new_name};
1659 exists = FilesystemUtils::CheckIfExists(new_path, &buf);
1661 LogAndReportError(IOException("File or directory with conflicting name already exists"),
1665 FilesystemUtils::Rename(path, new_path);
1666 ReportSuccess(picojson::value(new_path), obj);
1667 } catch (const std::system_error& e) {
1668 FilesystemUtils::TranslateException(e, obj);
1675 void FilterResult(std::vector<const char*>& names, std::vector<unsigned char>& types, bool is_type,
1676 unsigned char type) {
1677 int i = (int)names.size() - 1;
1680 if (is_type ? type != types[i] : type == types[i]) {
1681 names.erase(names.begin() + i);
1687 void FilesystemInstance::FileSystemManagerListDirectory(const picojson::value& args,
1688 picojson::object& out) {
1690 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1692 double callback_id = args.get("callbackId").get<double>();
1693 const std::string& path = args.get("path").get<std::string>();
1694 const picojson::object& filter = args.get("filter").get<picojson::object>();
1695 CHECK_STORAGE_ACCESS(path, &out);
1697 common::TaskQueue::GetInstance().Async([this, callback_id, path, filter] {
1699 picojson::value response = picojson::value(picojson::object());
1700 picojson::object& obj = response.get<picojson::object>();
1701 obj["callbackId"] = picojson::value(callback_id);
1704 std::vector<const char*> names;
1706 std::vector<unsigned char> types;
1707 FilesystemUtils::ListDirectory(path, [&](const char* name, unsigned char type) {
1708 names.push_back(name);
1709 types.push_back(type);
1712 auto it = filter.find("isFile");
1713 if (filter.end() != it) {
1714 FilterResult(names, types, it->second.get<bool>(), DT_REG);
1717 it = filter.find("isDirectory");
1718 if (filter.end() != it) {
1719 FilterResult(names, types, it->second.get<bool>(), DT_DIR);
1723 auto start_modified_it = filter.find("startModified"),
1724 end_modified_it = filter.find("endModified"),
1725 start_created_it = filter.find("startCreated"),
1726 end_created_it = filter.find("endCreated");
1727 if (filter.end() != start_modified_it || filter.end() != end_modified_it ||
1728 filter.end() != start_created_it || filter.end() != end_created_it) {
1729 auto name_iterator = names.begin();
1730 while (name_iterator != names.end()) {
1732 std::string path_with_name = path + std::string("/") + std::string(*name_iterator);
1733 int status = ::stat(path_with_name.c_str(), &buf);
1735 throw std::system_error{errno, std::generic_category(),
1736 "Failed to get last modification date of a file"};
1738 if (filter.end() != start_modified_it &&
1739 (buf.st_mtime < start_modified_it->second.get<double>())) {
1740 name_iterator = names.erase(name_iterator);
1743 if (filter.end() != end_modified_it &&
1744 (buf.st_mtime > end_modified_it->second.get<double>())) {
1745 name_iterator = names.erase(name_iterator);
1748 if (filter.end() != start_created_it &&
1749 (buf.st_ctime < start_created_it->second.get<double>())) {
1750 name_iterator = names.erase(name_iterator);
1753 if (filter.end() != end_created_it &&
1754 (buf.st_ctime > end_created_it->second.get<double>())) {
1755 name_iterator = names.erase(name_iterator);
1762 picojson::value value = picojson::value(picojson::object());
1763 picojson::object& object = value.get<picojson::object>();
1765 object["names"] = picojson::value{picojson::array_type, true};
1766 object["path"] = picojson::value(path);
1768 picojson::array& names_array = object["names"].get<picojson::array>();
1769 names_array.reserve(names.size());
1770 for (unsigned int i = 0; i < names.size(); ++i) {
1771 names_array.push_back(picojson::value(names[i]));
1774 ReportSuccess(value, obj);
1775 } catch (const std::system_error& e) {
1776 FilesystemUtils::TranslateException(e, obj);
1778 this->PostMessage(response.serialize().c_str());
1784 void FilesystemInstance::FileSystemManagerIsFile(const picojson::value& args,
1785 picojson::object& out) {
1787 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1788 const std::string& path = args.get("path").get<std::string>();
1790 CHECK_STORAGE_ACCESS(path, &out);
1791 picojson::value is_file{};
1794 bool exists = FilesystemUtils::CheckIfExists(path, &buf);
1796 LogAndReportError(NotFoundException("Given path does not point to file."), out);
1799 is_file = picojson::value{FilesystemUtils::CheckIfFile(buf)};
1800 } catch (const std::system_error& e) {
1801 FilesystemUtils::TranslateException(e, out);
1803 ReportSuccess(is_file, out);
1806 void FilesystemInstance::FileSystemManagerIsDirectory(const picojson::value& args,
1807 picojson::object& out) {
1809 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1810 const std::string& path = args.get("path").get<std::string>();
1812 CHECK_STORAGE_ACCESS(path, &out);
1813 picojson::value is_directory{};
1816 bool exists = FilesystemUtils::CheckIfExists(path, &buf);
1818 LogAndReportError(NotFoundException("Given path does not point to directory."), out);
1821 is_directory = picojson::value{FilesystemUtils::CheckIfDir(buf)};
1822 } catch (const std::system_error& e) {
1823 FilesystemUtils::TranslateException(e, out);
1825 ReportSuccess(is_directory, out);
1828 void FilesystemInstance::FileSystemManagerPathExists(const picojson::value& args,
1829 picojson::object& out) {
1831 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1832 const std::string& path = args.get("path").get<std::string>();
1834 CHECK_STORAGE_ACCESS(path, &out);
1835 picojson::value does_file_exist = picojson::value{true};
1838 bool exists = FilesystemUtils::CheckIfExists(path, &buf);
1840 does_file_exist = picojson::value{false};
1842 } catch (const std::system_error& e) {
1843 FilesystemUtils::TranslateException(e, out);
1845 ReportSuccess(does_file_exist, out);
1848 void FilesystemInstance::FileSystemManagerGetLimits(const picojson::value& args,
1849 picojson::object& out) {
1851 picojson::value response =
1852 picojson::value{picojson::array{picojson::value{static_cast<double>(NAME_MAX)},
1853 picojson::value{static_cast<double>(PATH_MAX)}}};
1854 ReportSuccess(response, out);
1857 void FilesystemInstance::FileHandleSeek(const picojson::value& args, picojson::object& out) {
1859 const int fh_id = static_cast<int>(args.get("id").get<double>());
1860 const long offset = static_cast<long>(args.get("offset").get<double>());
1861 const std::string& _whence = args.get("whence").get<std::string>();
1863 auto fh = opened_files.find(fh_id);
1865 int whence = SEEK_SET;
1867 if ("CURRENT" == _whence) {
1869 LoggerD("SEEK_CUR selected");
1870 } else if ("END" == _whence) {
1872 LoggerD("SEEK_END selected");
1875 if (opened_files.end() == fh) {
1876 LogAndReportError(IOException("Invalid FileHandle"), out);
1880 auto handle = fh->second;
1882 auto logic = [handle, whence, offset](decltype(out) out) {
1883 long ret = fseek(handle->file_handle, offset, whence);
1885 LoggerE("fseek returned failed");
1886 std::string error_message =
1887 std::string("seek failed, fileHandle may be corrupted, error message: ") +
1888 GetErrorString(errno);
1889 LogAndReportError(IOException(error_message.c_str()), out);
1893 ret = ftell(handle->file_handle);
1895 LoggerE("ftell returned failed");
1896 std::string error_message =
1897 std::string("seek failed, fileHandle may be corrupted, error message: ") +
1898 GetErrorString(errno);
1899 LogAndReportError(IOException(error_message.c_str()), out);
1903 ReportSuccess(picojson::value((double)ret), out);
1906 bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
1912 double callback_id = args.get("callbackId").get<double>();
1913 this->worker.add_job([this, callback_id, logic] {
1914 picojson::value response = picojson::value(picojson::object());
1915 picojson::object& async_out = response.get<picojson::object>();
1916 async_out["callbackId"] = picojson::value(callback_id);
1918 this->PostMessage(response.serialize().c_str());
1926 void FilesystemInstance::FileHandleReadString(const picojson::value& args, picojson::object& out) {
1928 CHECK_EXIST(args, "id", out)
1929 const int fh_id = static_cast<int>(args.get("id").get<double>());
1930 const std::string& encoding =
1931 args.contains("encoding") ? args.get("encoding").get<std::string>() : "UTF-8";
1932 if (encoding != kISOEncoding && encoding != kUTF8Encoding) {
1933 LogAndReportError(NotSupportedException("Given encoding is not supported."), out);
1937 auto fh = opened_files.find(fh_id);
1938 if (opened_files.end() == fh) {
1939 LogAndReportError(IOException("Invalid FileHandle"), out);
1944 bool whole_file = false;
1945 if (args.contains("count")) {
1946 // If user passed 'count' parameter, we need to read at most 'count' characters.
1947 double count_double = args.get("count").get<double>();
1948 if (std::string::npos <= static_cast<unsigned long long>(count_double)) {
1949 LogAndReportError(InvalidValuesException("Invalid count was given"), out);
1952 count = static_cast<size_t>(count_double);
1955 count = file_size(fh->second->file_handle);
1957 } catch (const std::system_error& e) {
1958 LogAndReportError(IOException(e.what()), out);
1962 LoggerD("count: %zu", count);
1964 auto handle = fh->second;
1966 auto logic = [handle, count, encoding, whole_file](decltype(out) out) {
1968 size_t read_bytes = 0;
1969 std::vector<std::uint8_t> buf = read_file(handle->file_handle, count, &read_bytes);
1970 buf.resize(read_bytes); // this protects from reporting too big arrays to JS
1971 if (encoding == kISOEncoding) { // for iso-8859-1 1 byte is equal to 1 character
1972 out["result"] = picojson::value(picojson::string_type, true);
1973 latin1::to_utf8(buf, out["result"].get<std::string>());
1976 unsigned long char_count;
1977 short expected_extension_bytes;
1978 if (!validate_and_check_character_count(buf, char_count, expected_extension_bytes)) {
1980 IOException("File doesn't contain UTF-8 encoded string with given length"), out);
1983 LoggerD("char_count: %lu", char_count);
1984 LoggerD("ftell: %ld", ftell(handle->file_handle));
1986 handle->file_handle))) { // read number of characters if not whole file read
1987 LoggerD("count parameter given: %zu", count);
1989 !add_utf8_chars_to_buffer(handle->file_handle, buf, count - char_count,
1990 expected_extension_bytes)) {
1992 IOException("File doesn't contain UTF-8 encoded string with given length"), out);
1995 const char* str = (const char*)buf.data();
1996 ReportSuccess(picojson::value{str, buf.size()}, out);
1998 } catch (std::runtime_error& e) {
1999 LoggerE("Cannot read, cause: %s", e.what());
2000 LogAndReportError(IOException(e.what()), out);
2004 bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
2010 double callback_id = args.get("callbackId").get<double>();
2011 this->worker.add_job([this, callback_id, logic] {
2012 picojson::value response = picojson::value(picojson::object());
2013 picojson::object& async_out = response.get<picojson::object>();
2014 async_out["callbackId"] = picojson::value(callback_id);
2016 this->PostMessage(response.serialize().c_str());
2024 void FilesystemInstance::FileHandleWriteString(const picojson::value& args, picojson::object& out) {
2026 CHECK_EXIST(args, "id", out)
2027 CHECK_EXIST(args, "string", out)
2028 const int fh_id = static_cast<int>(args.get("id").get<double>());
2029 const std::string& str = args.get("string").get<std::string>();
2030 const std::string& encoding =
2031 args.contains("encoding") ? args.get("encoding").get<std::string>() : "UTF-8";
2032 if (encoding != kISOEncoding && encoding != kUTF8Encoding) {
2033 LogAndReportError(NotSupportedException("Given encoding is not supported."), out);
2037 auto fh = opened_files.find(fh_id);
2038 if (opened_files.end() == fh) {
2039 LogAndReportError(IOException("Invalid FileHandle"), out);
2043 auto handle = fh->second;
2045 auto logic = [str, handle, encoding](decltype(out) out) {
2047 std::vector<std::uint8_t> data;
2048 data.resize(str.size());
2050 if (encoding == kISOEncoding) {
2051 latin1::from_utf8(str, data);
2053 LoggerD("copying string memory to vector");
2054 std::memcpy(data.data(), str.data(), str.size());
2056 write_file(data.data(), data.size(), handle->file_handle);
2057 ReportSuccess(picojson::value{(double)data.size()}, out);
2058 } catch (std::runtime_error& e) {
2059 LoggerE("Cannot write, cause: %s", e.what());
2060 LogAndReportError(IOException(e.what()), out);
2064 bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
2070 double callback_id = args.get("callbackId").get<double>();
2071 this->worker.add_job([this, callback_id, logic] {
2072 picojson::value response = picojson::value(picojson::object());
2073 picojson::object& async_out = response.get<picojson::object>();
2074 async_out["callbackId"] = picojson::value(callback_id);
2076 this->PostMessage(response.serialize().c_str());
2084 void FilesystemInstance::FileHandleReadData(const picojson::value& args, picojson::object& out) {
2086 CHECK_EXIST(args, "id", out)
2087 const int fh_id = static_cast<int>(args.get("id").get<double>());
2088 auto fh = opened_files.find(fh_id);
2090 if (opened_files.end() == fh) {
2091 LoggerE("FileHandle with id: %d not found", fh_id);
2092 LogAndReportError(IOException("Invalid FileHandle"), out);
2097 // We need to check how many bytes is it possible to read until the EOF.
2099 // We need to read from file exactly the minimum value of 'size' given by user and the
2100 // 'size ' to avoid returning array with redundant data (which would be equal to 0).
2101 size = file_bytes_to_eof(fh->second->file_handle);
2102 if (args.contains("size")) {
2103 // If user passed 'size' parameter, we need to read at most 'size' bytes.
2104 double size_double = args.get("size").get<double>();
2105 if (std::string::npos <= static_cast<unsigned long long>(size_double)) {
2106 LogAndReportError(InvalidValuesException("Invalid size was given"), out);
2109 size = std::min(static_cast<size_t>(size_double), size);
2111 } catch (const std::system_error& e) {
2112 LogAndReportError(IOException(e.what()), out);
2116 LoggerD("size: %zu", size);
2118 auto handle = fh->second;
2120 auto logic = [handle, size](decltype(out) out) {
2122 std::vector<std::uint8_t> data = read_file(handle->file_handle, size);
2123 out["result"] = picojson::value(picojson::string_type, true);
2124 encode_binary_in_string(data, out["result"].get<std::string>());
2125 } catch (std::runtime_error& e) {
2126 LoggerE("Cannot read, cause: %s", e.what());
2127 LogAndReportError(IOException(e.what()), out);
2131 bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
2137 double callback_id = args.get("callbackId").get<double>();
2138 this->worker.add_job([this, callback_id, logic] {
2139 picojson::value response = picojson::value(picojson::object());
2140 picojson::object& async_out = response.get<picojson::object>();
2141 async_out["callbackId"] = picojson::value(callback_id);
2143 this->PostMessage(response.serialize().c_str());
2151 void FilesystemInstance::FileHandleWriteData(const picojson::value& args, picojson::object& out) {
2153 CHECK_EXIST(args, "id", out)
2154 CHECK_EXIST(args, "data", out)
2155 const auto& str = args.get("data").get<std::string>();
2156 const int fh_id = static_cast<int>(args.get("id").get<double>());
2158 auto fh = opened_files.find(fh_id);
2159 if (opened_files.end() == fh) {
2160 LoggerE("FileHandle with id: %d not found", fh_id);
2161 LogAndReportError(IOException("Invalid FileHandle"), out);
2165 auto handle = fh->second;
2167 auto logic = [str, handle](decltype(out) out) {
2169 std::vector<std::uint8_t> bytes;
2170 decode_binary_from_string(str, bytes);
2171 write_file(bytes.data(), bytes.size(), handle->file_handle);
2172 } catch (std::runtime_error& e) {
2173 LogAndReportError(IOException(e.what()), out);
2177 bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
2183 double callback_id = args.get("callbackId").get<double>();
2184 this->worker.add_job([this, callback_id, logic] {
2185 picojson::value response = picojson::value(picojson::object());
2186 picojson::object& async_out = response.get<picojson::object>();
2187 async_out["callbackId"] = picojson::value(callback_id);
2189 this->PostMessage(response.serialize().c_str());
2197 void FilesystemInstance::FileHandleFlush(const picojson::value& args, picojson::object& out) {
2199 const int fh_id = static_cast<int>(args.get("id").get<double>());
2201 auto fh = opened_files.find(fh_id);
2202 if (opened_files.end() == fh) {
2203 LogAndReportError(IOException("Invalid FileHandle"), out);
2207 auto handle = fh->second;
2209 auto logic = [handle](decltype(out) out) {
2210 int ret = fflush(handle->file_handle);
2212 std::string error_message =
2213 std::string("flush failed, error message: ") + GetErrorString(errno);
2214 LogAndReportError(IOException(error_message.c_str()), out);
2218 bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
2224 double callback_id = args.get("callbackId").get<double>();
2225 this->worker.add_job([this, callback_id, logic] {
2226 picojson::value response = picojson::value(picojson::object());
2227 picojson::object& async_out = response.get<picojson::object>();
2228 async_out["callbackId"] = picojson::value(callback_id);
2230 this->PostMessage(response.serialize().c_str());
2238 void FilesystemInstance::FileHandleSync(const picojson::value& args, picojson::object& out) {
2240 const int fh_id = static_cast<int>(args.get("id").get<double>());
2242 auto fh = opened_files.find(fh_id);
2243 if (opened_files.end() == fh) {
2244 LogAndReportError(IOException("Invalid FileHandle"), out);
2248 auto handle = fh->second;
2250 auto logic = [handle](decltype(out) out) {
2251 int ret = fsync(fileno(handle->file_handle));
2253 std::string error_message =
2254 std::string("sync failed, error message: ") + GetErrorString(errno);
2255 LogAndReportError(IOException(error_message.c_str()), out);
2259 bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
2265 double callback_id = args.get("callbackId").get<double>();
2266 this->worker.add_job([this, callback_id, logic] {
2267 picojson::value response = picojson::value(picojson::object());
2268 picojson::object& async_out = response.get<picojson::object>();
2269 async_out["callbackId"] = picojson::value(callback_id);
2271 this->PostMessage(response.serialize().c_str());
2279 void FilesystemInstance::FileHandleClose(const picojson::value& args, picojson::object& out) {
2281 const int fh_id = static_cast<int>(args.get("id").get<double>());
2282 auto fh = opened_files.find(fh_id);
2283 if (opened_files.end() == fh) {
2284 LogAndReportError(IOException("Invalid FileHandle"), out);
2288 std::shared_ptr<FileHandle> handle = fh->second;
2289 opened_files.erase(fh);
2291 auto logic = [handle](decltype(out) out) {
2292 if (!handle->file_handle) {
2293 LogAndReportError(IOException("File handle already closed."), out);
2296 int ret = fclose(handle->file_handle);
2297 handle->file_handle = nullptr;
2299 std::string error_message =
2300 std::string("close failed, error message: ") + GetErrorString(errno);
2301 LogAndReportError(IOException(error_message.c_str()), out);
2305 bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
2311 std::condition_variable conditional_variable;
2312 // adding empty job to worker's queue, in order to wait for all jobs to be done before closing
2314 this->worker.add_job([] {},
2315 [&conditional_variable, &mutex, &ready, &done, logic, &out] {
2317 std::unique_lock<std::mutex> lock(mutex);
2318 conditional_variable.wait(lock, [&ready] { return ready; });
2322 conditional_variable.notify_one();
2326 // let know that close is ready
2327 std::unique_lock<std::mutex> lock(mutex);
2330 conditional_variable.notify_one();
2334 std::unique_lock<std::mutex> lock(mutex);
2335 conditional_variable.wait(lock, [&done] { return done; });
2337 handle->file_handle = nullptr;
2340 double callback_id = args.get("callbackId").get<double>();
2341 this->worker.add_job([this, callback_id, logic] {
2342 picojson::value response = picojson::value(picojson::object());
2343 picojson::object& async_out = response.get<picojson::object>();
2344 async_out["callbackId"] = picojson::value(callback_id);
2346 this->PostMessage(response.serialize().c_str());
2356 } // namespace filesystem
2357 } // namespace extension