'filesystem_api.js',
'filesystem_extension.cc',
'filesystem_extension.h',
+ 'filesystem_file.cc',
+ 'filesystem_file.h',
'filesystem_instance.cc',
'filesystem_instance.h',
'filesystem_manager.cc',
--- /dev/null
+// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "filesystem_file.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <common/scope_exit.h>
+#include <common/logger.h>
+
+namespace extension {
+namespace filesystem {
+
+namespace {
+uint8_t characterToNumber(char c) {
+ if (c == '+') {
+ return 62;
+ }
+ if (c == '/') {
+ return 63;
+ }
+ if (c <= '9') {
+ return c + 0x04;
+ }
+ if (c <= 'Z') {
+ return c - 0x41;
+ }
+ if (c <= 'z') {
+ return c - 0x47;
+ }
+ return 0;
+}
+
+char numberToCharacter(uint8_t i) {
+ if (i <= 25) {
+ return 'A' + i;
+ }
+ if (i <= 51) {
+ return 'a' + i - 26;
+ }
+ if (i <= 61) {
+ return '0' + i - 52;
+ }
+ if (i == 62) {
+ return '+';
+ }
+ if (i == 63) {
+ return '/';
+ }
+ return 0;
+}
+
+bool validateCharacter(char c) {
+ if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') || (c == '=') || (c == '+') || (c == '/')) {
+ return true;
+ }
+ return false;
+}
+} // namespace
+
+/**
+ * Data is encoded using Base64 encoding.
+ */
+
+bool FilesystemBuffer::DecodeData(const std::string& data) {
+ if (data.length() % 4) {
+ LoggerE("Buffer has invalid length");
+ return false;
+ }
+
+ for (auto c : data) {
+ if (!validateCharacter(c)) {
+ LoggerE("Buffer has invalid character");
+ return false;
+ }
+ }
+
+ // Validate padding
+ for (size_t i = 0; i + 2 < data.length(); ++i) {
+ if (data[i] == '=') {
+ LoggerE("Unexpected padding character in string");
+ return false;
+ }
+ }
+
+ if (data[data.length() - 2] == '=' && data[data.length() - 1] != '=') {
+ LoggerE("Unexpected padding character in string");
+ return false;
+ }
+
+ clear();
+
+ if (data.length() == 0) {
+ return true;
+ }
+
+ int padding = 0;
+ if (data[data.length() - 1] == '=') {
+ padding++;
+ }
+
+ if (data[data.length() - 2] == '=') {
+ padding++;
+ }
+
+ for (size_t i = 0; i < data.length(); i += 4) {
+ uint8_t part[] = {
+ characterToNumber(data[i + 0]), characterToNumber(data[i + 1]),
+ characterToNumber(data[i + 2]), characterToNumber(data[i + 3])};
+ push_back(uint8_t((part[0] << 2) | (part[1] >> 4)));
+ if ((data.length() - i != 4) || (padding < 2)) {
+ push_back(uint8_t((part[1] << 4) | (part[2] >> 2)));
+ }
+ if ((data.length() - i != 4) || (padding < 1)) {
+ push_back(uint8_t((part[2] << 6) | (part[3])));
+ }
+ }
+ return true;
+}
+
+std::string FilesystemBuffer::EncodeData() const {
+ std::string out;
+
+ for (size_t i = 0; i < size(); i += 3) {
+ uint8_t part[] = {safe_get(i), safe_get(i + 1), safe_get(i + 2)};
+ out.push_back(numberToCharacter(0x3F & (part[0] >> 2)));
+ out.push_back(numberToCharacter(0x3F & ((part[0] << 4) | (part[1] >> 4))));
+ out.push_back(numberToCharacter(0x3F & ((part[1] << 2) | (part[2] >> 6))));
+ out.push_back(numberToCharacter(0x3F & (part[2])));
+ }
+
+ if (out.size() == 0)
+ return out;
+
+ // Add padding
+ int fillup = (size() % 3);
+ if (fillup == 1) {
+ out[out.size() - 2] = '=';
+ }
+
+ if (fillup == 1 || fillup == 2) {
+ out[out.size() - 1] = '=';
+ }
+
+ return out;
+}
+
+FilesystemFile::FilesystemFile(const std::string& path_)
+ : path(path_) {}
+
+bool FilesystemFile::Read(FilesystemBuffer* data,
+ size_t offset,
+ size_t length) {
+ if (!data) {
+ LoggerE("Missing output buffer");
+ return false;
+ }
+
+ data->resize(length);
+ FILE* file = fopen(path.c_str(), "r");
+ if (!file) {
+ LoggerE("Cannot open file %s to read!", path.c_str());
+ return false;
+ }
+ SCOPE_EXIT {
+ int status = fclose(file);
+ if (status) {
+ LoggerE("Cannot close file!");
+ }
+ };
+ int status;
+ status = fseek(file, offset, SEEK_SET);
+ if (status) {
+ LoggerE("Cannot perform seek!");
+ return false;
+ }
+
+ size_t readed = 0;
+ uint8_t* data_p = data->data();
+ size_t data_size = length;
+ while (readed < data->size()) {
+ size_t part = fread(data_p, 1, data_size, file);
+
+ readed += part;
+ data_p += part;
+ data_size -= part;
+
+ LoggerD("Readed part %li bytes", readed);
+
+ if (ferror(file)) {
+ LoggerE("Error during file write!");
+ return false;
+ }
+
+ if (feof(file)) {
+ LoggerD("File is at end before buffer is filled. Finish.");
+ break;
+ }
+ }
+ LoggerD("Readed %li bytes", readed);
+ data->resize(readed);
+ return true;
+}
+
+bool FilesystemFile::Write(const FilesystemBuffer& data, size_t offset) {
+ FILE* file = fopen(path.c_str(), "r+");
+ if (!file) {
+ LoggerE("Cannot open file %s to write!", path.c_str());
+ return false;
+ }
+
+ SCOPE_EXIT {
+ int status = fclose(file);
+ if (status) {
+ LoggerE("Cannot close file!");
+ }
+ };
+
+ int status;
+ status = fseek(file, offset, SEEK_SET);
+ LoggerD("Offset is %li, writing %i bytes", offset, data.size());
+ if (status) {
+ LoggerE("Cannot perform seek!");
+ return false;
+ }
+
+ size_t written = 0;
+ uint8_t* data_p = const_cast<uint8_t*>(data.data());
+ size_t data_size = data.size();
+ while (written < data.size()) {
+ size_t part = fwrite(data_p, 1, data_size, file);
+
+ if (ferror(file)) {
+ LoggerE("Error during file write!");
+ return false;
+ }
+
+ written += part;
+ data_p += part;
+ data_size -= part;
+ }
+
+ status = fflush(file);
+ if (status) {
+ LoggerE("Cannot flush file!");
+ return false;
+ }
+
+ status = fsync(fileno(file));
+ if (status) {
+ LoggerE("Cannot sync file!");
+ return false;
+ }
+ LoggerD("Written %li bytes", written);
+
+ return true;
+}
+} // namespace filesystem
+} // namespace extension
--- /dev/null
+// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef FILESYSTEM_FILESYSTEM_FILE_H
+#define FILESYSTEM_FILESYSTEM_FILE_H
+
+#include <string>
+#include <vector>
+#include <stdint.h>
+
+namespace extension {
+namespace filesystem {
+
+class FilesystemBuffer : public std::vector<uint8_t> {
+ public:
+ bool DecodeData(const std::string& data);
+ std::string EncodeData() const;
+
+ private:
+ inline uint8_t safe_get(size_t i) const {
+ if (i >= size()) {
+ return 0;
+ }
+ return at(i);
+ }
+};
+
+class FilesystemFile {
+ const std::string path;
+
+ public:
+ FilesystemFile(const std::string& path_);
+
+ bool Read(FilesystemBuffer* data, size_t offset, size_t length);
+ bool Write(const FilesystemBuffer& data, size_t offset);
+};
+
+} // namespace filesystem
+} // namespace extension
+
+#endif // FILESYSTEM_FILESYSTEM_FILE_H
REGISTER_SYNC("File_createSync", FileCreateSync);
REGISTER_ASYNC("File_readDir", ReadDir);
REGISTER_ASYNC("File_rename", FileRename);
+ REGISTER_ASYNC("File_read", FileRead);
+ REGISTER_SYNC("File_readSync", FileReadSync);
+ REGISTER_ASYNC("File_write", FileWrite);
+ REGISTER_SYNC("File_writeSync", FileWriteSync);
REGISTER_SYNC("Filesystem_getWidgetPaths", FilesystemGetWidgetPaths);
REGISTER_SYNC("FileSystemManager_addStorageStateChangeListener",
StartListening);
&FilesystemManager::Rename, &fsm, oldPath, newPath, onSuccess, onError));
}
+void FilesystemInstance::FileRead(const picojson::value& args,
+ picojson::object& out) {
+ LoggerD("enter");
+ CHECK_EXIST(args, "callbackId", out)
+ CHECK_EXIST(args, "location", out)
+ CHECK_EXIST(args, "offset", out)
+ CHECK_EXIST(args, "length", out)
+
+ double callback_id = args.get("callbackId").get<double>();
+ const std::string& location = args.get("location").get<std::string>();
+ size_t offset = static_cast<size_t>(args.get("offset").get<double>());
+ size_t length = static_cast<size_t>(args.get("length").get<double>());
+
+ auto onSuccess = [this, callback_id](const std::string& data) {
+ LoggerD("enter");
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& obj = response.get<picojson::object>();
+ obj["callbackId"] = picojson::value(callback_id);
+ ReportSuccess(picojson::value(data), obj);
+ PostMessage(response.serialize().c_str());
+ };
+
+ auto onError = [this, callback_id](FilesystemError e) {
+ LoggerD("enter");
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& obj = response.get<picojson::object>();
+ obj["callbackId"] = picojson::value(callback_id);
+ PrepareError(e, obj);
+ PostMessage(response.serialize().c_str());
+ };
+
+ FilesystemManager& fsm = FilesystemManager::GetInstance();
+ common::TaskQueue::GetInstance().Async(std::bind(&FilesystemManager::FileRead,
+ &fsm,
+ location,
+ offset,
+ length,
+ onSuccess,
+ onError));
+}
+
+void FilesystemInstance::FileReadSync(const picojson::value& args,
+ picojson::object& out) {
+ LoggerD("enter");
+ CHECK_EXIST(args, "location", out)
+ CHECK_EXIST(args, "offset", out)
+ CHECK_EXIST(args, "length", out)
+
+ const std::string& location = args.get("location").get<std::string>();
+ size_t offset = static_cast<size_t>(args.get("offset").get<double>());
+ size_t length = static_cast<size_t>(args.get("length").get<double>());
+
+ auto onSuccess = [this, &out](const std::string& data) {
+ LoggerD("enter");
+ ReportSuccess(picojson::value(data), out);
+ };
+
+ auto onError = [this, &out](FilesystemError e) {
+ LoggerD("enter");
+ PrepareError(e, out);
+ };
+
+ FilesystemManager::GetInstance().FileRead(
+ location, offset, length, onSuccess, onError);
+}
+
+void FilesystemInstance::FileWrite(const picojson::value& args,
+ picojson::object& out) {
+ LoggerD("enter");
+ CHECK_EXIST(args, "callbackId", out)
+ CHECK_EXIST(args, "location", out)
+ CHECK_EXIST(args, "data", out)
+ CHECK_EXIST(args, "offset", out)
+
+ double callback_id = args.get("callbackId").get<double>();
+ const std::string& location = args.get("location").get<std::string>();
+ const std::string& data = args.get("data").get<std::string>();
+ size_t offset = static_cast<size_t>(args.get("location").get<double>());
+
+ auto onSuccess = [this, callback_id]() {
+ LoggerD("enter");
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& obj = response.get<picojson::object>();
+ obj["callbackId"] = picojson::value(callback_id);
+ ReportSuccess(obj);
+ PostMessage(response.serialize().c_str());
+ };
+
+ auto onError = [this, callback_id](FilesystemError e) {
+ LoggerD("enter");
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& obj = response.get<picojson::object>();
+ obj["callbackId"] = picojson::value(callback_id);
+ PrepareError(e, obj);
+ PostMessage(response.serialize().c_str());
+ };
+
+ FilesystemManager& fsm = FilesystemManager::GetInstance();
+ common::TaskQueue::GetInstance().Async(
+ std::bind(&FilesystemManager::FileWrite,
+ &fsm,
+ location,
+ data,
+ offset,
+ onSuccess,
+ onError));
+}
+
+void FilesystemInstance::FileWriteSync(const picojson::value& args,
+ picojson::object& out) {
+ LoggerD("enter");
+ CHECK_EXIST(args, "location", out)
+ CHECK_EXIST(args, "data", out)
+ CHECK_EXIST(args, "offset", out)
+
+ const std::string& location = args.get("location").get<std::string>();
+ const std::string& data = args.get("data").get<std::string>();
+ size_t offset = static_cast<size_t>(args.get("offset").get<double>());
+
+ auto onSuccess = [this, &out]() {
+ LoggerD("enter");
+ ReportSuccess(out);
+ };
+
+ auto onError = [this, &out](FilesystemError e) {
+ LoggerD("enter");
+ PrepareError(e, out);
+ };
+
+ FilesystemManager::GetInstance().FileWrite(
+ location, data, offset, onSuccess, onError);
+}
+
void FilesystemInstance::FileStat(const picojson::value& args,
picojson::object& out) {
LoggerD("enter");
void FileRename(const picojson::value& args, picojson::object& out);
void FileStat(const picojson::value& args, picojson::object& out);
void FileStatSync(const picojson::value& args, picojson::object& out);
+ void FileRead(const picojson::value& args, picojson::object& out);
+ void FileReadSync(const picojson::value& args, picojson::object& out);
+ void FileWrite(const picojson::value& args, picojson::object& out);
+ void FileWriteSync(const picojson::value& args, picojson::object& out);
void FilesystemGetWidgetPaths(const picojson::value& args,
picojson::object& out);
void FileSystemManagerFetchStorages(const picojson::value& args,
#include "common/logger.h"
#include "common/scope_exit.h"
#include "common/extension.h"
+#include "filesystem_file.h"
namespace extension {
namespace filesystem {
storage_get_type(storage_id, &type);
listener->onFilesystemStateChangeSuccessCallback(
std::to_string(type) + std::to_string(storage_id),
- std::to_string(state), std::to_string(type));
+ std::to_string(state),
+ std::to_string(type));
}
}
-int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
-{
+int unlink_cb(const char* fpath,
+ const struct stat* sb,
+ int typeflag,
+ struct FTW* ftwbuf) {
int result = remove(fpath);
if (result)
LoggerE("error occured");
if (STORAGE_ERROR_NONE !=
storage_foreach_device_supported(fetch_storages_cb, &result))
error_cb(FilesystemError::Other);
- for(auto storage : result) {
+ for (auto storage : result) {
ids_.insert(storage.storage_id);
}
success_cb(result);
}
void FilesystemManager::ReadDir(
- const std::string& path,
- const std::function<void(const std::vector<std::string>&)>& success_cb,
- const std::function<void(FilesystemError)>& error_cb) {
+ const std::string& path,
+ const std::function<void(const std::vector<std::string>&)>& success_cb,
+ const std::function<void(FilesystemError)>& error_cb) {
LoggerD("entered");
std::vector<std::string> fileList;
- DIR *dp = nullptr;
+ DIR* dp = nullptr;
struct dirent entry;
- struct dirent *result = nullptr;
+ struct dirent* result = nullptr;
int status = 0;
dp = opendir(path.c_str());
if (dp != NULL) {
- while ((status = readdir_r(dp, &entry, &result)) == 0 && result != nullptr) {
- if (strcmp(result->d_name, ".") != 0 && strcmp(result->d_name, "..") != 0)
- fileList.push_back(path + "/" + std::string(result->d_name));
+ while ((status = readdir_r(dp, &entry, &result)) == 0 &&
+ result != nullptr) {
+ if (strcmp(result->d_name, ".") != 0 && strcmp(result->d_name, "..") != 0)
+ fileList.push_back(path + "/" + std::string(result->d_name));
}
(void)closedir(dp);
if (status == 0) {
}
void FilesystemManager::UnlinkFile(
- const std::string& path,
- const std::function<void()>& success_cb,
- const std::function<void(FilesystemError)>& error_cb) {
+ const std::string& path,
+ const std::function<void()>& success_cb,
+ const std::function<void(FilesystemError)>& error_cb) {
if (unlink(path.c_str()) != 0) {
- LoggerE("Error occured while deleting file");
- error_cb(FilesystemError::Other);
- return;
+ LoggerE("Error occured while deleting file");
+ error_cb(FilesystemError::Other);
+ return;
}
success_cb();
}
void FilesystemManager::RemoveDirectory(
- const std::string& path,
- const std::function<void()>& success_cb,
- const std::function<void(FilesystemError)>& error_cb) {
+ const std::string& path,
+ const std::function<void()>& success_cb,
+ const std::function<void(FilesystemError)>& error_cb) {
const int maxDirOpened = 64;
if (nftw(path.c_str(), unlink_cb, maxDirOpened, FTW_DEPTH | FTW_PHYS) != 0) {
LoggerE("Error occured");
success_cb();
return;
}
+
+void FilesystemManager::FileRead(
+ const std::string& path,
+ size_t offset,
+ size_t length,
+ const std::function<void(const std::string&)>& success_cb,
+ const std::function<void(FilesystemError)>& error_cb) {
+
+ FilesystemFile file(path);
+ FilesystemBuffer buffer;
+ if (!file.Read(&buffer, offset, length)) {
+ LoggerE("Cannot read file %s", path.c_str());
+ error_cb(FilesystemError::Other);
+ return;
+ }
+
+ std::string out_data = buffer.EncodeData();
+ success_cb(out_data);
+}
+
+void FilesystemManager::FileWrite(
+ const std::string& path,
+ const std::string& data,
+ size_t offset,
+ const std::function<void()>& success_cb,
+ const std::function<void(FilesystemError)>& error_cb) {
+
+ FilesystemFile file(path);
+ FilesystemBuffer buffer;
+ // Decode buffer data
+ if (!buffer.DecodeData(data)) {
+ LoggerE("Cannot decode file data!");
+ error_cb(FilesystemError::Other);
+ return;
+ }
+
+ if (file.Write(buffer, offset)) {
+ success_cb();
+ } else {
+ LoggerE("Cannot write to file %s!", path.c_str());
+ error_cb(FilesystemError::Other);
+ }
+}
+
void FilesystemManager::StartListening() {
LoggerD("enter");
void MakeDirectory(const std::string& path,
const std::function<void(FilesystemError)>& result_cb);
-
+
void ReadDir(
const std::string& path,
const std::function<void(const std::vector<std::string>&)>& success_cb,
const std::string& path,
const std::function<void()>& success_cb,
const std::function<void(FilesystemError)>& error_cb);
+
+ void FileRead(const std::string& path,
+ size_t offset,
+ size_t length,
+ const std::function<void(const std::string&)>& success_cb,
+ const std::function<void(FilesystemError)>& error_cb);
+
+ void FileWrite(const std::string& path,
+ const std::string& data,
+ size_t offset,
+ const std::function<void()>& success_cb,
+ const std::function<void(FilesystemError)>& error_cb);
+
void StartListening();
void StopListening();
void AddListener(FilesystemStateChangeListener* listener);