Merge "[Mediacontroller] Removed usage of removed native API" into tizen
[platform/core/api/webapi-plugins.git] / src / filesystem / filesystem_instance.cc
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include "filesystem/filesystem_instance.h"
18
19 #include <linux/limits.h>
20 #include <cstdint>
21 #include <functional>
22 #include <stdexcept>
23
24 #include <sys/stat.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"
33
34 namespace extension {
35 namespace filesystem {
36
37 namespace {
38
39 using common::tools::GetErrorString;
40
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";
44
45 const std::string kISOEncoding = "ISO-8859-1";
46 const std::string kUTF8Encoding = "UTF-8";
47
48 std::string GetFopenMode(const picojson::value& args) {
49   ScopeLogger();
50   const std::string& open_mode = args.get("openMode").get<std::string>();
51
52   if ("rw" == open_mode) {
53     return "r+";
54   } else if ("rwo" == open_mode) {
55     return "w+";
56   }
57
58   return open_mode;
59 }
60
61 bool WriteAccessRequested(const picojson::value& args) {
62   ScopeLogger();
63   const std::string& open_mode = args.get("openMode").get<std::string>();
64
65   return "a" == open_mode || "rw" == open_mode || "rwo" == open_mode || "w" == open_mode;
66 }
67
68 bool ReadAccessRequested(const picojson::value& args) {
69   ScopeLogger();
70   const std::string& open_mode = args.get("openMode").get<std::string>();
71
72   return "r" == open_mode || "rw" == open_mode || "rwo" == open_mode;
73 }
74
75 bool ShouldMakeParents(const picojson::value& args) {
76   ScopeLogger();
77   const std::string& path = args.get("path").get<std::string>();
78   struct stat buf {};
79   if (FilesystemUtils::CheckIfExists(FilesystemUtils::Dirname(path), &buf)) {
80     return false;
81   }
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);
85 }
86 }
87
88 using namespace common;
89 using namespace extension::filesystem;
90 using namespace std::string_literals;
91
92 FileHandle::~FileHandle() {
93   ScopeLogger();
94
95   if (file_handle && std::fclose(file_handle)) {
96     LoggerE("close file failed, error message: %s", GetErrorString(errno).c_str());
97   }
98 }
99
100 FilesystemInstance::FilesystemInstance() {
101   ScopeLogger();
102
103   using std::placeholders::_1;
104   using std::placeholders::_2;
105
106 #define REGISTER_SYNC(c, x) RegisterSyncHandler(c, std::bind(&FilesystemInstance::x, this, _1, _2));
107
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_fetchVirtualRoots", FilesystemFetchVirtualRoots);
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);
128
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);
143
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);
152
153 #undef REGISTER_SYNC
154   FilesystemManager::GetInstance().AddListener(this);
155 }
156
157 FilesystemInstance::~FilesystemInstance() {
158   ScopeLogger();
159   worker.stop();
160   FilesystemManager::GetInstance().StopListening();
161   FilesystemManager::GetInstance().RemoveListener();
162 }
163
164 #define CHECK_EXIST(args, name, out)                                             \
165   if (!args.contains(name)) {                                                    \
166     LogAndReportError(TypeMismatchException(name " is required argument"), out); \
167     return;                                                                      \
168   }
169
170 void FilesystemInstance::FileCreateSync(const picojson::value& args, picojson::object& out) {
171   ScopeLogger();
172   LoggerW(
173       "DEPRECATION WARNING: File.createFile() is deprecated since Tizen 5.0. Use "
174       "FileSystemManager.openFile() instead.");
175
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);
180
181   auto onSuccess = [&](const FilesystemStat& data) {
182     ScopeLogger("Entered into asynchronous function, onSuccess");
183     ReportSuccess(data.toJSON(), out);
184   };
185
186   auto onError = [&](FilesystemError e) {
187     ScopeLogger("Entered into asynchronous function, onError");
188     PrepareError(e, out);
189   };
190
191   FilesystemManager::GetInstance().CreateFile(location, onSuccess, onError);
192 }
193
194 void FilesystemInstance::FileRename(const picojson::value& args, picojson::object& out) {
195   ScopeLogger();
196   LoggerW(
197       "DEPRECATION WARNING: File.moveTo() is deprecated since Tizen 5.0. Use "
198       "FileSystemManager.moveFile() or FileSystemManager.moveDirectory() instead.");
199
200   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
201   CHECK_EXIST(args, "callbackId", out)
202
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);
209
210   double callback_id = args.get("callbackId").get<double>();
211
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());
219   };
220
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());
228   };
229
230   FilesystemManager& fsm = FilesystemManager::GetInstance();
231   common::TaskQueue::GetInstance().Async(
232       std::bind(&FilesystemManager::Rename, &fsm, oldPath, newPath, onSuccess, onError));
233 }
234
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) {
237   ScopeLogger();
238   str.reserve(str.size() + buf.size());
239
240   for (std::uint8_t byte : buf) {
241     if (byte < 128) {
242       str += byte;
243       continue;
244     }
245     str += 0xC0 | (byte >> 6);
246     str += 0x80 | (byte & 0x3F);
247   }
248 }
249
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) {
252   ScopeLogger();
253   buf.reserve(buf.size() + str.size());
254
255   const std::uint8_t* it = (std::uint8_t*)str.data();
256   const std::uint8_t* end = it + str.size();
257   while (it != end) {
258     if (*it < 128) {
259       buf.push_back(*it++);
260       continue;
261     }
262     auto b1 = *it++;
263     if (it == end) {
264       throw std::runtime_error("internal error (invalid UTF-8 sequence)");
265     }
266     auto b2 = *it++;
267     unsigned int x = ((b1 & 0x1F) << 6) | (b2 & 0x3F);
268     buf.push_back(x);
269   }
270 }
271
272 namespace latin1 {
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;
277 }
278
279 static constexpr std::size_t NPOS = (std::size_t)(-1);
280
281 /**
282  * On failure throws std::system_error
283  */
284 static std::size_t file_size(FILE* file) {
285   ScopeLogger();
286
287   struct ::stat buf;
288   int status = ::fstat(::fileno(file), &buf);
289   if (status != 0) {
290     throw std::system_error{errno, std::generic_category(), "failed to get file size"};
291   }
292
293   return buf.st_size;
294 }
295
296 /**
297  * Returns the amount of bytes to the EOF starting from current file-position indicator.
298  *
299  * On failure throws std::system_error
300  */
301 static std::size_t file_bytes_to_eof(FILE* file) {
302   ScopeLogger();
303
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)};
309   }
310   return total_fize_size - static_cast<size_t>(file_position);
311 }
312
313 static std::vector<std::uint8_t> read_file(FILE* file, std::size_t length = NPOS,
314                                            std::size_t* read_bytes = nullptr);
315
316 /**
317  * Returns a buffer. If length is NPOS, then it reads whole file, up to the end.
318  * On failure throws std::runtime_error
319  */
320 static std::vector<std::uint8_t> read_file(std::string path, long offset = 0,
321                                            std::size_t length = NPOS) {
322   ScopeLogger();
323
324   FILE* file = std::fopen(path.c_str(), "r");
325   if (!file) {
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};
328   }
329
330   SCOPE_EXIT {
331     int status = std::fclose(file);
332     if (status) {
333       LoggerE("Cannot close file!");
334     }
335   };
336
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};
340   }
341
342   if (NPOS == length) {
343     length = file_size(file) - offset;
344   }
345
346   return read_file(file, length);
347 }
348
349 /**
350  * Returns a buffer. If length is NPOS, then it reads whole file, up to the end.
351  * On failure throws std::runtime_error
352  */
353 static std::vector<std::uint8_t> read_file(FILE* file, std::size_t length /*= NPOS*/,
354                                            std::size_t* read_bytes /* = nullptr*/) {
355   ScopeLogger();
356
357   // By default reads whole file. Get the file size.
358   if (NPOS == length) {
359     length = file_size(file);
360   }
361
362   std::vector<std::uint8_t> out_buf;
363   try {
364     out_buf.resize(length);
365   } catch (std::bad_alloc& err) {
366     throw std::runtime_error{"Could not allocate memory"};
367   }
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);
372
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);
376     }
377
378     if (std::feof(file)) {
379       LoggerD("File is at end before buffer is filled. Finish.");
380       break;
381     }
382   }
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
385   // changed.
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);
390   }
391   return out_buf;
392 }
393
394 /**
395  * On failure throws std::runtime_error
396  */
397 void write_file(const std::uint8_t* data, std::size_t len, FILE* file) {
398   ScopeLogger();
399
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);
404
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);
408     }
409   }
410
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);
414   }
415 }
416
417 /**
418  * On failure throws std::runtime_error
419  */
420 void write_file(const std::uint8_t* data, std::size_t len, std::string path, long offset,
421                 const char* mode) {
422   ScopeLogger();
423
424   FILE* file = std::fopen(path.c_str(), mode);
425
426   if (!file) {
427     std::string err_msg = std::string("Cannot open file to write. ") + GetErrorString(errno);
428     throw std::runtime_error(err_msg);
429   }
430
431   SCOPE_EXIT {
432     int status = std::fclose(file);
433     if (status) {
434       LoggerE("Cannot close file!");
435     }
436   };
437
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};
441   }
442
443   write_file(data, len, file);
444 }
445
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
451
452 enum class ByteOfUTF8Classification {
453   NOT_VALID,
454   ONE_BYTE_CHAR,
455   FIRST_OF_2_BYTES,
456   FIRST_OF_3_BYTES,
457   FIRST_OF_4_BYTES,
458   EXTENSION_BYTE
459 };
460
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;
468           } else {
469             return ByteOfUTF8Classification::FIRST_OF_4_BYTES;
470           }
471         } else {
472           return ByteOfUTF8Classification::FIRST_OF_3_BYTES;
473         }
474       } else {
475         return ByteOfUTF8Classification::FIRST_OF_2_BYTES;
476       }
477     } else {
478       return ByteOfUTF8Classification::EXTENSION_BYTE;
479     }
480   } else {
481     return ByteOfUTF8Classification::ONE_BYTE_CHAR;
482   }
483 }
484
485 void skip_partial_character(std::vector<std::uint8_t>& buf) {
486   auto buf_position = buf.begin();
487
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");
492   }
493 }
494
495 bool validate_and_check_character_count(std::vector<std::uint8_t>& buf, unsigned long& char_count,
496                                         short& no_of_extensions_expected) {
497   ScopeLogger();
498   char_count = 0;
499   no_of_extensions_expected = 0;
500   auto buf_position = buf.begin();
501
502   skip_partial_character(buf);
503
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) {
509           return false;
510         } else if (0 == no_of_extensions_expected) {
511           char_count++;
512         }
513         break;
514       case ByteOfUTF8Classification::ONE_BYTE_CHAR:
515         if (0 != no_of_extensions_expected) {
516           return false;
517         }
518         char_count++;
519         break;
520       case ByteOfUTF8Classification::FIRST_OF_2_BYTES:
521         if (0 != no_of_extensions_expected) {
522           return false;
523         }
524         no_of_extensions_expected = 1;
525         break;
526       case ByteOfUTF8Classification::FIRST_OF_3_BYTES:
527         if (0 != no_of_extensions_expected) {
528           return false;
529         }
530         no_of_extensions_expected = 2;
531         break;
532       case ByteOfUTF8Classification::FIRST_OF_4_BYTES:
533         if (0 != no_of_extensions_expected) {
534           return false;
535         }
536         no_of_extensions_expected = 3;
537         break;
538       case ByteOfUTF8Classification::NOT_VALID:
539         return false;
540       default:
541         LoggerE("Abnormal value returned from is_utf8_byte function");
542     }
543     buf_position++;
544   }
545   return true;
546 }
547
548 /*
549  * add_utf8_chars_to_buffer
550  * Method returns false if byte read is not a valid utf8 char
551  */
552 bool add_utf8_chars_to_buffer(FILE* file, std::vector<std::uint8_t>& buf, int chars_to_read,
553                               short& extension_bytes_expected) {
554   int character;
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) {
561         return false;
562       }
563       buf.push_back(character);
564       if (!--extension_bytes_expected) {
565         chars_to_read--;
566       }
567       continue;
568     }
569     character = getc(file);
570     if (EOF == character) {
571       return false;
572     }
573     buf.push_back(character);
574     switch (is_utf8_byte(character)) {
575       case ByteOfUTF8Classification::ONE_BYTE_CHAR:
576         chars_to_read--;
577         break;
578       case ByteOfUTF8Classification::FIRST_OF_2_BYTES:
579         extension_bytes_expected = 1;
580         break;
581       case ByteOfUTF8Classification::FIRST_OF_3_BYTES:
582         extension_bytes_expected = 2;
583         break;
584       case ByteOfUTF8Classification::FIRST_OF_4_BYTES:
585         extension_bytes_expected = 3;
586         break;
587       case ByteOfUTF8Classification::EXTENSION_BYTE:
588         LoggerD("unexpected EXTENSION_BYTE");
589         return false;
590       case ByteOfUTF8Classification::NOT_VALID:
591         LoggerE("unexpected NOT_VALID byte while reading utf-8");
592         return false;
593       default:
594         LoggerE("Abnormal. Last read char: %c: ", character);
595         return false;
596     }
597   }
598   return true;
599 }
600
601 namespace base64 {
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};
621
622 /**
623  * On error throws std::runtime_error
624  */
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;
629
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);
634   while (p != end) {
635     b1 = char_to_int[*p++];
636     b2 = char_to_int[*p++];
637     b3 = char_to_int[*p++];
638     b4 = char_to_int[*p++];
639
640     if (b1 > 63 || b2 > 63 || b3 > 63 || b4 > 63) throw std::runtime_error("invalid character");
641
642     out.push_back((b1 << 2) | (b2 >> 4));
643     out.push_back((b2 << 4) | (b3 >> 2));
644     out.push_back((b3 << 6) | b4);
645   }
646   b1 = char_to_int[*p++];
647   b2 = char_to_int[*p++];
648   b3 = char_to_int[*p++];
649   b4 = char_to_int[*p++];
650
651   if (b1 == PAD || b1 == INV || b2 == PAD || b2 == INV || b3 == INV || b4 == INV)
652     throw std::runtime_error("invalid character");
653
654   out.push_back((b1 << 2) | (b2 >> 4));
655   if (b3 == PAD) {
656     if (b4 != PAD) throw std::runtime_error("invalid character");
657   } else {
658     out.push_back((b2 << 4) | (b3 >> 2));
659     if (b4 != PAD) out.push_back((b3 << 6) | b4);
660   }
661
662   return out;
663 }
664 }  // namespace base64
665
666 void FilesystemInstance::FileReadString(const picojson::value& args, picojson::object& out) {
667   ScopeLogger();
668   LoggerW(
669       "DEPRECATION WARNING: This method is deprecated since Tizen 5.0.Use FileHandle.readString() "
670       "or FileHandle.readStringNonBlocking() instead.");
671
672   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
673   CHECK_EXIST(args, "location", out)
674   CHECK_EXIST(args, "offset", out)
675
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";
681
682   try {
683     std::vector<std::uint8_t> buf = read_file(location, offset, length);
684
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>());
688       ReportSuccess(out);
689     } else {  // default: UTF-8
690       buf.push_back('\0');
691       const char* str = (const char*)buf.data();
692       ReportSuccess(picojson::value{str}, out);
693     }
694   } catch (std::runtime_error& e) {
695     LoggerE("Cannot read file %s, cause: %s", location.c_str(), e.what());
696     PrepareError(FilesystemError::Other, out);
697   }
698 }
699
700 void FilesystemInstance::FileReadBytes(const picojson::value& args, picojson::object& out) {
701   ScopeLogger();
702   LoggerW(
703       "DEPRECATION WARNING: This method is deprecated since Tizen 5.0. Use FileHandle.readData() "
704       "or FileHandle.readDataNonBlocking() instead.");
705
706   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
707   CHECK_EXIST(args, "location", out)
708   CHECK_EXIST(args, "offset", out)
709   CHECK_EXIST(args, "length", out)
710
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>());
714
715   try {
716     std::vector<std::uint8_t> out_data = read_file(location, offset, length);
717
718     out["result"] = picojson::value(picojson::string_type, true);
719     encode_binary_in_string(out_data, out["result"].get<std::string>());
720     ReportSuccess(out);
721   } catch (std::runtime_error& e) {
722     LoggerE("Cannot read file %s, cause: %s", location.c_str(), e.what());
723     PrepareError(FilesystemError::Other, out);
724   }
725 }
726
727 void FilesystemInstance::FileWriteString(const picojson::value& args, picojson::object& out) {
728   ScopeLogger();
729   LoggerW(
730       "DEPRECATION WARNING: FileStream.write() is deprecated since Tizen 5.0. Use "
731       "FileHandle.writeString() or FileHandle.writeStringNonBlocking() instead.");
732
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)
738
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";
746
747   try {
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);
756     }
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);
760     return;
761   }
762
763   ReportSuccess(out);
764 }
765
766 void FilesystemInstance::FileWriteBytes(const picojson::value& args, picojson::object& out) {
767   ScopeLogger();
768   LoggerW(
769       "DEPRECATION WARNING: FileStream.writeBytes() is deprecated since Tizen 5.0. To read and Use "
770       "FileHandle.writeData() or FileHandle.writeDataNonBlocking() instead.");
771
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)
777
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+";
783
784   try {
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);
791     return;
792   }
793
794   ReportSuccess(out);
795 }
796
797 void FilesystemInstance::FileWriteBase64(const picojson::value& args, picojson::object& out) {
798   ScopeLogger();
799   LoggerW(
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.");
803
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)
809
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+";
815
816   std::vector<std::uint8_t> data;
817   try {
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);
822     return;
823   }
824
825   try {
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);
831   }
832 }
833
834 void FilesystemInstance::FileStat(const picojson::value& args, picojson::object& out) {
835   ScopeLogger();
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);
840
841   CHECK_EXIST(args, "callbackId", out)
842   double callback_id = args.get("callbackId").get<double>();
843
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());
851   };
852
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());
860   };
861
862   FilesystemManager& fsm = FilesystemManager::GetInstance();
863   common::TaskQueue::GetInstance().Async(
864       std::bind(&FilesystemManager::StatPath, &fsm, location, onSuccess, onError));
865 }
866
867 void FilesystemInstance::FileStatSync(const picojson::value& args, picojson::object& out) {
868   ScopeLogger();
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);
873
874   auto onSuccess = [&](const FilesystemStat& data) {
875     ScopeLogger("Entered into asynchronous function, onSuccess");
876     ReportSuccess(data.toJSON(), out);
877   };
878
879   auto onError = [&](FilesystemError e) {
880     ScopeLogger("Entered into asynchronous function, onError");
881     PrepareError(e, out);
882   };
883
884   FilesystemManager::GetInstance().StatPath(location, onSuccess, onError);
885 }
886
887 void FilesystemInstance::FilesystemFetchVirtualRoots(const picojson::value& args,
888                                                      picojson::object& out) {
889   ScopeLogger();
890
891   auto onSuccess = [&](const std::vector<common::VirtualRoot>& result) {
892     ScopeLogger("Entered into asynchronous function, onSuccess");
893     picojson::array roots;
894     for (const auto& root : result) {
895       roots.push_back(root.ToJson());
896     }
897     ReportSuccess(picojson::value(roots), out);
898   };
899
900   auto onError = [&](FilesystemError e) {
901     ScopeLogger("Entered into asynchronous function, onError");
902     PrepareError(e, out);
903   };
904
905   FilesystemManager::GetInstance().GetVirtualRoots(onSuccess, onError);
906 }
907
908 void FilesystemInstance::FileSystemManagerFetchStorages(const picojson::value& args,
909                                                         picojson::object& out) {
910   ScopeLogger();
911
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());
918     }
919     ReportSuccess(picojson::value(storages), out);
920   };
921
922   auto onError = [&](FilesystemError e) {
923     ScopeLogger("Entered into asynchronous function, onError");
924     PrepareError(e, out);
925   };
926
927   FilesystemManager::GetInstance().FetchStorages(onSuccess, onError);
928 }
929 void FilesystemInstance::StartListening(const picojson::value& args, picojson::object& out) {
930   ScopeLogger();
931   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
932   FilesystemManager::GetInstance().StartListening();
933   ReportSuccess(out);
934 }
935
936 void FilesystemInstance::StopListening(const picojson::value& args, picojson::object& out) {
937   ScopeLogger();
938   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
939   FilesystemManager::GetInstance().StopListening();
940   ReportSuccess(out);
941 }
942
943 void FilesystemInstance::onFilesystemStateChangeSuccessCallback(const common::Storage& storage) {
944   ScopeLogger();
945
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());
953 }
954
955 void FilesystemInstance::onFilesystemStateChangeErrorCallback() {
956   ScopeLogger();
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());
963 }
964
965 void FilesystemInstance::FileSystemManagerMakeDirectory(const picojson::value& args,
966                                                         picojson::object& out) {
967   ScopeLogger();
968   CHECK_EXIST(args, "callbackId", out)
969   CHECK_EXIST(args, "location", out)
970
971   double callback_id = args.get("callbackId").get<double>();
972   const std::string& location = args.get("location").get<std::string>();
973
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)
980       ReportSuccess(obj);
981     else
982       PrepareError(e, obj);
983     Instance::PostMessage(this, response.serialize().c_str());
984   };
985
986   auto onAction = [location, onResult]() {
987     ScopeLogger("Entered into asynchronous function, onAction");
988     FilesystemManager::GetInstance().MakeDirectory(location, onResult);
989   };
990
991   common::TaskQueue::GetInstance().Async(onAction);
992 }
993
994 void FilesystemInstance::FileSystemManagerMakeDirectorySync(const picojson::value& args,
995                                                             picojson::object& out) {
996   ScopeLogger();
997   LoggerW(
998       "DEPRECATION WARNING: File.createDirectory() is deprecated since Tizen 5.0. Use "
999       "FileSystemManager.createDirectory() instead.");
1000
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);
1005
1006   auto onResult = [&](FilesystemError e) {
1007     ScopeLogger("Entered into asynchronous function, onResult");
1008     if (e == FilesystemError::DirectoryExists)
1009       ReportSuccess(out);
1010     else
1011       PrepareError(e, out);
1012   };
1013
1014   FilesystemManager::GetInstance().MakeDirectory(location, onResult);
1015 }
1016
1017 void FilesystemInstance::ReadDir(const picojson::value& args, picojson::object& out) {
1018   ScopeLogger();
1019   LoggerW(
1020       "DEPRECATION WARNING: File.listFiles() is deprecated since Tizen 5.0. Use "
1021       "FileSystemManager.listDirectory() instead.");
1022
1023   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1024   CHECK_EXIST(args, "pathToDir", out)
1025   CHECK_EXIST(args, "callbackId", out)
1026
1027   double callback_id = args.get("callbackId").get<double>();
1028   const std::string& pathToDir = args.get("pathToDir").get<std::string>();
1029
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());
1033     ;
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);
1040       statPaths.push_back(stat.toJSON());
1041     }
1042     ReportSuccess(result, obj);
1043     Instance::PostMessage(this, response.serialize().c_str());
1044   };
1045
1046   auto onError = [this, callback_id](FilesystemError e) {
1047     ScopeLogger("Entered into asynchronous function, onError");
1048     picojson::value response = picojson::value(picojson::object());
1049     picojson::object& obj = response.get<picojson::object>();
1050     obj["callbackId"] = picojson::value(callback_id);
1051     PrepareError(e, obj);
1052     Instance::PostMessage(this, response.serialize().c_str());
1053   };
1054
1055   FilesystemManager& fm = FilesystemManager::GetInstance();
1056   common::TaskQueue::GetInstance().Async(
1057       std::bind(&FilesystemManager::ReadDir, &fm, pathToDir, onSuccess, onError));
1058 }
1059
1060 void FilesystemInstance::UnlinkFile(const picojson::value& args, picojson::object& out) {
1061   ScopeLogger();
1062   LoggerW(
1063       "DEPRECATION WARNING: File.deleteFile() is deprecated since Tizen 5.0. Use "
1064       "FileSystemManager.deleteFile() instead.");
1065
1066   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1067   CHECK_EXIST(args, "pathToFile", out)
1068   double callback_id = args.get("callbackId").get<double>();
1069   const std::string& pathToFile = args.get("pathToFile").get<std::string>();
1070   CHECK_STORAGE_ACCESS(pathToFile, &out);
1071
1072   auto onSuccess = [this, callback_id]() {
1073     ScopeLogger("Entered into asynchronous function, onSuccess");
1074     picojson::value result = picojson::value();
1075     picojson::value response = picojson::value(picojson::object());
1076     picojson::object& obj = response.get<picojson::object>();
1077     obj["callbackId"] = picojson::value(callback_id);
1078     ReportSuccess(result, obj);
1079     Instance::PostMessage(this, response.serialize().c_str());
1080   };
1081
1082   auto onError = [this, callback_id](FilesystemError e) {
1083     ScopeLogger("Entered into asynchronous function, onError");
1084     picojson::value response = picojson::value(picojson::object());
1085     picojson::object& obj = response.get<picojson::object>();
1086     obj["callbackId"] = picojson::value(callback_id);
1087     PrepareError(e, obj);
1088     Instance::PostMessage(this, response.serialize().c_str());
1089   };
1090
1091   FilesystemManager& fm = FilesystemManager::GetInstance();
1092   common::TaskQueue::GetInstance().Async(
1093       std::bind(&FilesystemManager::UnlinkFile, &fm, pathToFile, onSuccess, onError));
1094 }
1095
1096 void FilesystemInstance::RemoveDirectory(const picojson::value& args, picojson::object& out) {
1097   ScopeLogger();
1098   LoggerW(
1099       "DEPRECATION WARNING: File.deleteDirectory() is deprecated since Tizen 5.0. Use "
1100       "FileSystemManager.deleteDirectory() instead.");
1101
1102   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1103   CHECK_EXIST(args, "pathToDelete", out)
1104   double callback_id = args.get("callbackId").get<double>();
1105   const std::string& pathToDelete = args.get("pathToDelete").get<std::string>();
1106   CHECK_STORAGE_ACCESS(pathToDelete, &out);
1107
1108   auto onSuccess = [this, callback_id]() {
1109     ScopeLogger("Entered into asynchronous function, onSuccess");
1110     picojson::value result = picojson::value();
1111     picojson::value response = picojson::value(picojson::object());
1112     picojson::object& obj = response.get<picojson::object>();
1113     obj["callbackId"] = picojson::value(callback_id);
1114     ReportSuccess(result, obj);
1115     Instance::PostMessage(this, response.serialize().c_str());
1116   };
1117
1118   auto onError = [this, callback_id](FilesystemError e) {
1119     ScopeLogger("Entered into asynchronous function, onError");
1120     picojson::value response = picojson::value(picojson::object());
1121     picojson::object& obj = response.get<picojson::object>();
1122     obj["callbackId"] = picojson::value(callback_id);
1123     PrepareError(e, obj);
1124     Instance::PostMessage(this, response.serialize().c_str());
1125   };
1126
1127   FilesystemManager& fm = FilesystemManager::GetInstance();
1128   common::TaskQueue::GetInstance().Async(
1129       std::bind(&FilesystemManager::RemoveDirectory, &fm, pathToDelete, onSuccess, onError));
1130 }
1131
1132 void FilesystemInstance::CopyTo(const picojson::value& args, picojson::object& out) {
1133   ScopeLogger();
1134   LoggerW(
1135       "DEPRECATION WARNING: File.copyTo() is deprecated since Tizen 5.0. Use "
1136       "FileSystemManager.CopyFile() or FileSystemManager.CopyDirectory() instead.");
1137
1138   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1139   CHECK_EXIST(args, "callbackId", out)
1140
1141   CHECK_EXIST(args, "originFilePath", out)
1142   const std::string& originPath = args.get("originFilePath").get<std::string>();
1143   CHECK_STORAGE_ACCESS(originPath, &out);
1144   CHECK_EXIST(args, "destinationFilePath", out)
1145   const std::string& destinationPath = args.get("destinationFilePath").get<std::string>();
1146   CHECK_STORAGE_ACCESS(destinationPath, &out);
1147
1148   CHECK_EXIST(args, "overwrite", out)
1149
1150   double callback_id = args.get("callbackId").get<double>();
1151   const bool& overwrite = args.get("overwrite").get<bool>();
1152
1153   auto onSuccess = [this, callback_id]() {
1154     ScopeLogger("Entered into asynchronous function, onSuccess");
1155     picojson::value result = picojson::value();
1156     picojson::value response = picojson::value(picojson::object());
1157     picojson::object& obj = response.get<picojson::object>();
1158     obj["callbackId"] = picojson::value(callback_id);
1159     ReportSuccess(result, obj);
1160     Instance::PostMessage(this, response.serialize().c_str());
1161   };
1162
1163   auto onError = [this, callback_id](FilesystemError e) {
1164     ScopeLogger("Entered into asynchronous function, onError");
1165     picojson::value response = picojson::value(picojson::object());
1166     picojson::object& obj = response.get<picojson::object>();
1167     obj["callbackId"] = picojson::value(callback_id);
1168     PrepareError(e, obj);
1169     Instance::PostMessage(this, response.serialize().c_str());
1170   };
1171
1172   FilesystemManager& fm = FilesystemManager::GetInstance();
1173   common::TaskQueue::GetInstance().Async(std::bind(&FilesystemManager::CopyTo, &fm, originPath,
1174                                                    destinationPath, overwrite, onSuccess, onError));
1175 }
1176
1177 void FilesystemInstance::PrepareError(const FilesystemError& error, picojson::object& out) {
1178   ScopeLogger();
1179   switch (error) {
1180     case FilesystemError::None:
1181       LogAndReportError(UnknownException("PLATFORM ERROR"), out);
1182       break;
1183     case FilesystemError::NotFound:
1184       LogAndReportError(NotFoundException("PLATFORM ERROR"), out,
1185                         ("NotFoundException - PLATFORM ERROR"));
1186       break;
1187     case FilesystemError::FileExists:
1188       LogAndReportError(IOException("File already exists"), out,
1189                         ("IOException - File already exists"));
1190       break;
1191     case FilesystemError::DirectoryExists:
1192       LogAndReportError(IOException("Directory already exists"), out,
1193                         ("IOException - Directory already exists"));
1194       break;
1195     case FilesystemError::PermissionDenied:
1196       LogAndReportError(IOException("Permission denied"), out, ("IOException - Permission denied"));
1197       break;
1198     case FilesystemError::IOError:
1199       LogAndReportError(IOException("IO Error"), out, ("IOException - IO Error"));
1200       break;
1201     case FilesystemError::Other:
1202       LogAndReportError(UnknownException("PLATFORM ERROR other"), out,
1203                         ("UnknownException - PLATFORM ERROR other"));
1204       break;
1205     case FilesystemError::InvalidValue:
1206       LogAndReportError(InvalidValuesException("PLATFORM ERROR"), out,
1207                         ("InvalidValuesException - PLATFORM ERROR"));
1208       break;
1209     default:
1210       LogAndReportError(UnknownException("PLATFORM ERROR default"), out,
1211                         ("UnknownException - PLATFORM ERROR default"));
1212       break;
1213   }
1214 }
1215
1216 void FilesystemInstance::FileSystemManagerGetCanonicalPath(const picojson::value& args,
1217                                                            picojson::object& out) {
1218   ScopeLogger();
1219   // TODO: any privilege needed?
1220   CHECK_EXIST(args, "path", out);
1221
1222   const std::string& path = args.get("path").get<std::string>();
1223
1224   auto onSuccess = [&](const std::string& canonicalPath) {
1225     ScopeLogger("Entered into asynchronous function, onSuccess");
1226     ReportSuccess(picojson::value(canonicalPath), out);
1227   };
1228
1229   auto onError = [&](FilesystemError e) {
1230     ScopeLogger("Entered into asynchronous function, onError");
1231     PrepareError(e, out);
1232   };
1233
1234   FilesystemManager::GetInstance().GetCanonicalPath(path, onSuccess, onError);
1235 }
1236
1237 namespace {
1238
1239 FILE* OpenFile(const std::string& path, const std::string& fopen_mode) {
1240   FILE* file = std::fopen(path.c_str(), fopen_mode.c_str());
1241   if (!file) {
1242     throw std::system_error{errno, std::generic_category(), "Could not open file"};
1243   }
1244
1245   return file;
1246 }
1247
1248 FILE* MakeParentsAndOpenFile(const std::string& path, const std::string& fopen_mode) {
1249   /*
1250    * If fopen fails, created parent directories have to be removed.
1251    * Save the path to the first nonexistent parent directory in the file path,
1252    * to know where to start recursive removal
1253    */
1254   std::string first_nonexistent_parent = FilesystemUtils::Dirname(path);
1255   struct ::stat buf;
1256
1257   while (
1258       !FilesystemUtils::CheckIfExists(FilesystemUtils::Dirname(first_nonexistent_parent), &buf)) {
1259     first_nonexistent_parent = FilesystemUtils::Dirname(first_nonexistent_parent);
1260   }
1261
1262   FilesystemUtils::Mkdir(FilesystemUtils::Dirname(path), true);
1263
1264   FILE* file = std::fopen(path.c_str(), fopen_mode.c_str());
1265   if (file) {
1266     return file;
1267   }
1268
1269   std::system_error fopen_error =
1270       std::system_error(errno, std::generic_category(), "Could not open file");
1271
1272   try {
1273     FilesystemUtils::RemoveDirectoryRecursively(first_nonexistent_parent);
1274   } catch (const std::system_error& error) {
1275     LoggerD("Failed to remove created parent directories: %s", error.what());
1276   }
1277
1278   throw fopen_error;
1279 }
1280
1281 }  // namespace
1282
1283 void FilesystemInstance::FileSystemManagerOpenFile(const picojson::value& args,
1284                                                    picojson::object& out) {
1285   ScopeLogger();
1286   const int unique_id = static_cast<int>(args.get("id").get<double>());
1287   if (opened_files.find(unique_id) != opened_files.end()) {
1288     LogAndReportError(IOException("Internal error (id is already in use)"), out);
1289     return;
1290   }
1291
1292   bool access_checked = false;
1293   if (WriteAccessRequested(args)) {
1294     CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1295     access_checked = true;
1296   }
1297
1298   if (ReadAccessRequested(args)) {
1299     CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1300     access_checked = true;
1301   }
1302
1303   // File open mode received from JS layer can be different than expected by
1304   // WriteAccessRequested and ReadAccessRequested functions. In case like that
1305   // privilege would not be checked and user could gain unauthorized access to file.
1306   // To prevent this situation we only accept specific open modes.
1307   if (false == access_checked) {
1308     const std::string& open_mode = args.get("openMode").get<std::string>();
1309     LogAndReportError(TypeMismatchException("Invalid open mode: " + open_mode), out);
1310     return;
1311   }
1312
1313   const std::string& path = args.get("path").get<std::string>();
1314
1315   CHECK_STORAGE_ACCESS(path, &out);
1316   const std::string open_mode = GetFopenMode(args);
1317   FILE* file = nullptr;
1318   try {
1319     if (ShouldMakeParents(args)) {
1320       file = MakeParentsAndOpenFile(path, open_mode);
1321     } else {
1322       file = OpenFile(path, open_mode);
1323     }
1324   } catch (const std::system_error& error) {
1325     FilesystemUtils::TranslateException(error, out);
1326     return;
1327   }
1328
1329   opened_files.emplace(std::make_pair(unique_id, std::make_shared<FileHandle>(file)));
1330   ReportSuccess(out);
1331 }
1332
1333 void FilesystemInstance::FileSystemManagerCreateDirectory(const picojson::value& args,
1334                                                           picojson::object& out) {
1335   ScopeLogger();
1336   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1337
1338   double callback_id = args.get("callbackId").get<double>();
1339   const std::string& path = args.get("path").get<std::string>();
1340   bool make_parents = args.get("makeParents").get<bool>();
1341   CHECK_STORAGE_ACCESS(path, &out);
1342
1343   this->worker.add_job([this, callback_id, path, make_parents] {
1344     picojson::value response = picojson::value(picojson::object());
1345     picojson::object& obj = response.get<picojson::object>();
1346     obj["callbackId"] = picojson::value(callback_id);
1347
1348     try {
1349       FilesystemUtils::Mkdir(path, make_parents);
1350       ReportSuccess(picojson::value(path), obj);
1351     } catch (const std::system_error& e) {
1352       FilesystemUtils::TranslateException(e, obj);
1353     }
1354     this->PostMessage(response.serialize().c_str());
1355   });
1356
1357   ReportSuccess(out);
1358 }
1359
1360 void FilesystemInstance::FileSystemManagerDeleteFile(const picojson::value& args,
1361                                                      picojson::object& out) {
1362   ScopeLogger();
1363   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1364
1365   double callback_id = args.get("callbackId").get<double>();
1366   const std::string& path = args.get("path").get<std::string>();
1367
1368   CHECK_STORAGE_ACCESS(path, &out);
1369   this->worker.add_job([this, callback_id, path] {
1370     picojson::value response = picojson::value(picojson::object());
1371     picojson::object& obj = response.get<picojson::object>();
1372     obj["callbackId"] = picojson::value(callback_id);
1373     SCOPE_EXIT {
1374       this->PostMessage(response.serialize().c_str());
1375     };
1376
1377     try {
1378       struct stat buf {};
1379       if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfFile(buf)) {
1380         LogAndReportError(NotFoundException("Given path does not point to file."), obj);
1381         return;
1382       }
1383       FilesystemUtils::Unlink(path);
1384       ReportSuccess(picojson::value(FilesystemUtils::Dirname(path)), obj);
1385     } catch (const std::system_error& e) {
1386       FilesystemUtils::TranslateException(e, obj);
1387     }
1388   });
1389
1390   ReportSuccess(out);
1391 }
1392
1393 void FilesystemInstance::FileSystemManagerDeleteDirectory(const picojson::value& args,
1394                                                           picojson::object& out) {
1395   ScopeLogger();
1396   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1397
1398   double callback_id = args.get("callbackId").get<double>();
1399   const std::string& path = args.get("path").get<std::string>();
1400
1401   CHECK_STORAGE_ACCESS(path, &out);
1402   bool recursive = args.get("recursive").get<bool>();
1403
1404   this->worker.add_job([this, callback_id, path, recursive] {
1405     ScopeLogger();
1406     picojson::value response = picojson::value(picojson::object());
1407     picojson::object& obj = response.get<picojson::object>();
1408     obj["callbackId"] = picojson::value(callback_id);
1409     SCOPE_EXIT {
1410       this->PostMessage(response.serialize().c_str());
1411     };
1412
1413     try {
1414       struct stat buf {};
1415       if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfDir(buf)) {
1416         LogAndReportError(NotFoundException("Given path does not point to directory."), obj);
1417         return;
1418       }
1419       if (recursive) {
1420         FilesystemUtils::RemoveDirectoryRecursively(path);
1421       } else {
1422         FilesystemUtils::RemoveDirectory(path);
1423       }
1424       ReportSuccess(picojson::value(FilesystemUtils::Dirname(path)), obj);
1425     } catch (const std::system_error& e) {
1426       FilesystemUtils::TranslateException(e, obj);
1427     }
1428   });
1429
1430   ReportSuccess(out);
1431 }
1432
1433 void FilesystemInstance::FileSystemManagerCopyFile(const picojson::value& args,
1434                                                    picojson::object& out) {
1435   ScopeLogger();
1436   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1437   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1438
1439   double callback_id = args.get("callbackId").get<double>();
1440   const std::string& path = args.get("path").get<std::string>();
1441   CHECK_STORAGE_ACCESS(path, &out);
1442   const std::string& destination_path = args.get("destinationPath").get<std::string>();
1443   CHECK_STORAGE_ACCESS(destination_path, &out);
1444   bool overwrite = args.get("overwrite").get<bool>();
1445
1446   this->worker.add_job([this, callback_id, path, destination_path, overwrite] {
1447     picojson::value response = picojson::value(picojson::object());
1448     picojson::object& obj = response.get<picojson::object>();
1449     obj["callbackId"] = picojson::value(callback_id);
1450     SCOPE_EXIT {
1451       this->PostMessage(response.serialize().c_str());
1452     };
1453
1454     try {
1455       struct stat buf {};
1456       if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfFile(buf)) {
1457         LogAndReportError(NotFoundException("Given path does not point to file."), obj);
1458         return;
1459       }
1460       buf = {};
1461       if (FilesystemUtils::CheckIfExists(destination_path, &buf) && !overwrite) {
1462         LogAndReportError(
1463             IOException("Given path points to an existing resource, overwriting is not allowed."),
1464             obj);
1465         return;
1466       }
1467       FilesystemUtils::CopyFile(path, destination_path, overwrite);
1468       ReportSuccess(picojson::value(destination_path), obj);
1469     } catch (const std::system_error& e) {
1470       FilesystemUtils::TranslateException(e, obj);
1471     }
1472   });
1473
1474   ReportSuccess(out);
1475 }
1476
1477 void FilesystemInstance::FileSystemManagerCopyDirectory(const picojson::value& args,
1478                                                         picojson::object& out) {
1479   ScopeLogger();
1480   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1481   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1482   const std::string& path = args.get("path").get<std::string>();
1483   CHECK_STORAGE_ACCESS(path, &out);
1484   const std::string& destination_path = args.get("destinationPath").get<std::string>();
1485   CHECK_STORAGE_ACCESS(destination_path, &out);
1486   double callback_id = args.get("callbackId").get<double>();
1487   bool overwrite = args.get("overwrite").get<bool>();
1488
1489   this->worker.add_job([this, callback_id, path, destination_path, overwrite] {
1490     ScopeLogger();
1491     picojson::value response = picojson::value(picojson::object());
1492     picojson::object& obj = response.get<picojson::object>();
1493     obj["callbackId"] = picojson::value(callback_id);
1494     SCOPE_EXIT {
1495       this->PostMessage(response.serialize().c_str());
1496     };
1497
1498     try {
1499       struct stat buf {};
1500       if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfDir(buf)) {
1501         LogAndReportError(NotFoundException("Given path does not point to directory."), obj);
1502         return;
1503       }
1504       buf = {};
1505       bool exists = FilesystemUtils::CheckIfExists(destination_path, &buf);
1506       if (exists && !FilesystemUtils::CheckIfDir(buf)) {
1507         LogAndReportError(IOException("File with conflicting name already exists."), obj);
1508         return;
1509       } else if (!exists) {
1510         FilesystemUtils::Mkdir(destination_path);
1511       }
1512       FilesystemUtils::CopyDirectory(path, destination_path, overwrite);
1513       ReportSuccess(picojson::value(destination_path), obj);
1514     } catch (const std::system_error& e) {
1515       FilesystemUtils::TranslateException(e, obj);
1516     }
1517   });
1518
1519   ReportSuccess(out);
1520 }
1521
1522 void FilesystemInstance::FileSystemManagerMoveFile(const picojson::value& args,
1523                                                    picojson::object& out) {
1524   ScopeLogger();
1525   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1526   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1527
1528   const std::string& path = args.get("path").get<std::string>();
1529   CHECK_STORAGE_ACCESS(path, &out);
1530   const std::string& destination_path = args.get("destinationPath").get<std::string>();
1531   CHECK_STORAGE_ACCESS(destination_path, &out);
1532   double callback_id = args.get("callbackId").get<double>();
1533   bool overwrite = args.get("overwrite").get<bool>();
1534
1535   this->worker.add_job([this, callback_id, path, destination_path, overwrite] {
1536     ScopeLogger();
1537     picojson::value response = picojson::value(picojson::object());
1538     picojson::object& obj = response.get<picojson::object>();
1539     obj["callbackId"] = picojson::value(callback_id);
1540     SCOPE_EXIT {
1541       this->PostMessage(response.serialize().c_str());
1542     };
1543
1544     try {
1545       struct stat buf {};
1546       if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfFile(buf)) {
1547         LogAndReportError(NotFoundException("Given path does not point to file."), obj);
1548         return;
1549       }
1550       buf = {};
1551       if (!FilesystemUtils::CheckIfExists(destination_path, &buf) ||
1552           !FilesystemUtils::CheckIfDir(buf)) {
1553         LogAndReportError(NotFoundException("Given path does not point to directory."), obj);
1554         return;
1555       }
1556
1557       buf = {};
1558       std::string new_path = destination_path + '/' + FilesystemUtils::PosixBasename(path);
1559       if (!overwrite && FilesystemUtils::CheckIfExists(new_path, &buf)) {
1560         LogAndReportError(IOException("File or directory with conflicting name already exists."),
1561                           obj);
1562         return;
1563       }
1564       FilesystemUtils::MoveFile(path, new_path, overwrite);
1565       ReportSuccess(picojson::value(new_path), obj);
1566     } catch (const std::system_error& e) {
1567       FilesystemUtils::TranslateException(e, obj);
1568     }
1569   });
1570
1571   ReportSuccess(out);
1572 }
1573
1574 void FilesystemInstance::FileSystemManagerMoveDirectory(const picojson::value& args,
1575                                                         picojson::object& out) {
1576   ScopeLogger();
1577
1578   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1579   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1580   double callback_id = args.get("callbackId").get<double>();
1581   const std::string& path = args.get("path").get<std::string>();
1582   CHECK_STORAGE_ACCESS(path, &out);
1583   const std::string& destination_path = args.get("destinationPath").get<std::string>();
1584   CHECK_STORAGE_ACCESS(destination_path, &out);
1585   bool overwrite = args.get("overwrite").get<bool>();
1586
1587   this->worker.add_job([this, callback_id, path, destination_path, overwrite] {
1588     picojson::value response = picojson::value(picojson::object());
1589     picojson::object& obj = response.get<picojson::object>();
1590     obj["callbackId"] = picojson::value(callback_id);
1591     SCOPE_EXIT {
1592       this->PostMessage(response.serialize().c_str());
1593     };
1594
1595     try {
1596       struct stat buf {};
1597       if (!FilesystemUtils::CheckIfExists(path, &buf) || !FilesystemUtils::CheckIfDir(buf)) {
1598         LogAndReportError(NotFoundException("Given path does not point to directory."), obj);
1599         return;
1600       }
1601       buf = {};
1602       if (!FilesystemUtils::CheckIfExists(destination_path, &buf) ||
1603           !FilesystemUtils::CheckIfDir(buf)) {
1604         LogAndReportError(NotFoundException("Given path does not point to directory."), obj);
1605         return;
1606       }
1607       buf = {};
1608       std::string new_path = destination_path + '/' + FilesystemUtils::PosixBasename(path);
1609       if (FilesystemUtils::CheckIfExists(new_path, &buf) && !FilesystemUtils::CheckIfDir(buf)) {
1610         LogAndReportError(IOException("File or directory with conflicting name already exists."),
1611                           obj);
1612         return;
1613       }
1614       FilesystemUtils::MoveDirectory(path, destination_path, overwrite);
1615       ReportSuccess(picojson::value(new_path), obj);
1616     } catch (const std::system_error& e) {
1617       FilesystemUtils::TranslateException(e, obj);
1618     }
1619   });
1620
1621   ReportSuccess(out);
1622 }
1623
1624 void FilesystemInstance::FileSystemManagerRename(const picojson::value& args,
1625                                                  picojson::object& out) {
1626   ScopeLogger();
1627   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
1628   const std::string& path = args.get("path").get<std::string>();
1629
1630   CHECK_STORAGE_ACCESS(path, &out);
1631   double callback_id = args.get("callbackId").get<double>();
1632   const std::string& new_name = args.get("newName").get<std::string>();
1633
1634   this->worker.add_job([this, callback_id, new_name, path] {
1635     ScopeLogger();
1636     picojson::value response = picojson::value(picojson::object());
1637     picojson::object& obj = response.get<picojson::object>();
1638     obj["callbackId"] = picojson::value(callback_id);
1639     SCOPE_EXIT {
1640       this->PostMessage(response.serialize().c_str());
1641     };
1642
1643     try {
1644       struct stat buf {};
1645       bool exists = FilesystemUtils::CheckIfExists(path, &buf);
1646       if (!exists) {
1647         LogAndReportError(NotFoundException("Given path does not point to file or directory."),
1648                           obj);
1649         return;
1650       }
1651       std::string new_path{FilesystemUtils::Dirname(path) + "/" + new_name};
1652       buf = {};
1653       exists = FilesystemUtils::CheckIfExists(new_path, &buf);
1654       if (exists) {
1655         LogAndReportError(IOException("File or directory with conflicting name already exists"),
1656                           obj);
1657         return;
1658       }
1659       FilesystemUtils::Rename(path, new_path);
1660       ReportSuccess(picojson::value(new_path), obj);
1661     } catch (const std::system_error& e) {
1662       FilesystemUtils::TranslateException(e, obj);
1663     }
1664   });
1665
1666   ReportSuccess(out);
1667 }
1668
1669 void FilterResult(std::vector<const char*>& names, std::vector<unsigned char>& types, bool is_type,
1670                   unsigned char type) {
1671   int i = (int)names.size() - 1;
1672
1673   while (i >= 0) {
1674     if (is_type ? type != types[i] : type == types[i]) {
1675       names.erase(names.begin() + i);
1676     }
1677     i--;
1678   }
1679 }
1680
1681 void FilesystemInstance::FileSystemManagerListDirectory(const picojson::value& args,
1682                                                         picojson::object& out) {
1683   ScopeLogger();
1684   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1685
1686   double callback_id = args.get("callbackId").get<double>();
1687   const std::string& path = args.get("path").get<std::string>();
1688   const picojson::object& filter = args.get("filter").get<picojson::object>();
1689   CHECK_STORAGE_ACCESS(path, &out);
1690
1691   this->worker.add_job([this, callback_id, path, filter] {
1692     ScopeLogger();
1693     picojson::value response = picojson::value(picojson::object());
1694     picojson::object& obj = response.get<picojson::object>();
1695     obj["callbackId"] = picojson::value(callback_id);
1696
1697     try {
1698       std::vector<const char*> names;
1699       {
1700         std::vector<unsigned char> types;
1701         FilesystemUtils::ListDirectory(path, [&](const char* name, unsigned char type) {
1702           names.push_back(name);
1703           types.push_back(type);
1704         });
1705
1706         auto it = filter.find("isFile");
1707         if (filter.end() != it) {
1708           FilterResult(names, types, it->second.get<bool>(), DT_REG);
1709         }
1710
1711         it = filter.find("isDirectory");
1712         if (filter.end() != it) {
1713           FilterResult(names, types, it->second.get<bool>(), DT_DIR);
1714         }
1715       }
1716
1717       auto start_modified_it = filter.find("startModified"),
1718            end_modified_it = filter.find("endModified"),
1719            start_created_it = filter.find("startCreated"),
1720            end_created_it = filter.find("endCreated");
1721       if (filter.end() != start_modified_it || filter.end() != end_modified_it ||
1722           filter.end() != start_created_it || filter.end() != end_created_it) {
1723         auto name_iterator = names.begin();
1724         while (name_iterator != names.end()) {
1725           struct ::stat buf;
1726           std::string path_with_name = path + std::string("/") + std::string(*name_iterator);
1727           int status = ::stat(path_with_name.c_str(), &buf);
1728           if (status != 0) {
1729             throw std::system_error{errno, std::generic_category(),
1730                                     "Failed to get last modification date of a file"};
1731           }
1732           if (filter.end() != start_modified_it &&
1733               (buf.st_mtime < start_modified_it->second.get<double>())) {
1734             name_iterator = names.erase(name_iterator);
1735             continue;
1736           }
1737           if (filter.end() != end_modified_it &&
1738               (buf.st_mtime > end_modified_it->second.get<double>())) {
1739             name_iterator = names.erase(name_iterator);
1740             continue;
1741           }
1742           if (filter.end() != start_created_it &&
1743               (buf.st_ctime < start_created_it->second.get<double>())) {
1744             name_iterator = names.erase(name_iterator);
1745             continue;
1746           }
1747           if (filter.end() != end_created_it &&
1748               (buf.st_ctime > end_created_it->second.get<double>())) {
1749             name_iterator = names.erase(name_iterator);
1750             continue;
1751           }
1752           name_iterator++;
1753         }
1754       }
1755
1756       picojson::value value = picojson::value(picojson::object());
1757       picojson::object& object = value.get<picojson::object>();
1758
1759       object["names"] = picojson::value{picojson::array_type, true};
1760       object["path"] = picojson::value(path);
1761
1762       picojson::array& names_array = object["names"].get<picojson::array>();
1763       names_array.reserve(names.size());
1764       for (unsigned int i = 0; i < names.size(); ++i) {
1765         names_array.push_back(picojson::value(names[i]));
1766       }
1767
1768       ReportSuccess(value, obj);
1769     } catch (const std::system_error& e) {
1770       FilesystemUtils::TranslateException(e, obj);
1771     }
1772     this->PostMessage(response.serialize().c_str());
1773   });
1774
1775   ReportSuccess(out);
1776 }
1777
1778 void FilesystemInstance::FileSystemManagerIsFile(const picojson::value& args,
1779                                                  picojson::object& out) {
1780   ScopeLogger();
1781   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1782   const std::string& path = args.get("path").get<std::string>();
1783
1784   CHECK_STORAGE_ACCESS(path, &out);
1785   picojson::value is_file{};
1786   try {
1787     struct stat buf {};
1788     bool exists = FilesystemUtils::CheckIfExists(path, &buf);
1789     if (!exists) {
1790       LogAndReportError(NotFoundException("Given path does not point to file."), out);
1791       return;
1792     }
1793     is_file = picojson::value{FilesystemUtils::CheckIfFile(buf)};
1794   } catch (const std::system_error& e) {
1795     FilesystemUtils::TranslateException(e, out);
1796   }
1797   ReportSuccess(is_file, out);
1798 }
1799
1800 void FilesystemInstance::FileSystemManagerIsDirectory(const picojson::value& args,
1801                                                       picojson::object& out) {
1802   ScopeLogger();
1803   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1804   const std::string& path = args.get("path").get<std::string>();
1805
1806   CHECK_STORAGE_ACCESS(path, &out);
1807   picojson::value is_directory{};
1808   try {
1809     struct stat buf {};
1810     bool exists = FilesystemUtils::CheckIfExists(path, &buf);
1811     if (!exists) {
1812       LogAndReportError(NotFoundException("Given path does not point to directory."), out);
1813       return;
1814     }
1815     is_directory = picojson::value{FilesystemUtils::CheckIfDir(buf)};
1816   } catch (const std::system_error& e) {
1817     FilesystemUtils::TranslateException(e, out);
1818   }
1819   ReportSuccess(is_directory, out);
1820 }
1821
1822 void FilesystemInstance::FileSystemManagerPathExists(const picojson::value& args,
1823                                                      picojson::object& out) {
1824   ScopeLogger();
1825   CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
1826   const std::string& path = args.get("path").get<std::string>();
1827
1828   CHECK_STORAGE_ACCESS(path, &out);
1829   picojson::value does_file_exist = picojson::value{true};
1830   try {
1831     struct stat buf {};
1832     bool exists = FilesystemUtils::CheckIfExists(path, &buf);
1833     if (!exists) {
1834       does_file_exist = picojson::value{false};
1835     }
1836   } catch (const std::system_error& e) {
1837     FilesystemUtils::TranslateException(e, out);
1838   }
1839   ReportSuccess(does_file_exist, out);
1840 }
1841
1842 void FilesystemInstance::FileSystemManagerGetLimits(const picojson::value& args,
1843                                                     picojson::object& out) {
1844   ScopeLogger();
1845   picojson::value response =
1846       picojson::value{picojson::array{picojson::value{static_cast<double>(NAME_MAX)},
1847                                       picojson::value{static_cast<double>(PATH_MAX)}}};
1848   ReportSuccess(response, out);
1849 }
1850
1851 void FilesystemInstance::FileHandleSeek(const picojson::value& args, picojson::object& out) {
1852   ScopeLogger();
1853   const int fh_id = static_cast<int>(args.get("id").get<double>());
1854   const long offset = static_cast<long>(args.get("offset").get<double>());
1855   const std::string& _whence = args.get("whence").get<std::string>();
1856
1857   auto fh = opened_files.find(fh_id);
1858
1859   int whence = SEEK_SET;
1860
1861   if ("CURRENT" == _whence) {
1862     whence = SEEK_CUR;
1863     LoggerD("SEEK_CUR selected");
1864   } else if ("END" == _whence) {
1865     whence = SEEK_END;
1866     LoggerD("SEEK_END selected");
1867   }
1868
1869   if (opened_files.end() == fh) {
1870     LogAndReportError(IOException("Invalid FileHandle"), out);
1871     return;
1872   }
1873
1874   auto handle = fh->second;
1875
1876   auto logic = [handle, whence, offset](decltype(out) out) {
1877     long ret = fseek(handle->file_handle, offset, whence);
1878     if (0 != ret) {
1879       LoggerE("fseek returned failed");
1880       std::string error_message =
1881           std::string("seek failed, fileHandle may be corrupted, error message: ") +
1882           GetErrorString(errno);
1883       LogAndReportError(IOException(error_message.c_str()), out);
1884       return;
1885     }
1886
1887     ret = ftell(handle->file_handle);
1888     if (-1L == ret) {
1889       LoggerE("ftell returned failed");
1890       std::string error_message =
1891           std::string("seek failed, fileHandle may be corrupted, error message: ") +
1892           GetErrorString(errno);
1893       LogAndReportError(IOException(error_message.c_str()), out);
1894       return;
1895     }
1896
1897     ReportSuccess(picojson::value((double)ret), out);
1898   };
1899
1900   bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
1901
1902   if (blocking) {
1903     logic(out);
1904   } else {
1905     // Async logic
1906     double callback_id = args.get("callbackId").get<double>();
1907     this->worker.add_job([this, callback_id, logic] {
1908       picojson::value response = picojson::value(picojson::object());
1909       picojson::object& async_out = response.get<picojson::object>();
1910       async_out["callbackId"] = picojson::value(callback_id);
1911       logic(async_out);
1912       this->PostMessage(response.serialize().c_str());
1913     });
1914
1915     // Sync return
1916     ReportSuccess(out);
1917   }
1918 }
1919
1920 void FilesystemInstance::FileHandleReadString(const picojson::value& args, picojson::object& out) {
1921   ScopeLogger();
1922   CHECK_EXIST(args, "id", out)
1923   const int fh_id = static_cast<int>(args.get("id").get<double>());
1924   const std::string& encoding =
1925       args.contains("encoding") ? args.get("encoding").get<std::string>() : "UTF-8";
1926   if (encoding != kISOEncoding && encoding != kUTF8Encoding) {
1927     LogAndReportError(NotSupportedException("Given encoding is not supported."), out);
1928     return;
1929   }
1930
1931   auto fh = opened_files.find(fh_id);
1932   if (opened_files.end() == fh) {
1933     LogAndReportError(IOException("Invalid FileHandle"), out);
1934     return;
1935   }
1936
1937   size_t count;
1938   bool whole_file = false;
1939   if (args.contains("count")) {
1940     // If user passed 'count' parameter, we need to read at most 'count' characters.
1941     double count_double = args.get("count").get<double>();
1942     if (std::string::npos <= static_cast<unsigned long long>(count_double)) {
1943       LogAndReportError(InvalidValuesException("Invalid count was given"), out);
1944       return;
1945     }
1946     count = static_cast<size_t>(count_double);
1947   } else {
1948     try {
1949       count = file_size(fh->second->file_handle);
1950       whole_file = true;
1951     } catch (const std::system_error& e) {
1952       LogAndReportError(IOException(e.what()), out);
1953       return;
1954     }
1955   }
1956   LoggerD("count: %zu", count);
1957
1958   auto handle = fh->second;
1959
1960   auto logic = [handle, count, encoding, whole_file](decltype(out) out) {
1961     try {
1962       size_t read_bytes = 0;
1963       std::vector<std::uint8_t> buf = read_file(handle->file_handle, count, &read_bytes);
1964       buf.resize(read_bytes);          // this protects from reporting too big arrays to JS
1965       if (encoding == kISOEncoding) {  // for iso-8859-1 1 byte is equal to 1 character
1966         out["result"] = picojson::value(picojson::string_type, true);
1967         latin1::to_utf8(buf, out["result"].get<std::string>());
1968         ReportSuccess(out);
1969       } else {  // UTF-8
1970         unsigned long char_count;
1971         short expected_extension_bytes;
1972         if (!validate_and_check_character_count(buf, char_count, expected_extension_bytes)) {
1973           LogAndReportError(
1974               IOException("File doesn't contain UTF-8 encoded string with given length"), out);
1975           return;
1976         }
1977         LoggerD("char_count: %lu", char_count);
1978         LoggerD("ftell: %ld", ftell(handle->file_handle));
1979         if (!(std::feof(
1980                 handle->file_handle))) {  // read number of characters if not whole file read
1981           LoggerD("count parameter given: %zu", count);
1982           if (!whole_file &&
1983               !add_utf8_chars_to_buffer(handle->file_handle, buf, count - char_count,
1984                                         expected_extension_bytes)) {
1985             LogAndReportError(
1986                 IOException("File doesn't contain UTF-8 encoded string with given length"), out);
1987           }
1988         }
1989         const char* str = (const char*)buf.data();
1990         ReportSuccess(picojson::value{str, buf.size()}, out);
1991       }
1992     } catch (std::runtime_error& e) {
1993       LoggerE("Cannot read, cause: %s", e.what());
1994       LogAndReportError(IOException(e.what()), out);
1995     }
1996   };
1997
1998   bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
1999
2000   if (blocking) {
2001     logic(out);
2002   } else {
2003     // Async logic
2004     double callback_id = args.get("callbackId").get<double>();
2005     this->worker.add_job([this, callback_id, logic] {
2006       picojson::value response = picojson::value(picojson::object());
2007       picojson::object& async_out = response.get<picojson::object>();
2008       async_out["callbackId"] = picojson::value(callback_id);
2009       logic(async_out);
2010       this->PostMessage(response.serialize().c_str());
2011     });
2012
2013     // Sync return
2014     ReportSuccess(out);
2015   }
2016 }
2017
2018 void FilesystemInstance::FileHandleWriteString(const picojson::value& args, picojson::object& out) {
2019   ScopeLogger();
2020   CHECK_EXIST(args, "id", out)
2021   CHECK_EXIST(args, "string", out)
2022   const int fh_id = static_cast<int>(args.get("id").get<double>());
2023   const std::string& str = args.get("string").get<std::string>();
2024   const std::string& encoding =
2025       args.contains("encoding") ? args.get("encoding").get<std::string>() : "UTF-8";
2026   if (encoding != kISOEncoding && encoding != kUTF8Encoding) {
2027     LogAndReportError(NotSupportedException("Given encoding is not supported."), out);
2028     return;
2029   }
2030
2031   auto fh = opened_files.find(fh_id);
2032   if (opened_files.end() == fh) {
2033     LogAndReportError(IOException("Invalid FileHandle"), out);
2034     return;
2035   }
2036
2037   auto handle = fh->second;
2038
2039   auto logic = [str, handle, encoding](decltype(out) out) {
2040     try {
2041       std::vector<std::uint8_t> data;
2042       data.resize(str.size());
2043
2044       if (encoding == kISOEncoding) {
2045         latin1::from_utf8(str, data);
2046       } else {  // UTF-8
2047         LoggerD("copying string memory to vector");
2048         std::memcpy(data.data(), str.data(), str.size());
2049       }
2050       write_file(data.data(), data.size(), handle->file_handle);
2051       ReportSuccess(picojson::value{(double)data.size()}, out);
2052     } catch (std::runtime_error& e) {
2053       LoggerE("Cannot write, cause: %s", e.what());
2054       LogAndReportError(IOException(e.what()), out);
2055     }
2056   };
2057
2058   bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
2059
2060   if (blocking) {
2061     logic(out);
2062   } else {
2063     // Async logic
2064     double callback_id = args.get("callbackId").get<double>();
2065     this->worker.add_job([this, callback_id, logic] {
2066       picojson::value response = picojson::value(picojson::object());
2067       picojson::object& async_out = response.get<picojson::object>();
2068       async_out["callbackId"] = picojson::value(callback_id);
2069       logic(async_out);
2070       this->PostMessage(response.serialize().c_str());
2071     });
2072
2073     // Sync return
2074     ReportSuccess(out);
2075   }
2076 }
2077
2078 void FilesystemInstance::FileHandleReadData(const picojson::value& args, picojson::object& out) {
2079   ScopeLogger();
2080   CHECK_EXIST(args, "id", out)
2081   const int fh_id = static_cast<int>(args.get("id").get<double>());
2082   auto fh = opened_files.find(fh_id);
2083
2084   if (opened_files.end() == fh) {
2085     LoggerE("FileHandle with id: %d not found", fh_id);
2086     LogAndReportError(IOException("Invalid FileHandle"), out);
2087     return;
2088   }
2089
2090   size_t size;
2091   // We need to check how many bytes is it possible to read until the EOF.
2092   try {
2093     // We need to read from file exactly the minimum value of 'size' given by user and the
2094     // 'size ' to avoid returning array with redundant data (which would be equal to 0).
2095     size = file_bytes_to_eof(fh->second->file_handle);
2096     if (args.contains("size")) {
2097       // If user passed 'size' parameter, we need to read at most 'size' bytes.
2098       double size_double = args.get("size").get<double>();
2099       if (std::string::npos <= static_cast<unsigned long long>(size_double)) {
2100         LogAndReportError(InvalidValuesException("Invalid size was given"), out);
2101         return;
2102       }
2103       size = std::min(static_cast<size_t>(size_double), size);
2104     }
2105   } catch (const std::system_error& e) {
2106     LogAndReportError(IOException(e.what()), out);
2107     return;
2108   }
2109
2110   LoggerD("size: %zu", size);
2111
2112   auto handle = fh->second;
2113
2114   auto logic = [handle, size](decltype(out) out) {
2115     try {
2116       std::vector<std::uint8_t> data = read_file(handle->file_handle, size);
2117       out["result"] = picojson::value(picojson::string_type, true);
2118       encode_binary_in_string(data, out["result"].get<std::string>());
2119     } catch (std::runtime_error& e) {
2120       LoggerE("Cannot read, cause: %s", e.what());
2121       LogAndReportError(IOException(e.what()), out);
2122     }
2123   };
2124
2125   bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
2126
2127   if (blocking) {
2128     logic(out);
2129   } else {
2130     // Async logic
2131     double callback_id = args.get("callbackId").get<double>();
2132     this->worker.add_job([this, callback_id, logic] {
2133       picojson::value response = picojson::value(picojson::object());
2134       picojson::object& async_out = response.get<picojson::object>();
2135       async_out["callbackId"] = picojson::value(callback_id);
2136       logic(async_out);
2137       this->PostMessage(response.serialize().c_str());
2138     });
2139
2140     // Sync return
2141     ReportSuccess(out);
2142   }
2143 }
2144
2145 void FilesystemInstance::FileHandleWriteData(const picojson::value& args, picojson::object& out) {
2146   ScopeLogger();
2147   CHECK_EXIST(args, "id", out)
2148   CHECK_EXIST(args, "data", out)
2149   const auto& str = args.get("data").get<std::string>();
2150   const int fh_id = static_cast<int>(args.get("id").get<double>());
2151
2152   auto fh = opened_files.find(fh_id);
2153   if (opened_files.end() == fh) {
2154     LoggerE("FileHandle with id: %d not found", fh_id);
2155     LogAndReportError(IOException("Invalid FileHandle"), out);
2156     return;
2157   }
2158
2159   auto handle = fh->second;
2160
2161   auto logic = [str, handle](decltype(out) out) {
2162     try {
2163       std::vector<std::uint8_t> bytes;
2164       decode_binary_from_string(str, bytes);
2165       write_file(bytes.data(), bytes.size(), handle->file_handle);
2166     } catch (std::runtime_error& e) {
2167       LogAndReportError(IOException(e.what()), out);
2168     }
2169   };
2170
2171   bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
2172
2173   if (blocking) {
2174     logic(out);
2175   } else {
2176     // Async logic
2177     double callback_id = args.get("callbackId").get<double>();
2178     this->worker.add_job([this, callback_id, logic] {
2179       picojson::value response = picojson::value(picojson::object());
2180       picojson::object& async_out = response.get<picojson::object>();
2181       async_out["callbackId"] = picojson::value(callback_id);
2182       logic(async_out);
2183       this->PostMessage(response.serialize().c_str());
2184     });
2185
2186     // Sync return
2187     ReportSuccess(out);
2188   }
2189 }
2190
2191 void FilesystemInstance::FileHandleFlush(const picojson::value& args, picojson::object& out) {
2192   ScopeLogger();
2193   const int fh_id = static_cast<int>(args.get("id").get<double>());
2194
2195   auto fh = opened_files.find(fh_id);
2196   if (opened_files.end() == fh) {
2197     LogAndReportError(IOException("Invalid FileHandle"), out);
2198     return;
2199   }
2200
2201   auto handle = fh->second;
2202
2203   auto logic = [handle](decltype(out) out) {
2204     int ret = fflush(handle->file_handle);
2205     if (ret) {
2206       std::string error_message =
2207           std::string("flush failed, error message: ") + GetErrorString(errno);
2208       LogAndReportError(IOException(error_message.c_str()), out);
2209     }
2210   };
2211
2212   bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
2213
2214   if (blocking) {
2215     logic(out);
2216   } else {
2217     // Async logic
2218     double callback_id = args.get("callbackId").get<double>();
2219     this->worker.add_job([this, callback_id, logic] {
2220       picojson::value response = picojson::value(picojson::object());
2221       picojson::object& async_out = response.get<picojson::object>();
2222       async_out["callbackId"] = picojson::value(callback_id);
2223       logic(async_out);
2224       this->PostMessage(response.serialize().c_str());
2225     });
2226
2227     // Sync return
2228     ReportSuccess(out);
2229   }
2230 }
2231
2232 void FilesystemInstance::FileHandleSync(const picojson::value& args, picojson::object& out) {
2233   ScopeLogger();
2234   const int fh_id = static_cast<int>(args.get("id").get<double>());
2235
2236   auto fh = opened_files.find(fh_id);
2237   if (opened_files.end() == fh) {
2238     LogAndReportError(IOException("Invalid FileHandle"), out);
2239     return;
2240   }
2241
2242   auto handle = fh->second;
2243
2244   auto logic = [handle](decltype(out) out) {
2245     int ret = fsync(fileno(handle->file_handle));
2246     if (ret) {
2247       std::string error_message =
2248           std::string("sync failed, error message: ") + GetErrorString(errno);
2249       LogAndReportError(IOException(error_message.c_str()), out);
2250     }
2251   };
2252
2253   bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
2254
2255   if (blocking) {
2256     logic(out);
2257   } else {
2258     // Async logic
2259     double callback_id = args.get("callbackId").get<double>();
2260     this->worker.add_job([this, callback_id, logic] {
2261       picojson::value response = picojson::value(picojson::object());
2262       picojson::object& async_out = response.get<picojson::object>();
2263       async_out["callbackId"] = picojson::value(callback_id);
2264       logic(async_out);
2265       this->PostMessage(response.serialize().c_str());
2266     });
2267
2268     // Sync return
2269     ReportSuccess(out);
2270   }
2271 }
2272
2273 void FilesystemInstance::FileHandleClose(const picojson::value& args, picojson::object& out) {
2274   ScopeLogger();
2275   const int fh_id = static_cast<int>(args.get("id").get<double>());
2276   auto fh = opened_files.find(fh_id);
2277   if (opened_files.end() == fh) {
2278     LogAndReportError(IOException("Invalid FileHandle"), out);
2279     return;
2280   }
2281
2282   std::shared_ptr<FileHandle> handle = fh->second;
2283   opened_files.erase(fh);
2284
2285   auto logic = [handle](decltype(out) out) {
2286     if (!handle->file_handle) {
2287       LogAndReportError(IOException("File handle already closed."), out);
2288       return;
2289     }
2290     int ret = fclose(handle->file_handle);
2291     handle->file_handle = nullptr;
2292     if (ret) {
2293       std::string error_message =
2294           std::string("close failed, error message: ") + GetErrorString(errno);
2295       LogAndReportError(IOException(error_message.c_str()), out);
2296     }
2297   };
2298
2299   bool blocking = args.contains("blocking") ? args.get("blocking").get<bool>() : true;
2300
2301   if (blocking) {
2302     bool ready = false;
2303     bool done = false;
2304     std::mutex mutex;
2305     std::condition_variable conditional_variable;
2306     // adding empty job to worker's queue, in order to wait for all jobs to be done before closing
2307     // FILE*
2308     this->worker.add_job([] {},
2309                          [&conditional_variable, &mutex, &ready, &done, logic, &out] {
2310                            // wait for close
2311                            std::unique_lock<std::mutex> lock(mutex);
2312                            conditional_variable.wait(lock, [&ready] { return ready; });
2313
2314                            logic(out);
2315                            done = true;
2316                            conditional_variable.notify_one();
2317                          });
2318
2319     {
2320       // let know that close is ready
2321       std::unique_lock<std::mutex> lock(mutex);
2322       ready = true;
2323     }
2324     conditional_variable.notify_one();
2325
2326     {
2327       // wait for worker
2328       std::unique_lock<std::mutex> lock(mutex);
2329       conditional_variable.wait(lock, [&done] { return done; });
2330     }
2331     handle->file_handle = nullptr;
2332   } else {
2333     // Async logic
2334     double callback_id = args.get("callbackId").get<double>();
2335     this->worker.add_job([this, callback_id, logic] {
2336       picojson::value response = picojson::value(picojson::object());
2337       picojson::object& async_out = response.get<picojson::object>();
2338       async_out["callbackId"] = picojson::value(callback_id);
2339       logic(async_out);
2340       this->PostMessage(response.serialize().c_str());
2341     });
2342
2343     // Sync return
2344     ReportSuccess(out);
2345   }
2346 }
2347
2348 #undef CHECK_EXIST
2349
2350 }  // namespace filesystem
2351 }  // namespace extension