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_METHOD(M) RegisterSyncHandler(#M, std::bind(&FilesystemInstance::M, this, _1, _2))
108 REGISTER_METHOD(FileStat);
109 REGISTER_METHOD(FileStatSync);
110 REGISTER_METHOD(FileCreateSync);
111 REGISTER_METHOD(FileReadDir);
112 REGISTER_METHOD(FileRename);
113 REGISTER_METHOD(FileReadBytes);
114 REGISTER_METHOD(FileReadString);
115 REGISTER_METHOD(FileWriteBytes);
116 REGISTER_METHOD(FileWriteBase64);
117 REGISTER_METHOD(FileWriteString);
118 REGISTER_METHOD(FilesystemFetchAllStorages);
119 REGISTER_METHOD(FileSystemManagerAddStorageStateChangeListener);
120 REGISTER_METHOD(FileSystemManagerRemoveStorageStateChangeListener);
121 REGISTER_METHOD(FileSystemManagerFetchStorages);
122 REGISTER_METHOD(FileSystemManagerMakeDirectory);
123 REGISTER_METHOD(FileSystemManagerMakeDirectorySync);
124 REGISTER_METHOD(FileUnlinkFile);
125 REGISTER_METHOD(FileRemoveDirectory);
126 REGISTER_METHOD(FileCopyTo);
127 REGISTER_METHOD(FileSystemManagerGetCanonicalPath);
129 REGISTER_METHOD(FileSystemManagerOpenFile);
130 REGISTER_METHOD(FileSystemManagerCreateDirectory);
131 REGISTER_METHOD(FileSystemManagerDeleteFile);
132 REGISTER_METHOD(FileSystemManagerDeleteDirectory);
133 REGISTER_METHOD(FileSystemManagerCopyFile);
134 REGISTER_METHOD(FileSystemManagerCopyDirectory);
135 REGISTER_METHOD(FileSystemManagerMoveFile);
136 REGISTER_METHOD(FileSystemManagerMoveDirectory);
137 REGISTER_METHOD(FileSystemManagerRename);
138 REGISTER_METHOD(FileSystemManagerListDirectory);
139 REGISTER_METHOD(FileSystemManagerIsFile);
140 REGISTER_METHOD(FileSystemManagerIsDirectory);
141 REGISTER_METHOD(FileSystemManagerPathExists);
142 REGISTER_METHOD(FileSystemManagerGetLimits);
144 REGISTER_METHOD(FileHandleSeek);
145 REGISTER_METHOD(FileHandleReadString);
146 REGISTER_METHOD(FileHandleWriteString);
147 REGISTER_METHOD(FileHandleReadData);
148 REGISTER_METHOD(FileHandleWriteData);
149 REGISTER_METHOD(FileHandleFlush);
150 REGISTER_METHOD(FileHandleSync);
151 REGISTER_METHOD(FileHandleClose);
153 #undef REGISTER_METHOD
155 FilesystemManager::GetInstance().AddListener(this);
158 FilesystemInstance::~FilesystemInstance() {
161 FilesystemManager::GetInstance().StopListening();
162 FilesystemManager::GetInstance().RemoveListener();
165 #define CHECK_EXIST(args, name, out) \
166 if (!args.contains(name)) { \
167 LogAndReportError(TypeMismatchException(name " is required argument"), out); \
171 void FilesystemInstance::FileCreateSync(const picojson::value& args, picojson::object& out) {
174 "DEPRECATION WARNING: File.createFile() is deprecated since Tizen 5.0. Use "
175 "FileSystemManager.openFile() instead.");
177 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
178 CHECK_EXIST(args, "location", out)
179 const std::string& location = args.get("location").get<std::string>();
180 CHECK_STORAGE_ACCESS(location, &out);
182 auto onSuccess = [&](const FilesystemStat& data) {
183 ScopeLogger("Entered into asynchronous function, onSuccess");
184 ReportSuccess(data.toJSON(), out);
187 auto onError = [&](FilesystemError e) {
188 ScopeLogger("Entered into asynchronous function, onError");
189 PrepareError(e, out);
192 FilesystemManager::GetInstance().CreateFile(location, onSuccess, onError);
195 void FilesystemInstance::FileRename(const picojson::value& args, picojson::object& out) {
198 "DEPRECATION WARNING: File.moveTo() is deprecated since Tizen 5.0. Use "
199 "FileSystemManager.moveFile() or FileSystemManager.moveDirectory() instead.");
201 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
202 CHECK_EXIST(args, "callbackId", out)
204 CHECK_EXIST(args, "oldPath", out)
205 const std::string& oldPath = args.get("oldPath").get<std::string>();
206 CHECK_STORAGE_ACCESS(oldPath, &out);
207 CHECK_EXIST(args, "newPath", out)
208 const std::string& newPath = args.get("newPath").get<std::string>();
209 CHECK_STORAGE_ACCESS(newPath, &out);
211 double callback_id = args.get("callbackId").get<double>();
213 auto onSuccess = [this, callback_id](const FilesystemStat& data) {
214 ScopeLogger("Entered into asynchronous function, onSuccess");
215 picojson::value response = picojson::value(picojson::object());
216 picojson::object& obj = response.get<picojson::object>();
217 obj["callbackId"] = picojson::value(callback_id);
218 ReportSuccess(data.toJSON(), obj);
219 Instance::PostMessage(this, response.serialize().c_str());
222 auto onError = [this, callback_id](FilesystemError e) {
223 ScopeLogger("Entered into asynchronous function, onError");
224 picojson::value response = picojson::value(picojson::object());
225 picojson::object& obj = response.get<picojson::object>();
226 obj["callbackId"] = picojson::value(callback_id);
227 PrepareError(e, obj);
228 Instance::PostMessage(this, response.serialize().c_str());
231 FilesystemManager& fsm = FilesystemManager::GetInstance();
232 common::TaskQueue::GetInstance().Queue(
233 std::bind(&FilesystemManager::Rename, &fsm, oldPath, newPath, onSuccess, onError));
236 /* Write to str buf bytes as if they were UTF-8 codepoints */
237 static void encode_binary_in_string(const std::vector<std::uint8_t>& buf, std::string& str) {
239 str.reserve(str.size() + buf.size());
241 for (std::uint8_t byte : buf) {
246 str += 0xC0 | (byte >> 6);
247 str += 0x80 | (byte & 0x3F);
251 /* Decode (max 2-byte) UTF-8 characters to buf, throws std::runtime_error */
252 static void decode_binary_from_string(const std::string& str, std::vector<std::uint8_t>& buf) {
254 buf.reserve(buf.size() + str.size());
256 const std::uint8_t* it = (std::uint8_t*)str.data();
257 const std::uint8_t* end = it + str.size();
260 buf.push_back(*it++);
265 throw std::runtime_error("internal error (invalid UTF-8 sequence)");
268 unsigned int x = ((b1 & 0x1F) << 6) | (b2 & 0x3F);
274 static auto to_utf8 = &encode_binary_in_string;
275 /* It does not check if UTF-8 values are representable by ISO-8859-1. Make proper checks and
276 * substitute invalid characters in JavaScript before passing through crosswalk */
277 static auto from_utf8 = &decode_binary_from_string;
280 static constexpr std::size_t NPOS = (std::size_t)(-1);
283 * On failure throws std::system_error
285 static std::size_t file_size(FILE* file) {
289 int status = ::fstat(::fileno(file), &buf);
291 throw std::system_error{errno, std::generic_category(), "failed to get file size"};
298 * Returns the amount of bytes to the EOF starting from current file-position indicator.
300 * On failure throws std::system_error
302 static std::size_t file_bytes_to_eof(FILE* file) {
305 std::size_t total_fize_size = file_size(file);
306 long file_position = ftell(file);
307 if (-1 == file_position) {
308 throw std::system_error{errno, std::generic_category(),
309 "Failed to get file position"s + GetErrorString(errno)};
311 return total_fize_size - static_cast<size_t>(file_position);
314 static std::vector<std::uint8_t> read_file(FILE* file, std::size_t length = NPOS,
315 std::size_t* read_bytes = nullptr);
318 * Returns a buffer. If length is NPOS, then it reads whole file, up to the end.
319 * On failure throws std::runtime_error
321 static std::vector<std::uint8_t> read_file(std::string path, long offset = 0,
322 std::size_t length = NPOS) {
325 FILE* file = std::fopen(path.c_str(), "r");
327 std::string err_msg = std::string("Cannot open file to read. ") + GetErrorString(errno);
328 throw std::system_error{errno, std::generic_category(), err_msg};
332 int status = std::fclose(file);
334 LoggerE("Cannot close file!");
338 if (0 != offset && 0 != std::fseek(file, offset, SEEK_SET)) {
339 std::string err_msg = std::string("Cannot perform seek. ") + GetErrorString(errno);
340 throw std::system_error{errno, std::generic_category(), err_msg};
343 if (NPOS == length) {
344 length = file_size(file) - offset;
347 return read_file(file, length);
351 * Returns a buffer. If length is NPOS, then it reads whole file, up to the end.
352 * On failure throws std::runtime_error
354 static std::vector<std::uint8_t> read_file(FILE* file, std::size_t length /*= NPOS*/,
355 std::size_t* read_bytes /* = nullptr*/) {
358 // By default reads whole file. Get the file size.
359 if (NPOS == length) {
360 length = file_size(file);
363 std::vector<std::uint8_t> out_buf;
365 out_buf.resize(length);
366 } catch (std::bad_alloc& err) {
367 throw std::runtime_error{"Could not allocate memory"};
369 std::uint8_t* data_p = out_buf.data();
370 std::uint8_t* end_p = data_p + length;
371 while (data_p != end_p) {
372 data_p += std::fread(data_p, 1, end_p - data_p, file);
374 if (std::ferror(file)) {
375 std::string err_msg = std::string("Error during file read. ") + GetErrorString(errno);
376 throw std::runtime_error(err_msg);
379 if (std::feof(file)) {
380 LoggerD("File is at end before buffer is filled. Finish.");
384 // read_file function is used in API since version 1.0.
385 // read_bytes was added in Tizen 5.0, with default value equal to nullptr, the behaviour is not
387 // It is used to return the actual number of read bytes, because requested length might be bigger
388 // than possible bytes to be read.
389 if (nullptr != read_bytes) {
390 *read_bytes = std::distance(out_buf.data(), data_p);
396 * On failure throws std::runtime_error
398 void write_file(const std::uint8_t* data, std::size_t len, FILE* file) {
401 const std::uint8_t* data_p = data;
402 const std::uint8_t* end_p = data + len;
403 while (data_p != end_p) {
404 data_p += fwrite(data_p, 1, end_p - data_p, file);
406 if (std::ferror(file)) {
407 std::string err_msg = std::string("Error during file write. ") + GetErrorString(errno);
408 throw std::runtime_error(err_msg);
412 if (std::fflush(file)) {
413 std::string err_msg = std::string("Error during file write. ") + GetErrorString(errno);
414 throw std::runtime_error(err_msg);
419 * On failure throws std::runtime_error
421 void write_file(const std::uint8_t* data, std::size_t len, std::string path, long offset,
425 FILE* file = std::fopen(path.c_str(), mode);
428 std::string err_msg = std::string("Cannot open file to write. ") + GetErrorString(errno);
429 throw std::runtime_error(err_msg);
433 int status = std::fclose(file);
435 LoggerE("Cannot close file!");
439 if (offset != 0 && std::fseek(file, offset, SEEK_SET) != 0) {
440 std::string err_msg = std::string("Cannot perform seek. ") + GetErrorString(errno);
441 throw std::system_error{errno, std::generic_category(), err_msg};
444 write_file(data, len, file);
447 #define FIRST_BIT_MASK 0x80
448 #define SECOND_BIT_MASK 0x40
449 #define THIRD_BIT_MASK 0x20
450 #define FOURTH_BIT_MASK 0x10
451 #define FIFTH_BIT_MASK 0x08
453 enum class ByteOfUTF8Classification {
462 ByteOfUTF8Classification is_utf8_byte(uint8_t byte) {
463 if (FIRST_BIT_MASK & byte) {
464 if (SECOND_BIT_MASK & byte) {
465 if (THIRD_BIT_MASK & byte) {
466 if (FOURTH_BIT_MASK & byte) {
467 if (FIFTH_BIT_MASK & byte) {
468 return ByteOfUTF8Classification::NOT_VALID;
470 return ByteOfUTF8Classification::FIRST_OF_4_BYTES;
473 return ByteOfUTF8Classification::FIRST_OF_3_BYTES;
476 return ByteOfUTF8Classification::FIRST_OF_2_BYTES;
479 return ByteOfUTF8Classification::EXTENSION_BYTE;
482 return ByteOfUTF8Classification::ONE_BYTE_CHAR;
486 void skip_partial_character(std::vector<std::uint8_t>& buf) {
487 auto buf_position = buf.begin();
489 while (buf.end() != buf_position &&
490 (ByteOfUTF8Classification::EXTENSION_BYTE == is_utf8_byte(*buf_position))) {
491 buf_position = buf.erase(buf_position);
492 LoggerD("Removed UTF-8 Extension Byte from begining of read buffer");
496 bool validate_and_check_character_count(std::vector<std::uint8_t>& buf, unsigned long& char_count,
497 short& no_of_extensions_expected) {
500 no_of_extensions_expected = 0;
501 auto buf_position = buf.begin();
503 skip_partial_character(buf);
505 while (buf.end() != buf_position) {
506 switch (is_utf8_byte(*buf_position)) {
507 case ByteOfUTF8Classification::EXTENSION_BYTE:
508 no_of_extensions_expected--;
509 if (0 > no_of_extensions_expected) {
511 } else if (0 == no_of_extensions_expected) {
515 case ByteOfUTF8Classification::ONE_BYTE_CHAR:
516 if (0 != no_of_extensions_expected) {
521 case ByteOfUTF8Classification::FIRST_OF_2_BYTES:
522 if (0 != no_of_extensions_expected) {
525 no_of_extensions_expected = 1;
527 case ByteOfUTF8Classification::FIRST_OF_3_BYTES:
528 if (0 != no_of_extensions_expected) {
531 no_of_extensions_expected = 2;
533 case ByteOfUTF8Classification::FIRST_OF_4_BYTES:
534 if (0 != no_of_extensions_expected) {
537 no_of_extensions_expected = 3;
539 case ByteOfUTF8Classification::NOT_VALID:
542 LoggerE("Abnormal value returned from is_utf8_byte function");
550 * add_utf8_chars_to_buffer
551 * Method returns false if byte read is not a valid utf8 char
553 bool add_utf8_chars_to_buffer(FILE* file, std::vector<std::uint8_t>& buf, int chars_to_read,
554 short& extension_bytes_expected) {
556 LoggerD("chars_to_read: %i", chars_to_read);
557 LoggerD("extension_bytes_expected: %i", extension_bytes_expected);
558 while (chars_to_read) {
559 if (extension_bytes_expected) {
560 character = getc(file);
561 if (EOF == character) {
564 buf.push_back(character);
565 if (!--extension_bytes_expected) {
570 character = getc(file);
571 if (EOF == character) {
574 buf.push_back(character);
575 switch (is_utf8_byte(character)) {
576 case ByteOfUTF8Classification::ONE_BYTE_CHAR:
579 case ByteOfUTF8Classification::FIRST_OF_2_BYTES:
580 extension_bytes_expected = 1;
582 case ByteOfUTF8Classification::FIRST_OF_3_BYTES:
583 extension_bytes_expected = 2;
585 case ByteOfUTF8Classification::FIRST_OF_4_BYTES:
586 extension_bytes_expected = 3;
588 case ByteOfUTF8Classification::EXTENSION_BYTE:
589 LoggerD("unexpected EXTENSION_BYTE");
591 case ByteOfUTF8Classification::NOT_VALID:
592 LoggerE("unexpected NOT_VALID byte while reading utf-8");
595 LoggerE("Abnormal. Last read char: %c: ", character);
603 static const char int_to_char[] =
604 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
605 static const std::uint8_t INV = 255;
606 static const std::uint8_t PAD = 254;
607 static const std::uint8_t char_to_int[] = {
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, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
610 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60,
611 61, 255, 255, 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
612 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255,
613 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
614 43, 44, 45, 46, 47, 48, 49, 50, 51, 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, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
621 255, 255, 255, 255, 255, 255, 255, 255, 255};
624 * On error throws std::runtime_error
626 static std::vector<std::uint8_t> decode(const char* str, std::size_t len) {
627 std::vector<std::uint8_t> out;
628 if (len % 4 != 0) throw std::runtime_error("string length is not multiple of 4");
629 if (len == 0) return out;
631 const std::uint8_t* p = (std::uint8_t*)str;
632 const std::uint8_t* end = p + len - 4; // last four can have padding in it
633 std::uint8_t b1, b2, b3, b4;
634 out.reserve(len / 4 * 3);
636 b1 = char_to_int[*p++];
637 b2 = char_to_int[*p++];
638 b3 = char_to_int[*p++];
639 b4 = char_to_int[*p++];
641 if (b1 > 63 || b2 > 63 || b3 > 63 || b4 > 63) throw std::runtime_error("invalid character");
643 out.push_back((b1 << 2) | (b2 >> 4));
644 out.push_back((b2 << 4) | (b3 >> 2));
645 out.push_back((b3 << 6) | b4);
647 b1 = char_to_int[*p++];
648 b2 = char_to_int[*p++];
649 b3 = char_to_int[*p++];
650 b4 = char_to_int[*p++];
652 if (b1 == PAD || b1 == INV || b2 == PAD || b2 == INV || b3 == INV || b4 == INV)
653 throw std::runtime_error("invalid character");
655 out.push_back((b1 << 2) | (b2 >> 4));
657 if (b4 != PAD) throw std::runtime_error("invalid character");
659 out.push_back((b2 << 4) | (b3 >> 2));
660 if (b4 != PAD) out.push_back((b3 << 6) | b4);
665 } // namespace base64
667 void FilesystemInstance::FileReadString(const picojson::value& args, picojson::object& out) {
670 "DEPRECATION WARNING: This method is deprecated since Tizen 5.0.Use FileHandle.readString() "
671 "or FileHandle.readStringNonBlocking() instead.");
673 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
674 CHECK_EXIST(args, "location", out)
675 CHECK_EXIST(args, "offset", out)
677 const std::string& location = args.get("location").get<std::string>();
678 size_t offset = static_cast<size_t>(args.get("offset").get<double>());
679 size_t length = args.contains("length") ? (size_t)args.get("length").get<double>() : NPOS;
680 const std::string& encoding =
681 args.contains("encoding") ? args.get("encoding").get<std::string>() : "utf-8";
684 std::vector<std::uint8_t> buf = read_file(location, offset, length);
686 if (encoding == "iso-8859-1") {
687 out["result"] = picojson::value(picojson::string_type, true);
688 latin1::to_utf8(buf, out["result"].get<std::string>());
690 } else { // default: UTF-8
692 const char* str = (const char*)buf.data();
693 ReportSuccess(picojson::value{str}, out);
695 } catch (std::runtime_error& e) {
696 LoggerE("Cannot read file %s, cause: %s", location.c_str(), e.what());
697 PrepareError(FilesystemError::Other, out);
701 void FilesystemInstance::FileReadBytes(const picojson::value& args, picojson::object& out) {
704 "DEPRECATION WARNING: This method is deprecated since Tizen 5.0. Use FileHandle.readData() "
705 "or FileHandle.readDataNonBlocking() instead.");
707 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
708 CHECK_EXIST(args, "location", out)
709 CHECK_EXIST(args, "offset", out)
710 CHECK_EXIST(args, "length", out)
712 const std::string& location = args.get("location").get<std::string>();
713 size_t offset = static_cast<size_t>(args.get("offset").get<double>());
714 size_t length = static_cast<size_t>(args.get("length").get<double>());
717 std::vector<std::uint8_t> out_data = read_file(location, offset, length);
719 out["result"] = picojson::value(picojson::string_type, true);
720 encode_binary_in_string(out_data, out["result"].get<std::string>());
722 } catch (std::runtime_error& e) {
723 LoggerE("Cannot read file %s, cause: %s", location.c_str(), e.what());
724 PrepareError(FilesystemError::Other, out);
728 void FilesystemInstance::FileWriteString(const picojson::value& args, picojson::object& out) {
731 "DEPRECATION WARNING: FileStream.write() is deprecated since Tizen 5.0. Use "
732 "FileHandle.writeString() or FileHandle.writeStringNonBlocking() instead.");
734 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
735 CHECK_EXIST(args, "location", out)
736 CHECK_EXIST(args, "data", out)
737 CHECK_EXIST(args, "offset", out)
738 CHECK_EXIST(args, "truncate", out)
740 const std::string& location = args.get("location").get<std::string>();
741 const std::string& str = args.get("data").get<std::string>();
742 size_t offset = static_cast<size_t>(args.get("offset").get<double>());
743 bool truncate = static_cast<bool>(args.get("truncate").get<bool>());
744 const char* mode = truncate ? "w" : "r+";
745 const std::string& encoding =
746 args.contains("encoding") ? args.get("encoding").get<std::string>() : "utf-8";
749 if (encoding == "iso-8859-1") {
750 std::vector<std::uint8_t> data;
751 latin1::from_utf8(str, data);
752 write_file(data.data(), data.size(), location, offset, mode);
753 ReportSuccess(picojson::value{(double)data.size()}, out);
754 } else { // default: UTF-8
755 const std::uint8_t* buf = (const std::uint8_t*)str.c_str();
756 std::size_t len = str.length();
757 write_file(buf, len, location, offset, mode);
758 ReportSuccess(picojson::value{(double)str.size()}, out);
760 } catch (std::runtime_error& e) {
761 LoggerE("Cannot write to file %s, cause: %s", location.c_str(), e.what());
762 PrepareError(FilesystemError::Other, out);
767 void FilesystemInstance::FileWriteBytes(const picojson::value& args, picojson::object& out) {
770 "DEPRECATION WARNING: FileStream.writeBytes() is deprecated since Tizen 5.0. To read and Use "
771 "FileHandle.writeData() or FileHandle.writeDataNonBlocking() instead.");
773 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
774 CHECK_EXIST(args, "location", out)
775 CHECK_EXIST(args, "data", out)
776 CHECK_EXIST(args, "offset", out)
777 CHECK_EXIST(args, "truncate", out)
779 const std::string& location = args.get("location").get<std::string>();
780 const std::string& str = args.get("data").get<std::string>();
781 size_t offset = static_cast<size_t>(args.get("offset").get<double>());
782 bool truncate = static_cast<bool>(args.get("truncate").get<bool>());
783 const char* mode = truncate ? "w" : "r+";
786 std::vector<std::uint8_t> data;
787 decode_binary_from_string(str, data);
788 write_file(data.data(), data.size(), location, offset, mode);
789 } catch (std::runtime_error& e) {
790 LoggerE("Cannot write to %s, cause: %s", location.c_str(), e.what());
791 PrepareError(FilesystemError::Other, out);
798 void FilesystemInstance::FileWriteBase64(const picojson::value& args, picojson::object& out) {
801 "DEPRECATION WARNING: FileStream.writeBase64() is deprecated since Tizen 5.0. Use "
802 "FileHandle.writeData() or FileHandle.writeDataNonBlocking() in combination with atob() and "
803 "btoa() functions instead.");
805 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
806 CHECK_EXIST(args, "location", out)
807 CHECK_EXIST(args, "data", out)
808 CHECK_EXIST(args, "offset", out)
809 CHECK_EXIST(args, "truncate", out)
811 const std::string& location = args.get("location").get<std::string>();
812 const std::string& str = args.get("data").get<std::string>();
813 size_t offset = static_cast<size_t>(args.get("offset").get<double>());
814 bool truncate = static_cast<bool>(args.get("truncate").get<bool>());
815 const char* mode = truncate ? "w" : "r+";
817 std::vector<std::uint8_t> data;
819 data = base64::decode(str.c_str(), str.length());
820 } catch (std::runtime_error& e) {
821 LoggerE("Can't decode base64: %s", e.what());
822 ReportError(InvalidValuesException(std::string("Can't decode base64: ") + e.what()), out);
827 write_file(data.data(), data.size(), location, offset, mode);
828 ReportSuccess(picojson::value{(double)data.size()}, out);
829 } catch (std::runtime_error& e) {
830 LoggerE("Cannot write to %s, cause: %s", location.c_str(), e.what());
831 PrepareError(FilesystemError::Other, out);
835 void FilesystemInstance::FileStat(const picojson::value& args, picojson::object& out) {
837 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
838 CHECK_EXIST(args, "location", out)
839 const std::string& location = args.get("location").get<std::string>();
840 CHECK_STORAGE_ACCESS(location, &out);
842 CHECK_EXIST(args, "callbackId", out)
843 double callback_id = args.get("callbackId").get<double>();
845 auto onSuccess = [this, callback_id](const FilesystemStat& data) {
846 ScopeLogger("Entered into asynchronous function, onSuccess");
847 picojson::value response = picojson::value(picojson::object());
848 picojson::object& obj = response.get<picojson::object>();
849 obj["callbackId"] = picojson::value(callback_id);
850 ReportSuccess(data.toJSON(), obj);
851 Instance::PostMessage(this, response.serialize().c_str());
854 auto onError = [this, callback_id](FilesystemError e) {
855 ScopeLogger("Entered into asynchronous function, onError");
856 picojson::value response = picojson::value(picojson::object());
857 picojson::object& obj = response.get<picojson::object>();
858 obj["callbackId"] = picojson::value(callback_id);
859 PrepareError(e, obj);
860 Instance::PostMessage(this, response.serialize().c_str());
863 FilesystemManager& fsm = FilesystemManager::GetInstance();
864 common::TaskQueue::GetInstance().Async(
865 std::bind(&FilesystemManager::StatPath, &fsm, location, onSuccess, onError));
868 void FilesystemInstance::FileStatSync(const picojson::value& args, picojson::object& out) {
870 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
871 CHECK_EXIST(args, "location", out)
872 const std::string& location = args.get("location").get<std::string>();
873 CHECK_STORAGE_ACCESS(location, &out);
875 auto onSuccess = [&](const FilesystemStat& data) {
876 ScopeLogger("Entered into asynchronous function, onSuccess");
877 ReportSuccess(data.toJSON(), out);
880 auto onError = [&](FilesystemError e) {
881 ScopeLogger("Entered into asynchronous function, onError");
882 PrepareError(e, out);
885 FilesystemManager::GetInstance().StatPath(location, onSuccess, onError);
888 void FilesystemInstance::FilesystemFetchAllStorages(const picojson::value& args,
889 picojson::object& out) {
892 auto onSuccess = [&](const common::VirtualStorages& result) {
893 ScopeLogger("Entered into asynchronous function, onSuccess");
894 picojson::array roots;
895 for (const auto& root : result) {
896 roots.push_back(root->ToJson());
898 ReportSuccess(picojson::value(roots), out);
901 auto onError = [&](FilesystemError e) {
902 ScopeLogger("Entered into asynchronous function, onError");
903 PrepareError(e, out);
906 FilesystemManager::GetInstance().FetchAllStorages(onSuccess, onError);
909 void FilesystemInstance::FileSystemManagerFetchStorages(const picojson::value& args,
910 picojson::object& out) {
913 auto onSuccess = [&](const common::Storages& result) {
914 ScopeLogger("Entered into asynchronous function, onSuccess");
915 picojson::array storages;
916 storages.reserve(result.size());
917 for (const auto storage : result) {
918 storages.push_back(storage->ToJson());
920 ReportSuccess(picojson::value(storages), out);
923 auto onError = [&](FilesystemError e) {
924 ScopeLogger("Entered into asynchronous function, onError");
925 PrepareError(e, out);
928 FilesystemManager::GetInstance().FetchStorages(onSuccess, onError);
930 void FilesystemInstance::FileSystemManagerAddStorageStateChangeListener(const picojson::value& args,
931 picojson::object& out) {
933 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
934 FilesystemManager::GetInstance().StartListening();
938 void FilesystemInstance::FileSystemManagerRemoveStorageStateChangeListener(
939 const picojson::value& args, picojson::object& out) {
941 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
942 FilesystemManager::GetInstance().StopListening();
946 void FilesystemInstance::onFilesystemStateChangeSuccessCallback(const common::Storage& storage) {
949 picojson::value event = picojson::value(picojson::object());
950 picojson::object& obj = event.get<picojson::object>();
951 obj["label"] = picojson::value(storage.name_);
952 obj["type"] = picojson::value(common::Storage::ToString(storage.type()));
953 obj["state"] = picojson::value(common::Storage::ToString(storage.state()));
954 obj["listenerId"] = picojson::value("StorageStateChangeListener");
955 Instance::PostMessage(this, event.serialize().c_str());
958 void FilesystemInstance::onFilesystemStateChangeErrorCallback() {
960 picojson::value event = picojson::value(picojson::object());
961 picojson::object& obj = event.get<picojson::object>();
962 LogAndReportError(UnknownException(std::string("Failed to registerd listener")), obj);
963 obj["listenerId"] = picojson::value("StorageStateChangeListener");
964 LoggerD("Posting: %s", event.serialize().c_str());
965 Instance::PostMessage(this, event.serialize().c_str());
968 void FilesystemInstance::FileSystemManagerMakeDirectory(const picojson::value& args,
969 picojson::object& out) {
971 CHECK_EXIST(args, "callbackId", out)
972 CHECK_EXIST(args, "location", out)
974 double callback_id = args.get("callbackId").get<double>();
975 const std::string& location = args.get("location").get<std::string>();
977 auto onResult = [this, callback_id](FilesystemError e) {
978 ScopeLogger("Entered into asynchronous function, onResult");
979 picojson::value response = picojson::value(picojson::object());
980 picojson::object& obj = response.get<picojson::object>();
981 obj["callbackId"] = picojson::value(callback_id);
982 if (e == FilesystemError::DirectoryExists)
985 PrepareError(e, obj);
986 Instance::PostMessage(this, response.serialize().c_str());
989 auto onAction = [location, onResult]() {
990 ScopeLogger("Entered into asynchronous function, onAction");
991 FilesystemManager::GetInstance().MakeDirectory(location, onResult);
994 common::TaskQueue::GetInstance().Async(onAction);
997 void FilesystemInstance::FileSystemManagerMakeDirectorySync(const picojson::value& args,
998 picojson::object& out) {
1001 "DEPRECATION WARNING: File.createDirectory() is deprecated since Tizen 5.0. Use "
1002 "FileSystemManager.createDirectory() instead.");
1004 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1005 CHECK_EXIST(args, "location", out)
1006 const std::string& location = args.get("location").get<std::string>();
1007 CHECK_STORAGE_ACCESS(location, &out);
1009 auto onResult = [&](FilesystemError e) {
1010 ScopeLogger("Entered into asynchronous function, onResult");
1011 if (e == FilesystemError::DirectoryExists)
1014 PrepareError(e, out);
1017 FilesystemManager::GetInstance().MakeDirectory(location, onResult);
1020 void FilesystemInstance::FileReadDir(const picojson::value& args, picojson::object& out) {
1023 "DEPRECATION WARNING: File.listFiles() is deprecated since Tizen 5.0. Use "
1024 "FileSystemManager.listDirectory() instead.");
1026 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1027 CHECK_EXIST(args, "pathToDir", out)
1028 CHECK_EXIST(args, "callbackId", out)
1030 double callback_id = args.get("callbackId").get<double>();
1031 const std::string& pathToDir = args.get("pathToDir").get<std::string>();
1033 auto onSuccess = [this, callback_id](const std::vector<std::string>& paths) {
1034 ScopeLogger("Entered into asynchronous function, onSuccess");
1035 picojson::value result = picojson::value(picojson::array());
1037 picojson::array& statPaths = result.get<picojson::array>();
1038 picojson::value response = picojson::value(picojson::object());
1039 picojson::object& obj = response.get<picojson::object>();
1040 obj["callbackId"] = picojson::value(callback_id);
1041 for (auto path : paths) {
1042 FilesystemStat stat = FilesystemStat::getStat(path);
1044 if (FilesystemError::None == stat.error) {
1045 statPaths.push_back(stat.toJSON());
1047 LoggerW("File stat for path: %s failed with error: %d. Ignoring this entry.", path.c_str(),
1048 static_cast<std::underlying_type<FilesystemError>::type>(stat.error));
1051 ReportSuccess(result, obj);
1052 Instance::PostMessage(this, response.serialize().c_str());
1055 auto onError = [this, callback_id](FilesystemError e) {
1056 ScopeLogger("Entered into asynchronous function, onError");
1057 picojson::value response = picojson::value(picojson::object());
1058 picojson::object& obj = response.get<picojson::object>();
1059 obj["callbackId"] = picojson::value(callback_id);
1060 PrepareError(e, obj);
1061 Instance::PostMessage(this, response.serialize().c_str());
1064 FilesystemManager& fm = FilesystemManager::GetInstance();
1065 common::TaskQueue::GetInstance().Async(
1066 std::bind(&FilesystemManager::ReadDir, &fm, pathToDir, onSuccess, onError));
1069 void FilesystemInstance::FileUnlinkFile(const picojson::value& args, picojson::object& out) {
1072 "DEPRECATION WARNING: File.deleteFile() is deprecated since Tizen 5.0. Use "
1073 "FileSystemManager.deleteFile() instead.");
1075 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1076 CHECK_EXIST(args, "pathToFile", out)
1077 double callback_id = args.get("callbackId").get<double>();
1078 const std::string& pathToFile = args.get("pathToFile").get<std::string>();
1079 CHECK_STORAGE_ACCESS(pathToFile, &out);
1081 auto onSuccess = [this, callback_id]() {
1082 ScopeLogger("Entered into asynchronous function, onSuccess");
1083 picojson::value result = picojson::value();
1084 picojson::value response = picojson::value(picojson::object());
1085 picojson::object& obj = response.get<picojson::object>();
1086 obj["callbackId"] = picojson::value(callback_id);
1087 ReportSuccess(result, obj);
1088 Instance::PostMessage(this, response.serialize().c_str());
1091 auto onError = [this, callback_id](FilesystemError e) {
1092 ScopeLogger("Entered into asynchronous function, onError");
1093 picojson::value response = picojson::value(picojson::object());
1094 picojson::object& obj = response.get<picojson::object>();
1095 obj["callbackId"] = picojson::value(callback_id);
1096 PrepareError(e, obj);
1097 Instance::PostMessage(this, response.serialize().c_str());
1100 FilesystemManager& fm = FilesystemManager::GetInstance();
1101 common::TaskQueue::GetInstance().Async(
1102 std::bind(&FilesystemManager::UnlinkFile, &fm, pathToFile, onSuccess, onError));
1105 void FilesystemInstance::FileRemoveDirectory(const picojson::value& args, picojson::object& out) {
1108 "DEPRECATION WARNING: File.deleteDirectory() is deprecated since Tizen 5.0. Use "
1109 "FileSystemManager.deleteDirectory() instead.");
1111 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1112 CHECK_EXIST(args, "pathToDelete", out)
1113 double callback_id = args.get("callbackId").get<double>();
1114 const std::string& pathToDelete = args.get("pathToDelete").get<std::string>();
1115 CHECK_STORAGE_ACCESS(pathToDelete, &out);
1117 auto onSuccess = [this, callback_id]() {
1118 ScopeLogger("Entered into asynchronous function, onSuccess");
1119 picojson::value result = picojson::value();
1120 picojson::value response = picojson::value(picojson::object());
1121 picojson::object& obj = response.get<picojson::object>();
1122 obj["callbackId"] = picojson::value(callback_id);
1123 ReportSuccess(result, obj);
1124 Instance::PostMessage(this, response.serialize().c_str());
1127 auto onError = [this, callback_id](FilesystemError e) {
1128 ScopeLogger("Entered into asynchronous function, onError");
1129 picojson::value response = picojson::value(picojson::object());
1130 picojson::object& obj = response.get<picojson::object>();
1131 obj["callbackId"] = picojson::value(callback_id);
1132 PrepareError(e, obj);
1133 Instance::PostMessage(this, response.serialize().c_str());
1136 FilesystemManager& fm = FilesystemManager::GetInstance();
1137 common::TaskQueue::GetInstance().Queue(
1138 std::bind(&FilesystemManager::RemoveDirectory, &fm, pathToDelete, onSuccess, onError));
1141 void FilesystemInstance::FileCopyTo(const picojson::value& args, picojson::object& out) {
1144 "DEPRECATION WARNING: File.copyTo() is deprecated since Tizen 5.0. Use "
1145 "FileSystemManager.CopyFile() or FileSystemManager.CopyDirectory() instead.");
1147 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1148 CHECK_EXIST(args, "callbackId", out)
1150 CHECK_EXIST(args, "originFilePath", out)
1151 const std::string& originPath = args.get("originFilePath").get<std::string>();
1152 CHECK_STORAGE_ACCESS(originPath, &out);
1153 CHECK_EXIST(args, "destinationFilePath", out)
1154 const std::string& destinationPath = args.get("destinationFilePath").get<std::string>();
1155 CHECK_STORAGE_ACCESS(destinationPath, &out);
1157 CHECK_EXIST(args, "overwrite", out)
1159 double callback_id = args.get("callbackId").get<double>();
1160 const bool& overwrite = args.get("overwrite").get<bool>();
1162 auto onSuccess = [this, callback_id]() {
1163 ScopeLogger("Entered into asynchronous function, onSuccess");
1164 picojson::value result = picojson::value();
1165 picojson::value response = picojson::value(picojson::object());
1166 picojson::object& obj = response.get<picojson::object>();
1167 obj["callbackId"] = picojson::value(callback_id);
1168 ReportSuccess(result, obj);
1169 Instance::PostMessage(this, response.serialize().c_str());
1172 auto onError = [this, callback_id](FilesystemError e) {
1173 ScopeLogger("Entered into asynchronous function, onError");
1174 picojson::value response = picojson::value(picojson::object());
1175 picojson::object& obj = response.get<picojson::object>();
1176 obj["callbackId"] = picojson::value(callback_id);
1177 PrepareError(e, obj);
1178 Instance::PostMessage(this, response.serialize().c_str());
1181 FilesystemManager& fm = FilesystemManager::GetInstance();
1182 common::TaskQueue::GetInstance().Queue(std::bind(&FilesystemManager::CopyTo, &fm, originPath,
1183 destinationPath, overwrite, onSuccess, onError));
1186 void FilesystemInstance::PrepareError(const FilesystemError& error, picojson::object& out) {
1189 case FilesystemError::None:
1190 LogAndReportError(UnknownException("PLATFORM ERROR"), out);
1192 case FilesystemError::NotFound:
1193 LogAndReportError(NotFoundException("PLATFORM ERROR"), out,
1194 ("NotFoundException - PLATFORM ERROR"));
1196 case FilesystemError::FileExists:
1197 LogAndReportError(IOException("File already exists"), out,
1198 ("IOException - File already exists"));
1200 case FilesystemError::DirectoryExists:
1201 LogAndReportError(IOException("Directory already exists"), out,
1202 ("IOException - Directory already exists"));
1204 case FilesystemError::PermissionDenied:
1205 LogAndReportError(IOException("Permission denied"), out, ("IOException - Permission denied"));
1207 case FilesystemError::IOError:
1208 LogAndReportError(IOException("IO Error"), out, ("IOException - IO Error"));
1210 case FilesystemError::Other:
1211 LogAndReportError(UnknownException("PLATFORM ERROR other"), out,
1212 ("UnknownException - PLATFORM ERROR other"));
1214 case FilesystemError::InvalidValue:
1215 LogAndReportError(InvalidValuesException("PLATFORM ERROR"), out,
1216 ("InvalidValuesException - PLATFORM ERROR"));
1219 LogAndReportError(UnknownException("PLATFORM ERROR default"), out,
1220 ("UnknownException - PLATFORM ERROR default"));
1225 void FilesystemInstance::FileSystemManagerGetCanonicalPath(const picojson::value& args,
1226 picojson::object& out) {
1228 // TODO: any privilege needed?
1229 CHECK_EXIST(args, "path", out);
1231 const std::string& path = args.get("path").get<std::string>();
1233 auto onSuccess = [&](const std::string& canonicalPath) {
1234 ScopeLogger("Entered into asynchronous function, onSuccess");
1235 ReportSuccess(picojson::value(canonicalPath), out);
1238 auto onError = [&](FilesystemError e) {
1239 ScopeLogger("Entered into asynchronous function, onError");
1240 PrepareError(e, out);
1243 FilesystemManager::GetInstance().GetCanonicalPath(path, onSuccess, onError);
1248 FILE* OpenFile(const std::string& path, const std::string& fopen_mode) {
1249 FILE* file = std::fopen(path.c_str(), fopen_mode.c_str());
1251 throw std::system_error{errno, std::generic_category(), "Could not open file"};
1257 FILE* MakeParentsAndOpenFile(const std::string& path, const std::string& fopen_mode) {
1259 * If fopen fails, created parent directories have to be removed.
1260 * Save the path to the first nonexistent parent directory in the file path,
1261 * to know where to start recursive removal
1263 std::string first_nonexistent_parent = FilesystemUtils::Dirname(path);
1267 !FilesystemUtils::CheckIfExists(FilesystemUtils::Dirname(first_nonexistent_parent), &buf)) {
1268 first_nonexistent_parent = FilesystemUtils::Dirname(first_nonexistent_parent);
1271 FilesystemUtils::Mkdir(FilesystemUtils::Dirname(path), true);
1273 FILE* file = std::fopen(path.c_str(), fopen_mode.c_str());
1278 std::system_error fopen_error =
1279 std::system_error(errno, std::generic_category(), "Could not open file");
1282 FilesystemUtils::RemoveDirectoryRecursively(first_nonexistent_parent);
1283 } catch (const std::system_error& error) {
1284 LoggerD("Failed to remove created parent directories: %s", error.what());
1292 void FilesystemInstance::FileSystemManagerOpenFile(const picojson::value& args,
1293 picojson::object& out) {
1295 const int unique_id = static_cast<int>(args.get("id").get<double>());
1296 if (opened_files.find(unique_id) != opened_files.end()) {
1297 LogAndReportError(IOException("Internal error (id is already in use)"), out);
1301 bool access_checked = false;
1302 if (WriteAccessRequested(args)) {
1303 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1304 access_checked = true;
1307 if (ReadAccessRequested(args)) {
1308 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1309 access_checked = true;
1312 // File open mode received from JS layer can be different than expected by
1313 // WriteAccessRequested and ReadAccessRequested functions. In case like that
1314 // privilege would not be checked and user could gain unauthorized access to file.
1315 // To prevent this situation we only accept specific open modes.
1316 if (false == access_checked) {
1317 const std::string& open_mode = args.get("openMode").get<std::string>();
1318 LogAndReportError(TypeMismatchException("Invalid open mode: " + open_mode), out);
1322 const std::string& path = args.get("path").get<std::string>();
1324 CHECK_STORAGE_ACCESS(path, &out);
1325 const std::string open_mode = GetFopenMode(args);
1326 FILE* file = nullptr;
1328 if (ShouldMakeParents(args)) {
1329 file = MakeParentsAndOpenFile(path, open_mode);
1331 file = OpenFile(path, open_mode);
1333 } catch (const std::system_error& error) {
1334 FilesystemUtils::TranslateException(error, out);
1338 opened_files.emplace(std::make_pair(unique_id, std::make_shared<FileHandle>(file)));
1342 void FilesystemInstance::FileSystemManagerCreateDirectory(const picojson::value& args,
1343 picojson::object& out) {
1345 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1347 double callback_id = args.get("callbackId").get<double>();
1348 const std::string& path = args.get("path").get<std::string>();
1349 bool make_parents = args.get("makeParents").get<bool>();
1350 CHECK_STORAGE_ACCESS(path, &out);
1352 common::TaskQueue::GetInstance().Async([this, callback_id, path, make_parents] {
1353 picojson::value response = picojson::value(picojson::object());
1354 picojson::object& obj = response.get<picojson::object>();
1355 obj["callbackId"] = picojson::value(callback_id);
1358 FilesystemUtils::Mkdir(path, make_parents);
1359 ReportSuccess(picojson::value(path), obj);
1360 } catch (const std::system_error& e) {
1361 FilesystemUtils::TranslateException(e, obj);
1363 this->PostMessage(response.serialize().c_str());
1369 void FilesystemInstance::FileSystemManagerDeleteFile(const picojson::value& args,
1370 picojson::object& out) {
1372 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1374 double callback_id = args.get("callbackId").get<double>();
1375 const std::string& path = args.get("path").get<std::string>();
1377 CHECK_STORAGE_ACCESS(path, &out);
1378 common::TaskQueue::GetInstance().Async([this, callback_id, path] {
1379 picojson::value response = picojson::value(picojson::object());
1380 picojson::object& obj = response.get<picojson::object>();
1381 obj["callbackId"] = picojson::value(callback_id);
1383 this->PostMessage(response.serialize().c_str());
1388 if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfFile(buf)) {
1389 LogAndReportError(NotFoundException("Given path does not point to file."), obj);
1392 FilesystemUtils::Unlink(path);
1393 ReportSuccess(picojson::value(FilesystemUtils::Dirname(path)), obj);
1394 } catch (const std::system_error& e) {
1395 FilesystemUtils::TranslateException(e, obj);
1402 void FilesystemInstance::FileSystemManagerDeleteDirectory(const picojson::value& args,
1403 picojson::object& out) {
1405 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1407 double callback_id = args.get("callbackId").get<double>();
1408 const std::string& path = args.get("path").get<std::string>();
1410 CHECK_STORAGE_ACCESS(path, &out);
1411 bool recursive = args.get("recursive").get<bool>();
1413 common::TaskQueue::GetInstance().Queue([this, callback_id, path, recursive] {
1415 picojson::value response = picojson::value(picojson::object());
1416 picojson::object& obj = response.get<picojson::object>();
1417 obj["callbackId"] = picojson::value(callback_id);
1419 this->PostMessage(response.serialize().c_str());
1424 if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfDir(buf)) {
1425 LogAndReportError(NotFoundException("Given path does not point to directory."), obj);
1429 FilesystemUtils::RemoveDirectoryRecursively(path);
1431 FilesystemUtils::RemoveDirectory(path);
1433 ReportSuccess(picojson::value(FilesystemUtils::Dirname(path)), obj);
1434 } catch (const std::system_error& e) {
1435 FilesystemUtils::TranslateException(e, obj);
1442 void FilesystemInstance::FileSystemManagerCopyFile(const picojson::value& args,
1443 picojson::object& out) {
1445 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1446 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1448 double callback_id = args.get("callbackId").get<double>();
1449 const std::string& path = args.get("path").get<std::string>();
1450 CHECK_STORAGE_ACCESS(path, &out);
1451 const std::string& destination_path = args.get("destinationPath").get<std::string>();
1452 CHECK_STORAGE_ACCESS(destination_path, &out);
1453 bool overwrite = args.get("overwrite").get<bool>();
1455 common::TaskQueue::GetInstance().Queue([this, callback_id, path, destination_path, overwrite] {
1456 picojson::value response = picojson::value(picojson::object());
1457 picojson::object& obj = response.get<picojson::object>();
1458 obj["callbackId"] = picojson::value(callback_id);
1460 this->PostMessage(response.serialize().c_str());
1465 if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfFile(buf)) {
1466 LogAndReportError(NotFoundException("Given path does not point to file."), obj);
1470 if (FilesystemUtils::CheckIfExists(destination_path, &buf) && !overwrite) {
1472 IOException("Given path points to an existing resource, overwriting is not allowed."),
1476 FilesystemUtils::CopyFile(path, destination_path, overwrite);
1477 ReportSuccess(picojson::value(destination_path), obj);
1478 } catch (const std::system_error& e) {
1479 FilesystemUtils::TranslateException(e, obj);
1486 void FilesystemInstance::FileSystemManagerCopyDirectory(const picojson::value& args,
1487 picojson::object& out) {
1489 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1490 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1491 const std::string& path = args.get("path").get<std::string>();
1492 CHECK_STORAGE_ACCESS(path, &out);
1493 const std::string& destination_path = args.get("destinationPath").get<std::string>();
1494 CHECK_STORAGE_ACCESS(destination_path, &out);
1495 double callback_id = args.get("callbackId").get<double>();
1496 bool overwrite = args.get("overwrite").get<bool>();
1498 common::TaskQueue::GetInstance().Queue([this, callback_id, path, destination_path, overwrite] {
1500 picojson::value response = picojson::value(picojson::object());
1501 picojson::object& obj = response.get<picojson::object>();
1502 obj["callbackId"] = picojson::value(callback_id);
1504 this->PostMessage(response.serialize().c_str());
1509 if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfDir(buf)) {
1510 LogAndReportError(NotFoundException("Given path does not point to directory."), obj);
1514 bool exists = FilesystemUtils::CheckIfExists(destination_path, &buf);
1515 if (exists && !FilesystemUtils::CheckIfDir(buf)) {
1516 LogAndReportError(IOException("File with conflicting name already exists."), obj);
1518 } else if (!exists) {
1519 FilesystemUtils::Mkdir(destination_path);
1521 FilesystemUtils::CopyDirectory(path, destination_path, overwrite);
1522 ReportSuccess(picojson::value(destination_path), obj);
1523 } catch (const std::system_error& e) {
1524 FilesystemUtils::TranslateException(e, obj);
1531 void FilesystemInstance::FileSystemManagerMoveFile(const picojson::value& args,
1532 picojson::object& out) {
1534 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1535 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1537 const std::string& path = args.get("path").get<std::string>();
1538 CHECK_STORAGE_ACCESS(path, &out);
1539 const std::string& destination_path = args.get("destinationPath").get<std::string>();
1540 CHECK_STORAGE_ACCESS(destination_path, &out);
1541 double callback_id = args.get("callbackId").get<double>();
1542 bool overwrite = args.get("overwrite").get<bool>();
1544 common::TaskQueue::GetInstance().Queue([this, callback_id, path, destination_path, overwrite] {
1546 picojson::value response = picojson::value(picojson::object());
1547 picojson::object& obj = response.get<picojson::object>();
1548 obj["callbackId"] = picojson::value(callback_id);
1550 this->PostMessage(response.serialize().c_str());
1555 if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfFile(buf)) {
1556 LogAndReportError(NotFoundException("Given path does not point to file."), obj);
1560 if (!FilesystemUtils::CheckIfExists(destination_path, &buf) ||
1561 !FilesystemUtils::CheckIfDir(buf)) {
1562 LogAndReportError(NotFoundException("Given path does not point to directory."), obj);
1567 std::string new_path = destination_path + '/' + FilesystemUtils::PosixBasename(path);
1568 if (!overwrite && FilesystemUtils::CheckIfExists(new_path, &buf)) {
1569 LogAndReportError(IOException("File or directory with conflicting name already exists."),
1573 FilesystemUtils::MoveFile(path, new_path, overwrite);
1574 ReportSuccess(picojson::value(new_path), obj);
1575 } catch (const std::system_error& e) {
1576 FilesystemUtils::TranslateException(e, obj);
1583 void FilesystemInstance::FileSystemManagerMoveDirectory(const picojson::value& args,
1584 picojson::object& out) {
1587 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1588 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1589 double callback_id = args.get("callbackId").get<double>();
1590 const std::string& path = args.get("path").get<std::string>();
1591 CHECK_STORAGE_ACCESS(path, &out);
1592 const std::string& destination_path = args.get("destinationPath").get<std::string>();
1593 CHECK_STORAGE_ACCESS(destination_path, &out);
1594 bool overwrite = args.get("overwrite").get<bool>();
1596 common::TaskQueue::GetInstance().Queue([this, callback_id, path, destination_path, overwrite] {
1597 picojson::value response = picojson::value(picojson::object());
1598 picojson::object& obj = response.get<picojson::object>();
1599 obj["callbackId"] = picojson::value(callback_id);
1601 this->PostMessage(response.serialize().c_str());
1606 if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfDir(buf)) {
1607 LogAndReportError(NotFoundException("Given path does not point to directory."), obj);
1611 if (!FilesystemUtils::CheckIfExists(destination_path, &buf) ||
1612 !FilesystemUtils::CheckIfDir(buf)) {
1613 LogAndReportError(NotFoundException("Given path does not point to directory."), obj);
1617 std::string new_path = destination_path + '/' + FilesystemUtils::PosixBasename(path);
1618 if (FilesystemUtils::CheckIfExists(new_path, &buf) && !FilesystemUtils::CheckIfDir(buf)) {
1619 LogAndReportError(IOException("File or directory with conflicting name already exists."),
1623 FilesystemUtils::MoveDirectory(path, destination_path, overwrite);
1624 ReportSuccess(picojson::value(new_path), obj);
1625 } catch (const std::system_error& e) {
1626 FilesystemUtils::TranslateException(e, obj);
1633 void FilesystemInstance::FileSystemManagerRename(const picojson::value& args,
1634 picojson::object& out) {
1636 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1637 const std::string& path = args.get("path").get<std::string>();
1639 CHECK_STORAGE_ACCESS(path, &out);
1640 double callback_id = args.get("callbackId").get<double>();
1641 const std::string& new_name = args.get("newName").get<std::string>();
1643 common::TaskQueue::GetInstance().Async([this, callback_id, new_name, path] {
1645 picojson::value response = picojson::value(picojson::object());
1646 picojson::object& obj = response.get<picojson::object>();
1647 obj["callbackId"] = picojson::value(callback_id);
1649 this->PostMessage(response.serialize().c_str());
1654 bool exists = FilesystemUtils::CheckIfExists(path, &buf);
1656 LogAndReportError(NotFoundException("Given path does not point to file or directory."),
1660 std::string new_path{FilesystemUtils::Dirname(path) + "/" + new_name};
1662 exists = FilesystemUtils::CheckIfExists(new_path, &buf);
1664 LogAndReportError(IOException("File or directory with conflicting name already exists"),
1668 FilesystemUtils::Rename(path, new_path);
1669 ReportSuccess(picojson::value(new_path), obj);
1670 } catch (const std::system_error& e) {
1671 FilesystemUtils::TranslateException(e, obj);
1678 void FilterResult(std::vector<const char*>& names, std::vector<unsigned char>& types, bool is_type,
1679 unsigned char type) {
1680 int i = (int)names.size() - 1;
1683 if (is_type ? type != types[i] : type == types[i]) {
1684 names.erase(names.begin() + i);
1690 void FilesystemInstance::FileSystemManagerListDirectory(const picojson::value& args,
1691 picojson::object& out) {
1693 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1695 double callback_id = args.get("callbackId").get<double>();
1696 const std::string& path = args.get("path").get<std::string>();
1697 const picojson::object& filter = args.get("filter").get<picojson::object>();
1698 CHECK_STORAGE_ACCESS(path, &out);
1700 common::TaskQueue::GetInstance().Async([this, callback_id, path, filter] {
1702 picojson::value response = picojson::value(picojson::object());
1703 picojson::object& obj = response.get<picojson::object>();
1704 obj["callbackId"] = picojson::value(callback_id);
1707 std::vector<const char*> names;
1709 std::vector<unsigned char> types;
1710 FilesystemUtils::ListDirectory(path, [&](const char* name, unsigned char type) {
1711 names.push_back(name);
1712 types.push_back(type);
1715 auto it = filter.find("isFile");
1716 if (filter.end() != it) {
1717 FilterResult(names, types, it->second.get<bool>(), DT_REG);
1720 it = filter.find("isDirectory");
1721 if (filter.end() != it) {
1722 FilterResult(names, types, it->second.get<bool>(), DT_DIR);
1726 auto start_modified_it = filter.find("startModified"),
1727 end_modified_it = filter.find("endModified"),
1728 start_created_it = filter.find("startCreated"),
1729 end_created_it = filter.find("endCreated");
1730 if (filter.end() != start_modified_it || filter.end() != end_modified_it ||
1731 filter.end() != start_created_it || filter.end() != end_created_it) {
1732 auto name_iterator = names.begin();
1733 while (name_iterator != names.end()) {
1735 std::string path_with_name = path + std::string("/") + std::string(*name_iterator);
1736 int status = ::stat(path_with_name.c_str(), &buf);
1738 throw std::system_error{errno, std::generic_category(),
1739 "Failed to get last modification date of a file"};
1741 if (filter.end() != start_modified_it &&
1742 (buf.st_mtime < start_modified_it->second.get<double>())) {
1743 name_iterator = names.erase(name_iterator);
1746 if (filter.end() != end_modified_it &&
1747 (buf.st_mtime > end_modified_it->second.get<double>())) {
1748 name_iterator = names.erase(name_iterator);
1751 if (filter.end() != start_created_it &&
1752 (buf.st_ctime < start_created_it->second.get<double>())) {
1753 name_iterator = names.erase(name_iterator);
1756 if (filter.end() != end_created_it &&
1757 (buf.st_ctime > end_created_it->second.get<double>())) {
1758 name_iterator = names.erase(name_iterator);
1765 picojson::value value = picojson::value(picojson::object());
1766 picojson::object& object = value.get<picojson::object>();
1768 object["names"] = picojson::value{picojson::array_type, true};
1769 object["path"] = picojson::value(path);
1771 picojson::array& names_array = object["names"].get<picojson::array>();
1772 names_array.reserve(names.size());
1773 for (unsigned int i = 0; i < names.size(); ++i) {
1774 names_array.push_back(picojson::value(names[i]));
1777 ReportSuccess(value, obj);
1778 } catch (const std::system_error& e) {
1779 FilesystemUtils::TranslateException(e, obj);
1781 this->PostMessage(response.serialize().c_str());
1787 void FilesystemInstance::FileSystemManagerIsFile(const picojson::value& args,
1788 picojson::object& out) {
1790 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1791 const std::string& path = args.get("path").get<std::string>();
1793 CHECK_STORAGE_ACCESS(path, &out);
1794 picojson::value is_file{};
1797 bool exists = FilesystemUtils::CheckIfExists(path, &buf);
1799 LogAndReportError(NotFoundException("Given path does not point to file."), out);
1802 is_file = picojson::value{FilesystemUtils::CheckIfFile(buf)};
1803 } catch (const std::system_error& e) {
1804 FilesystemUtils::TranslateException(e, out);
1806 ReportSuccess(is_file, out);
1809 void FilesystemInstance::FileSystemManagerIsDirectory(const picojson::value& args,
1810 picojson::object& out) {
1812 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1813 const std::string& path = args.get("path").get<std::string>();
1815 CHECK_STORAGE_ACCESS(path, &out);
1816 picojson::value is_directory{};
1819 bool exists = FilesystemUtils::CheckIfExists(path, &buf);
1821 LogAndReportError(NotFoundException("Given path does not point to directory."), out);
1824 is_directory = picojson::value{FilesystemUtils::CheckIfDir(buf)};
1825 } catch (const std::system_error& e) {
1826 FilesystemUtils::TranslateException(e, out);
1828 ReportSuccess(is_directory, out);
1831 void FilesystemInstance::FileSystemManagerPathExists(const picojson::value& args,
1832 picojson::object& out) {
1834 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1835 const std::string& path = args.get("path").get<std::string>();
1837 CHECK_STORAGE_ACCESS(path, &out);
1838 picojson::value does_file_exist = picojson::value{true};
1841 bool exists = FilesystemUtils::CheckIfExists(path, &buf);
1843 does_file_exist = picojson::value{false};
1845 } catch (const std::system_error& e) {
1846 FilesystemUtils::TranslateException(e, out);
1848 ReportSuccess(does_file_exist, out);
1851 void FilesystemInstance::FileSystemManagerGetLimits(const picojson::value& args,
1852 picojson::object& out) {
1854 picojson::value response =
1855 picojson::value{picojson::array{picojson::value{static_cast<double>(NAME_MAX)},
1856 picojson::value{static_cast<double>(PATH_MAX)}}};
1857 ReportSuccess(response, out);
1860 void FilesystemInstance::FileHandleSeek(const picojson::value& args, picojson::object& out) {
1862 const int fh_id = static_cast<int>(args.get("id").get<double>());
1863 const long offset = static_cast<long>(args.get("offset").get<double>());
1864 const std::string& _whence = args.get("whence").get<std::string>();
1866 auto fh = opened_files.find(fh_id);
1868 int whence = SEEK_SET;
1870 if ("CURRENT" == _whence) {
1872 LoggerD("SEEK_CUR selected");
1873 } else if ("END" == _whence) {
1875 LoggerD("SEEK_END selected");
1878 if (opened_files.end() == fh) {
1879 LogAndReportError(IOException("Invalid FileHandle"), out);
1883 auto handle = fh->second;
1885 auto logic = [handle, whence, offset](decltype(out) out) {
1886 long ret = fseek(handle->file_handle, offset, whence);
1888 LoggerE("fseek returned failed");
1889 std::string error_message =
1890 std::string("seek failed, fileHandle may be corrupted, error message: ") +
1891 GetErrorString(errno);
1892 LogAndReportError(IOException(error_message.c_str()), out);
1896 ret = ftell(handle->file_handle);
1898 LoggerE("ftell returned failed");
1899 std::string error_message =
1900 std::string("seek failed, fileHandle may be corrupted, error message: ") +
1901 GetErrorString(errno);
1902 LogAndReportError(IOException(error_message.c_str()), out);
1906 ReportSuccess(picojson::value((double)ret), out);
1909 bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
1915 double callback_id = args.get("callbackId").get<double>();
1916 this->worker.add_job([this, callback_id, logic] {
1917 picojson::value response = picojson::value(picojson::object());
1918 picojson::object& async_out = response.get<picojson::object>();
1919 async_out["callbackId"] = picojson::value(callback_id);
1921 this->PostMessage(response.serialize().c_str());
1929 void FilesystemInstance::FileHandleReadString(const picojson::value& args, picojson::object& out) {
1931 CHECK_EXIST(args, "id", out)
1932 const int fh_id = static_cast<int>(args.get("id").get<double>());
1933 const std::string& encoding =
1934 args.contains("encoding") ? args.get("encoding").get<std::string>() : "UTF-8";
1935 if (encoding != kISOEncoding && encoding != kUTF8Encoding) {
1936 LogAndReportError(NotSupportedException("Given encoding is not supported."), out);
1940 auto fh = opened_files.find(fh_id);
1941 if (opened_files.end() == fh) {
1942 LogAndReportError(IOException("Invalid FileHandle"), out);
1947 bool whole_file = false;
1948 if (args.contains("count")) {
1949 // If user passed 'count' parameter, we need to read at most 'count' characters.
1950 double count_double = args.get("count").get<double>();
1951 if (std::string::npos <= static_cast<unsigned long long>(count_double)) {
1952 LogAndReportError(InvalidValuesException("Invalid count was given"), out);
1955 count = static_cast<size_t>(count_double);
1958 count = file_size(fh->second->file_handle);
1960 } catch (const std::system_error& e) {
1961 LogAndReportError(IOException(e.what()), out);
1965 LoggerD("count: %zu", count);
1967 auto handle = fh->second;
1969 auto logic = [handle, count, encoding, whole_file](decltype(out) out) {
1971 size_t read_bytes = 0;
1972 std::vector<std::uint8_t> buf = read_file(handle->file_handle, count, &read_bytes);
1973 buf.resize(read_bytes); // this protects from reporting too big arrays to JS
1974 if (encoding == kISOEncoding) { // for iso-8859-1 1 byte is equal to 1 character
1975 out["result"] = picojson::value(picojson::string_type, true);
1976 latin1::to_utf8(buf, out["result"].get<std::string>());
1979 unsigned long char_count;
1980 short expected_extension_bytes;
1981 if (!validate_and_check_character_count(buf, char_count, expected_extension_bytes)) {
1983 IOException("File doesn't contain UTF-8 encoded string with given length"), out);
1986 LoggerD("char_count: %lu", char_count);
1987 LoggerD("ftell: %ld", ftell(handle->file_handle));
1989 handle->file_handle))) { // read number of characters if not whole file read
1990 LoggerD("count parameter given: %zu", count);
1992 !add_utf8_chars_to_buffer(handle->file_handle, buf, count - char_count,
1993 expected_extension_bytes)) {
1995 IOException("File doesn't contain UTF-8 encoded string with given length"), out);
1998 const char* str = (const char*)buf.data();
1999 ReportSuccess(picojson::value{str, buf.size()}, out);
2001 } catch (std::runtime_error& e) {
2002 LoggerE("Cannot read, cause: %s", e.what());
2003 LogAndReportError(IOException(e.what()), out);
2007 bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
2013 double callback_id = args.get("callbackId").get<double>();
2014 this->worker.add_job([this, callback_id, logic] {
2015 picojson::value response = picojson::value(picojson::object());
2016 picojson::object& async_out = response.get<picojson::object>();
2017 async_out["callbackId"] = picojson::value(callback_id);
2019 this->PostMessage(response.serialize().c_str());
2027 void FilesystemInstance::FileHandleWriteString(const picojson::value& args, picojson::object& out) {
2029 CHECK_EXIST(args, "id", out)
2030 CHECK_EXIST(args, "string", out)
2031 const int fh_id = static_cast<int>(args.get("id").get<double>());
2032 const std::string& str = args.get("string").get<std::string>();
2033 const std::string& encoding =
2034 args.contains("encoding") ? args.get("encoding").get<std::string>() : "UTF-8";
2035 if (encoding != kISOEncoding && encoding != kUTF8Encoding) {
2036 LogAndReportError(NotSupportedException("Given encoding is not supported."), out);
2040 auto fh = opened_files.find(fh_id);
2041 if (opened_files.end() == fh) {
2042 LogAndReportError(IOException("Invalid FileHandle"), out);
2046 auto handle = fh->second;
2048 auto logic = [str, handle, encoding](decltype(out) out) {
2050 std::vector<std::uint8_t> data;
2051 data.resize(str.size());
2053 if (encoding == kISOEncoding) {
2054 latin1::from_utf8(str, data);
2056 LoggerD("copying string memory to vector");
2057 std::memcpy(data.data(), str.data(), str.size());
2059 write_file(data.data(), data.size(), handle->file_handle);
2060 ReportSuccess(picojson::value{(double)data.size()}, out);
2061 } catch (std::runtime_error& e) {
2062 LoggerE("Cannot write, cause: %s", e.what());
2063 LogAndReportError(IOException(e.what()), out);
2067 bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
2073 double callback_id = args.get("callbackId").get<double>();
2074 this->worker.add_job([this, callback_id, logic] {
2075 picojson::value response = picojson::value(picojson::object());
2076 picojson::object& async_out = response.get<picojson::object>();
2077 async_out["callbackId"] = picojson::value(callback_id);
2079 this->PostMessage(response.serialize().c_str());
2087 void FilesystemInstance::FileHandleReadData(const picojson::value& args, picojson::object& out) {
2089 CHECK_EXIST(args, "id", out)
2090 const int fh_id = static_cast<int>(args.get("id").get<double>());
2091 auto fh = opened_files.find(fh_id);
2093 if (opened_files.end() == fh) {
2094 LoggerE("FileHandle with id: %d not found", fh_id);
2095 LogAndReportError(IOException("Invalid FileHandle"), out);
2100 // We need to check how many bytes is it possible to read until the EOF.
2102 // We need to read from file exactly the minimum value of 'size' given by user and the
2103 // 'size ' to avoid returning array with redundant data (which would be equal to 0).
2104 size = file_bytes_to_eof(fh->second->file_handle);
2105 if (args.contains("size")) {
2106 // If user passed 'size' parameter, we need to read at most 'size' bytes.
2107 double size_double = args.get("size").get<double>();
2108 if (std::string::npos <= static_cast<unsigned long long>(size_double)) {
2109 LogAndReportError(InvalidValuesException("Invalid size was given"), out);
2112 size = std::min(static_cast<size_t>(size_double), size);
2114 } catch (const std::system_error& e) {
2115 LogAndReportError(IOException(e.what()), out);
2119 LoggerD("size: %zu", size);
2121 auto handle = fh->second;
2123 auto logic = [handle, size](decltype(out) out) {
2125 std::vector<std::uint8_t> data = read_file(handle->file_handle, size);
2126 out["result"] = picojson::value(picojson::string_type, true);
2127 encode_binary_in_string(data, out["result"].get<std::string>());
2128 } catch (std::runtime_error& e) {
2129 LoggerE("Cannot read, cause: %s", e.what());
2130 LogAndReportError(IOException(e.what()), out);
2134 bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
2140 double callback_id = args.get("callbackId").get<double>();
2141 this->worker.add_job([this, callback_id, logic] {
2142 picojson::value response = picojson::value(picojson::object());
2143 picojson::object& async_out = response.get<picojson::object>();
2144 async_out["callbackId"] = picojson::value(callback_id);
2146 this->PostMessage(response.serialize().c_str());
2154 void FilesystemInstance::FileHandleWriteData(const picojson::value& args, picojson::object& out) {
2156 CHECK_EXIST(args, "id", out)
2157 CHECK_EXIST(args, "data", out)
2158 const auto& str = args.get("data").get<std::string>();
2159 const int fh_id = static_cast<int>(args.get("id").get<double>());
2161 auto fh = opened_files.find(fh_id);
2162 if (opened_files.end() == fh) {
2163 LoggerE("FileHandle with id: %d not found", fh_id);
2164 LogAndReportError(IOException("Invalid FileHandle"), out);
2168 auto handle = fh->second;
2170 auto logic = [str, handle](decltype(out) out) {
2172 std::vector<std::uint8_t> bytes;
2173 decode_binary_from_string(str, bytes);
2174 write_file(bytes.data(), bytes.size(), handle->file_handle);
2175 } catch (std::runtime_error& e) {
2176 LogAndReportError(IOException(e.what()), out);
2180 bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
2186 double callback_id = args.get("callbackId").get<double>();
2187 this->worker.add_job([this, callback_id, logic] {
2188 picojson::value response = picojson::value(picojson::object());
2189 picojson::object& async_out = response.get<picojson::object>();
2190 async_out["callbackId"] = picojson::value(callback_id);
2192 this->PostMessage(response.serialize().c_str());
2200 void FilesystemInstance::FileHandleFlush(const picojson::value& args, picojson::object& out) {
2202 const int fh_id = static_cast<int>(args.get("id").get<double>());
2204 auto fh = opened_files.find(fh_id);
2205 if (opened_files.end() == fh) {
2206 LogAndReportError(IOException("Invalid FileHandle"), out);
2210 auto handle = fh->second;
2212 auto logic = [handle](decltype(out) out) {
2213 int ret = fflush(handle->file_handle);
2215 std::string error_message =
2216 std::string("flush failed, error message: ") + GetErrorString(errno);
2217 LogAndReportError(IOException(error_message.c_str()), out);
2221 bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
2227 double callback_id = args.get("callbackId").get<double>();
2228 this->worker.add_job([this, callback_id, logic] {
2229 picojson::value response = picojson::value(picojson::object());
2230 picojson::object& async_out = response.get<picojson::object>();
2231 async_out["callbackId"] = picojson::value(callback_id);
2233 this->PostMessage(response.serialize().c_str());
2241 void FilesystemInstance::FileHandleSync(const picojson::value& args, picojson::object& out) {
2243 const int fh_id = static_cast<int>(args.get("id").get<double>());
2245 auto fh = opened_files.find(fh_id);
2246 if (opened_files.end() == fh) {
2247 LogAndReportError(IOException("Invalid FileHandle"), out);
2251 auto handle = fh->second;
2253 auto logic = [handle](decltype(out) out) {
2254 int ret = fsync(fileno(handle->file_handle));
2256 std::string error_message =
2257 std::string("sync failed, error message: ") + GetErrorString(errno);
2258 LogAndReportError(IOException(error_message.c_str()), out);
2262 bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
2268 double callback_id = args.get("callbackId").get<double>();
2269 this->worker.add_job([this, callback_id, logic] {
2270 picojson::value response = picojson::value(picojson::object());
2271 picojson::object& async_out = response.get<picojson::object>();
2272 async_out["callbackId"] = picojson::value(callback_id);
2274 this->PostMessage(response.serialize().c_str());
2282 void FilesystemInstance::FileHandleClose(const picojson::value& args, picojson::object& out) {
2284 const int fh_id = static_cast<int>(args.get("id").get<double>());
2285 auto fh = opened_files.find(fh_id);
2286 if (opened_files.end() == fh) {
2287 LogAndReportError(IOException("Invalid FileHandle"), out);
2291 std::shared_ptr<FileHandle> handle = fh->second;
2292 opened_files.erase(fh);
2294 auto logic = [handle](decltype(out) out) {
2295 if (!handle->file_handle) {
2296 LogAndReportError(IOException("File handle already closed."), out);
2299 int ret = fclose(handle->file_handle);
2300 handle->file_handle = nullptr;
2302 std::string error_message =
2303 std::string("close failed, error message: ") + GetErrorString(errno);
2304 LogAndReportError(IOException(error_message.c_str()), out);
2308 bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
2314 std::condition_variable conditional_variable;
2315 // adding empty job to worker's queue, in order to wait for all jobs to be done before closing
2317 this->worker.add_job([] {},
2318 [&conditional_variable, &mutex, &ready, &done, logic, &out] {
2320 std::unique_lock<std::mutex> lock(mutex);
2321 conditional_variable.wait(lock, [&ready] { return ready; });
2325 conditional_variable.notify_one();
2329 // let know that close is ready
2330 std::unique_lock<std::mutex> lock(mutex);
2333 conditional_variable.notify_one();
2337 std::unique_lock<std::mutex> lock(mutex);
2338 conditional_variable.wait(lock, [&done] { return done; });
2340 handle->file_handle = nullptr;
2343 double callback_id = args.get("callbackId").get<double>();
2344 this->worker.add_job([this, callback_id, logic] {
2345 picojson::value response = picojson::value(picojson::object());
2346 picojson::object& async_out = response.get<picojson::object>();
2347 async_out["callbackId"] = picojson::value(callback_id);
2349 this->PostMessage(response.serialize().c_str());
2359 } // namespace filesystem
2360 } // namespace extension