@@ 0,0 1,136 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#define CATCH_CONFIG_MAIN
+#include <catch2/catch.hpp>
+
+#include <purefs/fs/filesystem.hpp>
+#include <purefs/blkdev/disk_manager.hpp>
+#include <purefs/blkdev/disk_image.hpp>
+#include <purefs/fs/drivers/filesystem_vfat.hpp>
+#include <purefs/fs/drivers/filesystem_littlefs.hpp>
+#include <sys/statvfs.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace
+{
+ constexpr auto vfat_disk_image = "PurePhone.img";
+ constexpr auto lfs_disk_image = "lfstest.img";
+
+ auto prepare_filesystem(std::string_view vfat_dev_name, std::string_view lfs_dev_name)
+ -> std::pair<std::unique_ptr<purefs::fs::filesystem>, std::shared_ptr<purefs::blkdev::disk_manager>>
+ {
+ using namespace purefs;
+
+ auto dm = std::make_shared<blkdev::disk_manager>();
+ auto vfat_disk = std::make_shared<blkdev::disk_image>(vfat_disk_image);
+ auto lfs_disk = std::make_shared<blkdev::disk_image>(lfs_disk_image);
+
+ if (dm->register_device(vfat_disk, vfat_dev_name) != 0) {
+ return {};
+ }
+ if (dm->register_device(lfs_disk, lfs_dev_name) != 0) {
+ return {};
+ }
+
+ auto fs_core = std::make_unique<fs::filesystem>(dm);
+ const auto vfs_vfat = std::make_shared<fs::drivers::filesystem_vfat>();
+ const auto vfs_lfs = std::make_shared<fs::drivers::filesystem_littlefs>();
+
+ if (fs_core->register_filesystem("vfat", vfs_vfat) != 0) {
+ return {};
+ }
+ if (fs_core->register_filesystem("littlefs", vfs_lfs) != 0) {
+ return {};
+ }
+
+ return std::make_pair(std::move(fs_core), std::move(dm));
+ }
+} // namespace
+
+TEST_CASE("dualmount: Basic mount")
+{
+ using namespace purefs;
+
+ auto dm = std::make_shared<blkdev::disk_manager>();
+ auto vfat_disk = std::make_shared<blkdev::disk_image>(vfat_disk_image);
+ auto lfs_disk = std::make_shared<blkdev::disk_image>(lfs_disk_image);
+ REQUIRE(vfat_disk);
+ REQUIRE(lfs_disk);
+ REQUIRE(dm->register_device(vfat_disk, "vfat0") == 0);
+ REQUIRE(dm->register_device(lfs_disk, "lfs0") == 0);
+
+ fs::filesystem fs_core(dm);
+ const auto vfs_vfat = std::make_shared<fs::drivers::filesystem_vfat>();
+ const auto vfs_lfs = std::make_shared<fs::drivers::filesystem_littlefs>();
+ REQUIRE(vfs_vfat->mount_count() == 0);
+ REQUIRE(vfs_lfs->mount_count() == 0);
+ REQUIRE(fs_core.register_filesystem("vfat", vfs_vfat) == 0);
+ REQUIRE(fs_core.register_filesystem("littlefs", vfs_lfs) == 0);
+
+ REQUIRE(fs_core.mount("vfat0part0", "/vfat", "vfat") == 0);
+ REQUIRE(fs_core.mount("lfs0part0", "/lfs", "littlefs") == 0);
+ REQUIRE(vfs_vfat->mount_count() == 1);
+ REQUIRE(vfs_lfs->mount_count() == 1);
+ REQUIRE(fs_core.umount("/vfat") == 0);
+ REQUIRE(fs_core.umount("/lfs") == 0);
+}
+
+TEST_CASE("dualmount: API tests")
+{
+ auto [fs_core, dm] = prepare_filesystem("vfat0", "lfs0");
+ REQUIRE(fs_core->mount("vfat0part0", "/vfat", "vfat") == 0);
+ REQUIRE(fs_core->mount("lfs0part0", "/lfs", "littlefs") == 0);
+
+ SECTION("Files stat")
+ {
+ const auto vfat_fd = fs_core->open("/vfat/.boot.json", O_RDONLY, 0);
+ REQUIRE(vfat_fd >= 3);
+ const auto lfs_fd = fs_core->open("/lfs/test_read_1.txt", O_RDONLY, 0);
+ REQUIRE(lfs_fd >= 3);
+
+ struct stat vfat_file_stat;
+ struct stat lfs_file_stat;
+ REQUIRE(fs_core->fstat(vfat_fd, vfat_file_stat) == 0);
+ REQUIRE(fs_core->fstat(lfs_fd, lfs_file_stat) == 0);
+ REQUIRE(vfat_file_stat.st_dev != lfs_file_stat.st_dev);
+
+ REQUIRE(fs_core->close(vfat_fd) == 0);
+ REQUIRE(fs_core->close(lfs_fd) == 0);
+ }
+ SECTION("Create, read & write files")
+ {
+ const auto lfs_fd = fs_core->open("/lfs/test_read_1.txt", O_RDONLY, 0);
+ REQUIRE(lfs_fd >= 3);
+
+ static constexpr auto vfat_filename = "/vfat/test_write_tmp_1.txt";
+ auto vfat_fd = fs_core->open(vfat_filename, O_CREAT | O_RDWR, 0);
+ REQUIRE(vfat_fd >= 3);
+
+ const std::string expected = "01234567";
+
+ {
+ char buf[64];
+ REQUIRE(fs_core->read(lfs_fd, buf, expected.size()) == static_cast<ssize_t>(expected.size()));
+ REQUIRE(memcmp(buf, expected.c_str(), expected.size()) == 0);
+ REQUIRE(fs_core->write(vfat_fd, buf, expected.size()) == static_cast<ssize_t>(expected.size()));
+ REQUIRE(fs_core->close(vfat_fd) == 0);
+ }
+
+ {
+ char buf[64];
+ vfat_fd = fs_core->open(vfat_filename, O_RDWR, 0);
+ REQUIRE(vfat_fd >= 3);
+ REQUIRE(fs_core->read(vfat_fd, buf, expected.size()) == static_cast<ssize_t>(expected.size()));
+ REQUIRE(memcmp(buf, expected.c_str(), expected.size()) == 0);
+ REQUIRE(fs_core->close(vfat_fd) == 0);
+ }
+
+ REQUIRE(fs_core->close(lfs_fd) == 0);
+ fs_core->unlink(vfat_filename);
+ }
+
+ REQUIRE(fs_core->umount("/vfat") == 0);
+ REQUIRE(fs_core->umount("/lfs") == 0);
+}<
\ No newline at end of file
@@ 2,107 2,303 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>
+
#include <purefs/fs/filesystem.hpp>
#include <purefs/blkdev/disk_manager.hpp>
#include <purefs/blkdev/disk_image.hpp>
#include <purefs/fs/drivers/filesystem_littlefs.hpp>
#include <sys/statvfs.h>
#include <sys/stat.h>
+#include <fcntl.h>
+#include <cstring>
namespace
{
constexpr auto disk_image = "lfstest.img";
-}
-TEST_CASE("Littlefs: Basic mount and functionality")
+ auto prepare_filesystem(std::string_view dev_name)
+ -> std::pair<std::unique_ptr<purefs::fs::filesystem>, std::shared_ptr<purefs::blkdev::disk_manager>>
+ {
+ using namespace purefs;
+
+ auto dm = std::make_shared<blkdev::disk_manager>();
+ auto disk = std::make_shared<blkdev::disk_image>(disk_image);
+
+ if (dm->register_device(disk, dev_name) != 0) {
+ return {};
+ }
+
+ auto fs_core = std::make_unique<fs::filesystem>(dm);
+ const auto vfs_lfs = std::make_shared<fs::drivers::filesystem_littlefs>();
+
+ if (fs_core->register_filesystem("littlefs", vfs_lfs) != 0) {
+ return {};
+ }
+
+ return std::make_pair(std::move(fs_core), std::move(dm));
+ }
+} // namespace
+
+TEST_CASE("littlefs: Basic mount and functionality")
{
using namespace purefs;
+
auto dm = std::make_shared<blkdev::disk_manager>();
auto disk = std::make_shared<blkdev::disk_image>(disk_image);
REQUIRE(disk);
REQUIRE(dm->register_device(disk, "emmc0") == 0);
- purefs::fs::filesystem fscore(dm);
- const auto vfs_vfat = std::make_shared<fs::drivers::filesystem_littlefs>();
- REQUIRE(vfs_vfat->mount_count() == 0);
- auto ret = fscore.register_filesystem("littlefs", vfs_vfat);
- REQUIRE(ret == 0);
- ret = fscore.mount("emmc0part0", "/sys", "littlefs");
- REQUIRE(ret == 0);
- REQUIRE(vfs_vfat->mount_count() == 1);
- REQUIRE(fscore.umount("/ala") == -ENOENT);
- ret = fscore.mount("emmc0part0", "/sys", "vfat");
- REQUIRE(ret == -EBUSY);
- ret = fscore.mount("emmc0part0", "/path", "vfat");
- REQUIRE(ret == -EBUSY);
- ret = fscore.umount("/sys");
- REQUIRE(ret == 0);
- REQUIRE(vfs_vfat->mount_count() == 0);
- ret = fscore.mount("emmc0part0", "/path", "littlefs");
- REQUIRE(ret == 0);
- REQUIRE(vfs_vfat->mount_count() == 1);
- ret = fscore.umount("/path");
- REQUIRE(ret == 0);
+
+ fs::filesystem fscore(dm);
+ const auto vfs_lfs = std::make_shared<fs::drivers::filesystem_littlefs>();
+ REQUIRE(vfs_lfs->mount_count() == 0);
+ REQUIRE(fscore.register_filesystem("littlefs", vfs_lfs) == 0);
+
+ REQUIRE(fscore.mount("emmc0part0", "/sys", "littlefs") == 0);
+ REQUIRE(vfs_lfs->mount_count() == 1);
+
+ SECTION("Mount non-existent partition")
+ {
+ REQUIRE(fscore.mount("dummy0part0", "/dummy", "littlefs") == -ENXIO);
+ }
+ SECTION("Umount not mounted point")
+ {
+ REQUIRE(fscore.umount("/ala") == -ENOENT);
+ }
+ SECTION("Mount when already mounted")
+ {
+ REQUIRE(fscore.mount("emmc0part0", "/sys", "vfat") == -EBUSY);
+ }
+ SECTION("Mount invalid filesystem type")
+ {
+ REQUIRE(fscore.mount("emmc0part0", "/path", "vfat") == -EBUSY);
+ }
+ SECTION("statvfs")
+ {
+ struct statvfs ssv;
+ REQUIRE(fscore.stat_vfs("/sys/", ssv) == 0);
+ }
+
+ REQUIRE(fscore.umount("/sys") == 0);
+ REQUIRE(vfs_lfs->mount_count() == 0);
+
+ REQUIRE(fscore.mount("emmc0part0", "/path", "littlefs") == 0);
+ REQUIRE(vfs_lfs->mount_count() == 1);
+ REQUIRE(fscore.umount("/path") == 0);
}
-TEST_CASE("littlefs: Basic API test")
+TEST_CASE("littlefs: Read tests")
{
- using namespace purefs;
- auto dm = std::make_shared<blkdev::disk_manager>();
- auto disk = std::make_shared<blkdev::disk_image>(disk_image);
- REQUIRE(disk);
- REQUIRE(dm->register_device(disk, "emmc0") == 0);
- purefs::fs::filesystem fscore(dm);
- const auto vfs_vfat = std::make_shared<fs::drivers::filesystem_littlefs>();
- REQUIRE(vfs_vfat->mount_count() == 0);
- auto ret = fscore.register_filesystem("littlefs", vfs_vfat);
- REQUIRE(ret == 0);
- // List partitions
- for (const auto &part : dm->partitions("emmc0")) {
- std::cout << part.name << " " << part.bootable << std::endl;
- }
- ret = fscore.mount("emmc0part0", "/sys", "littlefs");
- REQUIRE(ret == 0);
+ auto [fs_core, dm] = prepare_filesystem("emmc0");
+ REQUIRE(fs_core);
+ REQUIRE(fs_core->mount("emmc0part0", "/sys", "littlefs") == 0);
+
+ const auto fd = fs_core->open("/sys/test_read_1.txt", O_RDONLY, 0);
+ REQUIRE(fd >= 3);
+
+ static char buf[64];
+
+ SECTION("Simple read")
{
- struct statvfs ssv;
- ret = fscore.stat_vfs("/sys/", ssv);
- REQUIRE(ret == 0);
+ REQUIRE(fs_core->read(fd, buf, 8) == 8);
+ REQUIRE(memcmp(buf, "01234567", 8) == 0);
}
+ SECTION("Read after seek")
+ {
+ REQUIRE(fs_core->seek(fd, 4, SEEK_SET) == 4);
+ REQUIRE(fs_core->read(fd, buf, 8) == 8);
+ REQUIRE(memcmp(buf, "456789AB", 8) == 0);
+ }
+ SECTION("File fstat")
{
- ret = fscore.open("/sys/ala/ma/kota/", 0, 0);
- REQUIRE(ret == -ENOENT);
- // Simple file test
- int hwnd = fscore.open("/sys/fonts/gt_pressura_bold_27.mpf", 0, 0);
- REQUIRE(hwnd >= 3);
- std::cout << "File open handle " << hwnd << std::endl;
struct stat st;
- ret = fscore.fstat(hwnd, st);
- REQUIRE(ret == 0);
- std::cout << "File size " << st.st_size << std::endl;
- char buf[4096]{};
- ret = fscore.read(hwnd, buf, sizeof buf);
- REQUIRE(ret > 0);
- ret = fscore.close(hwnd);
- REQUIRE(ret == 0);
+ REQUIRE(fs_core->fstat(fd, st) == 0);
+ REQUIRE(st.st_mode & S_IFREG);
+ REQUIRE((st.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == (S_IRUSR | S_IRGRP | S_IROTH));
}
+
+ REQUIRE(fs_core->close(fd) == 0);
+ REQUIRE(fs_core->umount("/sys") == 0);
+}
+
+TEST_CASE("littlefs: Write tests")
+{
+ auto [fs_core, dm] = prepare_filesystem("emmc0");
+ REQUIRE(fs_core);
+ REQUIRE(fs_core->mount("emmc0part0", "/sys", "littlefs") == 0);
+
+ SECTION("Create, write & unlink file")
{
+ static constexpr auto filename = "/sys/test_write_tmp_1.txt";
+ auto fd = fs_core->open(filename, O_CREAT | O_RDWR, 0);
+ REQUIRE(fd >= 3);
+
+ const std::string str = "Hello, littlefs!";
+ REQUIRE(fs_core->write(fd, str.c_str(), str.length()) == static_cast<ssize_t>(str.length()));
+
+ // reopen the file to flush write buffers
+ REQUIRE(fs_core->close(fd) == 0);
+ fd = fs_core->open(filename, O_RDONLY, 0);
+ REQUIRE(fd >= 3);
+
+ static char buf[64];
+ REQUIRE(fs_core->read(fd, buf, str.length()) == static_cast<ssize_t>(str.length()));
+ REQUIRE(memcmp(buf, str.c_str(), str.length()) == 0);
+
+ REQUIRE(fs_core->close(fd) == 0);
+ REQUIRE(fs_core->unlink(filename) == 0);
+ }
+
+ REQUIRE(fs_core->umount("/sys") == 0);
+}
+
+TEST_CASE("littlefs: Read-only filesystem tests")
+{
+ auto [fs_core, dm] = prepare_filesystem("emmc0");
+ REQUIRE(fs_core);
+ REQUIRE(fs_core->mount("emmc0part0", "/sys", "littlefs", purefs::fs::mount_flags::read_only) == 0);
+
+ SECTION("Open and stat file with O_RDONLY")
+ {
+ const auto fd = fs_core->open("/sys/test_read_1.txt", O_RDONLY, 0);
+ REQUIRE(fd >= 3);
+
struct stat st;
- int ndirs{};
- // Simple directory test
- auto dirhandle = fscore.diropen("/sys/fonts/");
- REQUIRE(dirhandle);
- REQUIRE(dirhandle->error() == 0);
- for (std::string fnm;;) {
- if (fscore.dirnext(dirhandle, fnm, st) != 0) {
- break;
+ REQUIRE(fs_core->fstat(fd, st) == 0);
+ REQUIRE(st.st_mode & S_IFREG);
+ REQUIRE((st.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == (S_IRUSR | S_IRGRP | S_IROTH));
+ REQUIRE((st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0);
+
+ REQUIRE(fs_core->close(fd) == 0);
+ }
+ SECTION("Open file with O_RDWR")
+ {
+ REQUIRE(fs_core->open("/sys/test_read_1.txt", O_RDWR, 0) == -EACCES);
+ }
+ SECTION("Create directory")
+ {
+ REQUIRE(fs_core->mkdir("/sys/tmp_dir", 0) == -EACCES);
+ }
+ SECTION("Unlink file")
+ {
+ REQUIRE(fs_core->unlink("/sys/dummy_file.txt") == -EACCES);
+ }
+
+ REQUIRE(fs_core->umount("/sys") == 0);
+}
+
+TEST_CASE("littlefs: Directory tests")
+{
+ auto [fs_core, dm] = prepare_filesystem("emmc0");
+ REQUIRE(fs_core);
+ REQUIRE(fs_core->mount("emmc0part0", "/sys", "littlefs") == 0);
+
+ SECTION("Create directory")
+ {
+ const std::string path = "/sys/test_mkdir_tmp";
+ REQUIRE(fs_core->mkdir(path, 0) == 0);
+
+ SECTION("Attempt to create existing directory")
+ {
+ REQUIRE(fs_core->mkdir(path, 0) == -EEXIST);
+ }
+ SECTION("Iterate over directory")
+ {
+ const std::vector<std::string> filenames = {
+ "document.txt", "image.jpg", "ringtone.mp3", "data.csv", "picture.png"};
+ std::vector<int> fds;
+ std::transform(filenames.begin(), filenames.end(), std::back_inserter(fds), [&](const auto &filename) {
+ return fs_core->open(path + "/" + filename, O_CREAT | O_RDWR, 0);
+ });
+ REQUIRE(std::all_of(fds.begin(), fds.end(), [](auto fd) { return fd >= 3; }));
+ const auto dh = fs_core->diropen(path);
+ REQUIRE(dh);
+
+ SECTION("Simple iterate")
+ {
+ std::vector<std::string> dir_filenames;
+ int dir_status = 0;
+ for (;;) {
+ std::string fn;
+ struct stat st;
+ dir_status = fs_core->dirnext(dh, fn, st);
+
+ if (dir_status == 0) {
+ dir_filenames.push_back(fn);
+ }
+ else {
+ break;
+ }
+ }
+
+ REQUIRE(dir_status == -ENODATA);
+ REQUIRE(std::all_of(filenames.begin(), filenames.end(), [&dir_filenames](const auto &fn) {
+ return std::find(dir_filenames.begin(), dir_filenames.end(), fn) != dir_filenames.end();
+ }));
+ }
+ SECTION("Directory reset")
+ {
+ struct stat st;
+ std::string first_fn;
+ REQUIRE(fs_core->dirnext(dh, first_fn, st) == 0);
+
+ for (std::string tmp_fn; fs_core->dirnext(dh, tmp_fn, st) == 0;)
+ ;
+ REQUIRE(fs_core->dirreset(dh) == 0);
+
+ std::string reset_fn;
+ REQUIRE(fs_core->dirnext(dh, reset_fn, st) == 0);
+ REQUIRE(reset_fn == first_fn);
+ }
+
+ REQUIRE(fs_core->dirclose(dh) == 0);
+ for (auto fd : fds) {
+ REQUIRE(fs_core->close(fd) == 0);
}
- else {
- std::cout << "name " << fnm << " size " << st.st_size << std::endl;
- ndirs++;
+ for (const auto &filename : filenames) {
+ REQUIRE(fs_core->unlink(path + "/" + filename) == 0);
}
}
- fscore.dirclose(dirhandle);
- REQUIRE(ndirs > 0);
+
+ REQUIRE(fs_core->unlink(path) == 0);
+ }
+
+ REQUIRE(fs_core->umount("/sys") == 0);
+}
+
+TEST_CASE("littlefs: Remount RO->RW->RW")
+{
+ using namespace purefs;
+ static constexpr auto filename = "/sys/remount_test.txt";
+
+ auto [fs_core, dm] = prepare_filesystem("emmc0");
+ REQUIRE(fs_core);
+ REQUIRE(fs_core->mount("emmc0part0", "/sys", "littlefs", fs::mount_flags::read_only) == 0);
+ REQUIRE(fs_core->open(filename, O_RDWR | O_CREAT, 0) == -EACCES);
+
+ const std::string wr_str = "remount_test";
+
+ {
+ REQUIRE(fs_core->mount("", "/sys", "", fs::mount_flags::remount) == 0);
+ const auto fd = fs_core->open(filename, O_RDWR | O_CREAT, 0);
+ REQUIRE(fd >= 3);
+ REQUIRE(fs_core->write(fd, wr_str.c_str(), wr_str.length()) == static_cast<ssize_t>(wr_str.length()));
+ REQUIRE(fs_core->close(fd) == 0);
+ }
+
+ {
+ REQUIRE(fs_core->mount("", "/sys", "", fs::mount_flags::remount | fs::mount_flags::read_only) == 0);
+ const auto fd = fs_core->open(filename, O_RDONLY, 0);
+ REQUIRE(fd >= 3);
+ char buf[64];
+ REQUIRE(fs_core->read(fd, buf, wr_str.length()) == static_cast<ssize_t>(wr_str.length()));
+ REQUIRE(memcmp(buf, wr_str.c_str(), wr_str.length()) == 0);
+ REQUIRE(fs_core->close(fd) == 0);
+ }
+
+ {
+ REQUIRE(fs_core->mount("", "/sys", "", fs::mount_flags::remount) == 0);
+ REQUIRE(fs_core->unlink(filename) == 0);
}
- ret = fscore.umount("/sys");
- REQUIRE(ret == 0);
+
+ REQUIRE(fs_core->umount("/sys") == 0);
}