M .gitmodules => .gitmodules +4 -0
@@ 95,3 95,7 @@
[submodule "klib"]
path = third-party/klib/src
url = https://github.com/attractivechaos/klib.git
+[submodule "third-party/lwext4/lwext4"]
+ path = third-party/lwext4/lwext4
+ url = ../lwext4.git
+ branch = mudita
M board/linux/libiosyscalls/src/syscalls_posix.cpp => board/linux/libiosyscalls/src/syscalls_posix.cpp +21 -4
@@ 25,6 25,7 @@ namespace
{
__REAL_DECL(link);
__REAL_DECL(unlink);
+ __REAL_DECL(rmdir);
__REAL_DECL(symlink);
__REAL_DECL(fcntl);
@@ 82,6 83,7 @@ namespace
{
__REAL_DLSYM(link);
__REAL_DLSYM(unlink);
+ __REAL_DLSYM(rmdir);
__REAL_DLSYM(symlink);
__REAL_DLSYM(fcntl);
@@ 130,10 132,10 @@ namespace
__REAL_DLSYM(poll);
__REAL_DLSYM(statvfs);
- if (!(real::link && real::unlink && real::symlink && real::fcntl && real::chdir && real::fchdir &&
- real::getcwd && real::getwd && real::get_current_dir_name && real::mkdir && real::chmod && real::fchmod &&
- real::fsync && real::fdatasync && real::read && real::write && real::lseek && real::lseek64 &&
- real::mount && real::umount && real::ioctl && real::poll && real::statvfs
+ if (!(real::link && real::unlink && real::rmdir && real::symlink && real::fcntl && real::chdir &&
+ real::fchdir && real::getcwd && real::getwd && real::get_current_dir_name && real::mkdir && real::chmod &&
+ real::fchmod && real::fsync && real::fdatasync && real::read && real::write && real::lseek &&
+ real::lseek64 && real::mount && real::umount && real::ioctl && real::poll && real::statvfs
#if __GLIBC__ > 2 || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 28))
&& real::fcntl64
#endif
@@ 286,6 288,21 @@ extern "C"
}
__asm__(".symver _iosys_unlink,unlink@GLIBC_2.2.5");
+ int _iosys_rmdir(const char *name)
+ {
+ if (vfs::redirect_to_image(name)) {
+ TRACE_SYSCALLN("(%s) -> VFS", name);
+ return vfs::invoke_fs(&fs::rmdir, name);
+ }
+ else {
+ TRACE_SYSCALLN("(%s) -> linux fs", name);
+ char tmp[PATH_MAX];
+ const auto path = vfs::npath_translate(name, tmp);
+ return real::rmdir(path);
+ }
+ }
+ __asm__(".symver _iosys_rmdir,rmdir@GLIBC_2.2.5");
+
int _iosys_fcntl(int fd, int cmd, ... /* arg */)
{
if (vfs::is_image_fd(fd)) {
M board/rt1051/newlib/io_syscalls.cpp => board/rt1051/newlib/io_syscalls.cpp +4 -1
@@ 57,7 57,10 @@ extern "C"
{
return syscalls::stat(r->_errno, file, pstat);
}
-
+ int rmdir(const char *path)
+ {
+ return syscalls::rmdir(_REENT->_errno, path);
+ }
/** POSIX directory related funcs */
int chdir(const char *path)
{
M module-platform/linux/tests/CMakeLists.txt => module-platform/linux/tests/CMakeLists.txt +18 -0
@@ 37,6 37,13 @@ add_custom_target(
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS genlittlefs test-assets
)
+set(EXT4_IMAGE "ext4test.img")
+add_custom_target(
+ ${EXT4_IMAGE}
+ COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/genext4diskimg.sh 1G ${EXT4_IMAGE} ${CMAKE_BINARY_DIR}/module-platform/test_dir
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+ DEPENDS genlittlefs test-assets
+)
add_catch2_executable(
NAME vfs-littlefs
@@ 51,6 58,17 @@ add_catch2_executable(
)
add_catch2_executable(
+ NAME vfs-ext4
+ SRCS
+ ${CMAKE_CURRENT_LIST_DIR}/unittest_filesystem_ext4.cpp
+ LIBS
+ platform
+ DEPS
+ ${EXT4_IMAGE}
+ USE_FS
+)
+
+add_catch2_executable(
NAME vfs-dualmount
SRCS
${CMAKE_CURRENT_LIST_DIR}/unittest_filesystem_dualmount.cpp
A module-platform/linux/tests/genext4diskimg.sh => module-platform/linux/tests/genext4diskimg.sh +62 -0
@@ 0,0 1,62 @@
+#!/bin/bash -e
+#Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+#For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+usage() {
+cat << ==usage
+Usage: $(basename $0) [image_size] [image_file] [sysroot]
+ image_size Target disk image size in bytes
+ image_file Target image name
+ sysroot Source directory with files
+==usage
+}
+
+if [ $# -lt 2 ]; then
+ echo "Error! Invalid argument count"
+ usage
+ exit -1
+fi
+IMAGE_SIZE="$1"
+IMAGE_FILE="$2"
+SYSROOT="$3"
+shift 3
+
+if [ ! -d "${SYSROOT}" ]; then
+ echo "Invalid sysroot: ${SYSROOT}"
+ exit -1
+fi
+
+_REQ_CMDS="sfdisk truncate mke2fs"
+for cmd in $_REQ_CMDS; do
+ if [ ! $(command -v $cmd) ]; then
+ echo "Error! $cmd is not installed, please use 'sudo apt install' for install required tool"
+ exit -1
+ fi
+done
+truncate -s $IMAGE_SIZE $IMAGE_FILE
+
+SECTOR_START=2048
+SECTOR_END=$(( $(stat -c "%s" $IMAGE_FILE)/512 - $SECTOR_START))
+
+sfdisk $IMAGE_FILE << ==sfdisk
+label: dos
+unit: sectors
+
+/dev/sdz1 : start=$SECTOR_START, size=$SECTOR_END, type=83
+==sfdisk
+
+#Generate image
+mke2fs \
+ -F \
+ -L 'user' \
+ -N 0 \
+ -E offset=$(($SECTOR_START*512)) \
+ -O ^64bit \
+ -O ^flex_bg \
+ -O ^metadata_csum \
+ -d "${SYSROOT}" \
+ -m 0 \
+ -r 1 \
+ -t ext4 \
+ "$IMAGE_FILE" \
+;
M module-platform/linux/tests/unittest_filesystem_core.cpp => module-platform/linux/tests/unittest_filesystem_core.cpp +8 -4
@@ 134,7 134,7 @@ TEST_CASE("Corefs: Create new file, write, read from it")
fscore.write(hwnd, text.c_str(), text.size());
REQUIRE(fscore.close(hwnd) == 0);
- SECTION("Read from file")
+
{
int hwnd = fscore.open("/sys/test.txt", O_RDONLY, 0);
REQUIRE(hwnd >= 3);
@@ 142,10 142,8 @@ TEST_CASE("Corefs: Create new file, write, read from it")
REQUIRE(fscore.read(hwnd, buf, sizeof(buf)) == 4);
REQUIRE(strcmp(buf, text.c_str()) == 0);
fscore.close(hwnd);
- REQUIRE(fscore.umount("/sys") == 0);
}
- SECTION("Test seek file")
{
int hwnd = fscore.open("/sys/test.txt", O_RDONLY, 0);
REQUIRE(hwnd >= 3);
@@ 155,8 153,14 @@ TEST_CASE("Corefs: Create new file, write, read from it")
REQUIRE(fscore.read(hwnd, buf, sizeof(buf)) == 0);
REQUIRE(fscore.seek(hwnd, 0, SEEK_SET) == 0);
fscore.close(hwnd);
- REQUIRE(fscore.umount("/sys") == 0);
}
+
+ {
+ REQUIRE(fscore.rmdir("/sys/test23") == -ENOENT);
+ REQUIRE(fscore.mkdir("/sys/testdirxyzk", 0666) == 0);
+ REQUIRE(fscore.rmdir("/sys/testdirxyzk") == 0);
+ }
+ REQUIRE(fscore.umount("/sys") == 0);
}
TEST_CASE("Corefs: Register null filesystem")
A module-platform/linux/tests/unittest_filesystem_ext4.cpp => module-platform/linux/tests/unittest_filesystem_ext4.cpp +271 -0
@@ 0,0 1,271 @@
+// 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 <platform/linux/DiskImage.hpp>
+
+#include <purefs/fs/filesystem.hpp>
+#include <purefs/blkdev/disk_manager.hpp>
+#include <purefs/fs/drivers/filesystem_ext4.hpp>
+#include <sys/statvfs.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <cstring>
+
+namespace
+{
+ constexpr auto disk_image = "ext4test.img";
+
+ 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_ext4>();
+
+ if (fs_core->register_filesystem("ext4", vfs_lfs) != 0) {
+ return {};
+ }
+
+ return std::make_pair(std::move(fs_core), std::move(dm));
+ }
+} // namespace
+
+TEST_CASE("ext4: 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);
+
+ fs::filesystem fscore(dm);
+ const auto vfs_ext = std::make_shared<fs::drivers::filesystem_ext4>();
+ REQUIRE(vfs_ext->mount_count() == 0);
+ REQUIRE(fscore.register_filesystem("ext4", vfs_ext) == 0);
+
+ REQUIRE(fscore.mount("emmc0part0", "/sys", "ext4") == 0);
+ REQUIRE(vfs_ext->mount_count() == 1);
+
+ REQUIRE(fscore.mount("dummy0part0", "/dummy", "ext4") == -ENXIO);
+ REQUIRE(fscore.umount("/ala") == -ENOENT);
+ REQUIRE(fscore.mount("emmc0part0", "/sys", "vfat") == -EBUSY);
+ REQUIRE(fscore.mount("emmc0part0", "/path", "vfat") == -EBUSY);
+ struct statvfs ssv;
+ REQUIRE(fscore.stat_vfs("/sys/", ssv) == 0);
+
+ REQUIRE(fscore.umount("/sys") == 0);
+ REQUIRE(vfs_ext->mount_count() == 0);
+
+ REQUIRE(fscore.mount("emmc0part0", "/path", "ext4") == 0);
+ REQUIRE(vfs_ext->mount_count() == 1);
+ REQUIRE(fscore.umount("/path") == 0);
+}
+
+TEST_CASE("ext4: Read tests")
+{
+ auto [fs_core, dm] = prepare_filesystem("emmc0");
+ REQUIRE(fs_core);
+ REQUIRE(fs_core->mount("emmc0part0", "/sys", "ext4") == 0);
+
+ const auto fd = fs_core->open("/sys/test_read_1.txt", O_RDONLY, 0);
+ REQUIRE(fd >= 3);
+
+ static char buf[64];
+
+ REQUIRE(fs_core->read(fd, buf, 8) == 8);
+ REQUIRE(memcmp(buf, "01234567", 8) == 0);
+ REQUIRE(fs_core->seek(fd, 4, SEEK_SET) == 4);
+ REQUIRE(fs_core->read(fd, buf, 8) == 8);
+ REQUIRE(memcmp(buf, "456789AB", 8) == 0);
+ struct stat st;
+ 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("ext4: Write tests")
+{
+ auto [fs_core, dm] = prepare_filesystem("emmc0");
+ REQUIRE(fs_core);
+ REQUIRE(fs_core->mount("emmc0part0", "/sys", "ext4") == 0);
+
+ 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);
+
+ // Test the ftruncate
+ static constexpr auto trunc_fname = "/sys/test_truncate.bin";
+ static auto trunc_fsize = 1024 * 256 + 4;
+ fd = fs_core->open(trunc_fname, O_CREAT | O_RDWR, 0);
+ REQUIRE(fd >= 3);
+ REQUIRE(fs_core->ftruncate(fd, trunc_fsize) == 0);
+ REQUIRE(fs_core->close(fd) == 0);
+ struct stat st;
+ REQUIRE(fs_core->stat(trunc_fname, st) == 0);
+ REQUIRE(st.st_mode & S_IFREG);
+ REQUIRE(st.st_size == trunc_fsize);
+ REQUIRE(fs_core->unlink(trunc_fname) == 0);
+
+ REQUIRE(fs_core->umount("/sys") == 0);
+}
+
+TEST_CASE("ext4: Read-only filesystem tests")
+{
+ auto [fs_core, dm] = prepare_filesystem("emmc0");
+ REQUIRE(fs_core);
+ REQUIRE(fs_core->mount("emmc0part0", "/sys", "ext4", purefs::fs::mount_flags::read_only) == 0);
+
+ const auto fd = fs_core->open("/sys/test_read_1.txt", O_RDONLY, 0);
+ REQUIRE(fd >= 3);
+
+ struct stat st;
+ 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);
+ REQUIRE(fs_core->open("/sys/test_read_1.txt", O_RDWR, 0) == -EACCES);
+ REQUIRE(fs_core->mkdir("/sys/tmp_dir", 0) == -EACCES);
+ REQUIRE(fs_core->unlink("/sys/dummy_file.txt") == -EACCES);
+ REQUIRE(fs_core->umount("/sys") == 0);
+}
+
+TEST_CASE("ext4: Directory tests")
+{
+ auto [fs_core, dm] = prepare_filesystem("emmc0");
+ REQUIRE(fs_core);
+ REQUIRE(fs_core->mount("emmc0part0", "/sys", "ext4") == 0);
+
+ const std::string path = "/sys/test_mkdir_tmp";
+ REQUIRE(fs_core->mkdir(path, 0) == 0);
+ REQUIRE(fs_core->mkdir(path, 0) == -EEXIST);
+ {
+ 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; }));
+ for (auto fd : fds) {
+ REQUIRE(fs_core->close(fd) == 0);
+ }
+
+ {
+ const auto dh = fs_core->diropen(path);
+ REQUIRE(dh);
+ 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();
+ }));
+ REQUIRE(fs_core->dirclose(dh) == 0);
+ }
+ {
+ const auto dh = fs_core->diropen(path);
+ REQUIRE(dh);
+ 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 (const auto &filename : filenames) {
+ REQUIRE(fs_core->unlink(path + "/" + filename) == 0);
+ }
+ REQUIRE(fs_core->rmdir(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", "ext4", 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);
+ }
+
+ REQUIRE(fs_core->umount("/sys") == 0);
+}
M module-platform/linux/tests/unittest_filesystem_littlefs.cpp => module-platform/linux/tests/unittest_filesystem_littlefs.cpp +2 -2
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// 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>
@@ 260,7 260,7 @@ TEST_CASE("littlefs: Directory tests")
}
}
- REQUIRE(fs_core->unlink(path) == 0);
+ REQUIRE(fs_core->rmdir(path) == 0);
}
REQUIRE(fs_core->umount("/sys") == 0);
M module-vfs/CMakeLists.txt => module-vfs/CMakeLists.txt +7 -0
@@ 19,17 19,23 @@ target_sources(module-vfs
drivers/include/purefs/fs/drivers/file_handle_littlefs.hpp
drivers/include/purefs/fs/drivers/file_handle_vfat.hpp
drivers/include/purefs/fs/drivers/filesystem_littlefs.hpp
+ drivers/include/purefs/fs/drivers/filesystem_ext4.hpp
drivers/include/purefs/fs/drivers/filesystem_vfat.hpp
drivers/include/purefs/fs/drivers/mount_point_littlefs.hpp
drivers/include/purefs/fs/drivers/mount_point_vfat.hpp
+ drivers/include/purefs/fs/drivers/mount_point_ext4.hpp
drivers/include/thirdparty/fatfs/ffconf.h
drivers/include/thirdparty/fatfs/volume_mapper.hpp
drivers/include/thirdparty/littlefs/volume_mapper.hpp
+ drivers/include/thirdparty/lwext4/ext4_bdev.hpp
drivers/src/purefs/fs/filesystem_littlefs.cpp
+ drivers/src/purefs/fs/filesystem_ext4.cpp
drivers/src/purefs/fs/filesystem_vfat.cpp
drivers/src/thirdparty/fatfs/ff_glue.cpp
drivers/src/thirdparty/fatfs/ffsystem.cpp
drivers/src/thirdparty/littlefs/lfs_glue.cpp
+ drivers/src/thirdparty/lwext4/ext4_bdev.cpp
+ drivers/src/purefs/fs/mount_point_ext4.cpp
include/internal/purefs/blkdev/disk_handle.hpp
include/internal/purefs/blkdev/partition_parser.hpp
@@ 93,6 99,7 @@ target_include_directories(module-vfs
target_link_libraries(module-vfs
PRIVATE
fatfs::fatfs
+ lwext4::lwext4
json::json
littlefs::littlefs
module-bsp
M module-vfs/board/rt1051/newlib/vfs_io_syscalls.cpp => module-vfs/board/rt1051/newlib/vfs_io_syscalls.cpp +31 -2
@@ 35,6 35,30 @@ namespace
}
return ret;
}
+ auto stmode_to_type(mode_t mode)
+ {
+ if (S_ISREG(mode)) {
+ return DT_REG;
+ }
+ else if (S_ISDIR(mode)) {
+ return DT_DIR;
+ }
+ else if (S_ISCHR(mode)) {
+ return DT_CHR;
+ }
+ else if (S_ISBLK(mode)) {
+ return DT_BLK;
+ }
+ else if (S_ISFIFO(mode)) {
+ return DT_FIFO;
+ }
+ else if (S_ISSOCK(mode)) {
+ return DT_SOCK;
+ }
+ else {
+ return 0;
+ }
+ }
} // namespace
namespace vfsn::internal::syscalls
@@ 85,6 109,11 @@ namespace vfsn::internal::syscalls
return invoke_fs(_errno_, &purefs::fs::filesystem::unlink, name);
}
+ int rmdir(int &_errno_, const char *name)
+ {
+ return invoke_fs(_errno_, &purefs::fs::filesystem::rmdir, name);
+ }
+
int fcntl(int &_errno_, int fd, int cmd, int arg)
{
_errno_ = ENOTSUP;
@@ 215,7 244,7 @@ namespace vfsn::internal::syscalls
}
dirp->position += 1;
dirp->dir_data.d_ino = stdata.st_ino;
- dirp->dir_data.d_type = S_ISREG(stdata.st_mode) ? DT_REG : DT_DIR;
+ dirp->dir_data.d_type = stmode_to_type(stdata.st_mode);
dirp->dir_data.d_reclen = fname.size();
std::strncpy(dirp->dir_data.d_name, fname.c_str(), sizeof(dirp->dir_data.d_name));
return &dirp->dir_data;
@@ 255,7 284,7 @@ namespace vfsn::internal::syscalls
}
dirp->position += 1;
entry->d_ino = stdata.st_ino;
- entry->d_type = S_ISREG(stdata.st_mode) ? DT_REG : DT_DIR;
+ entry->d_type = stmode_to_type(stdata.st_mode);
entry->d_reclen = fname.size();
std::strncpy(entry->d_name, fname.c_str(), sizeof(entry->d_name));
*result = entry;
A module-vfs/drivers/include/purefs/fs/drivers/directory_handle_ext4.hpp => module-vfs/drivers/include/purefs/fs/drivers/directory_handle_ext4.hpp +26 -0
@@ 0,0 1,26 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <purefs/fs/directory_handle.hpp>
+#include <ext4.h>
+
+namespace purefs::fs::drivers
+{
+ class directory_handle_ext4 final : public internal::directory_handle
+ {
+ public:
+ directory_handle_ext4(std::shared_ptr<internal::mount_point> mp, int error)
+ : internal::directory_handle(mp, error)
+ {}
+ virtual ~directory_handle_ext4() = default;
+ auto dirp() noexcept
+ {
+ return &m_dir;
+ }
+
+ private:
+ ext4_dir m_dir{};
+ };
+} // namespace purefs::fs::drivers<
\ No newline at end of file
A module-vfs/drivers/include/purefs/fs/drivers/file_handle_ext4.hpp => module-vfs/drivers/include/purefs/fs/drivers/file_handle_ext4.hpp +32 -0
@@ 0,0 1,32 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+#include <purefs/fs/file_handle.hpp>
+#include <ext4_config.h>
+#include <ext4.h>
+
+namespace purefs::fs::drivers
+{
+ class file_handle_ext4 final : public internal::file_handle
+ {
+ public:
+ file_handle_ext4(std::shared_ptr<internal::mount_point> mp, std::string_view path, unsigned flags)
+ : file_handle(mp, flags), m_path(path)
+ {}
+ virtual ~file_handle_ext4() = default;
+ [[nodiscard]] auto filp() noexcept
+ {
+ return &m_file;
+ }
+ [[nodiscard]] auto open_path() const noexcept -> const std::string &
+ {
+ return m_path;
+ }
+
+ private:
+ ::ext4_file m_file{};
+ //! Store full path because some handle based fncs are not in lwext4
+ const std::string m_path;
+ };
+} // namespace purefs::fs::drivers
M module-vfs/drivers/include/purefs/fs/drivers/file_handle_littlefs.hpp => module-vfs/drivers/include/purefs/fs/drivers/file_handle_littlefs.hpp +2 -2
@@ 15,11 15,11 @@ namespace purefs::fs::drivers
: file_handle(mp, flags), m_path(path)
{}
virtual ~file_handle_littlefs() = default;
- auto lfs_filp() noexcept
+ [[nodiscard]] auto lfs_filp() noexcept
{
return &file;
}
- auto open_path() const noexcept -> const std::string &
+ [[nodiscard]] auto open_path() const noexcept -> const std::string &
{
return m_path;
}
A module-vfs/drivers/include/purefs/fs/drivers/filesystem_ext4.hpp => module-vfs/drivers/include/purefs/fs/drivers/filesystem_ext4.hpp +59 -0
@@ 0,0 1,59 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+#include <purefs/fs/filesystem_operations.hpp>
+
+namespace purefs::fs::drivers
+{
+
+ /** Filesystem specific driver for the ext4 fs */
+ class filesystem_ext4 final : public filesystem_operations
+ {
+ public:
+ using fsfile = std::shared_ptr<internal::file_handle>;
+ using fsdir = std::shared_ptr<internal::directory_handle>;
+ using fsmount = std::shared_ptr<internal::mount_point>;
+ filesystem_ext4() = default;
+ virtual ~filesystem_ext4() = default;
+
+ auto mount_prealloc(std::shared_ptr<blkdev::internal::disk_handle> diskh, std::string_view path, unsigned flags)
+ -> fsmount override;
+ auto mount(fsmount mnt, const void *data) noexcept -> int override;
+ auto umount(fsmount mnt) noexcept -> int override;
+ auto stat_vfs(fsmount mnt, std::string_view path, struct statvfs &stat) const noexcept -> int override;
+
+ /** Standard file access API */
+ auto open(fsmount mnt, std::string_view path, int flags, int mode) noexcept -> fsfile override;
+ auto close(fsfile zfile) noexcept -> int override;
+ auto write(fsfile zfile, const char *ptr, size_t len) noexcept -> ssize_t override;
+ auto read(fsfile zfile, char *ptr, size_t len) noexcept -> ssize_t override;
+ auto seek(fsfile zfile, off_t pos, int dir) noexcept -> off_t override;
+ auto fstat(fsfile zfile, struct stat &st) noexcept -> int override;
+ auto stat(fsmount mnt, std::string_view file, struct stat &st) noexcept -> int override;
+ auto link(fsmount mnt, std::string_view existing, std::string_view newlink) noexcept -> int override;
+ auto symlink(fsmount mnt, std::string_view existing, std::string_view newlink) noexcept -> int override;
+ auto unlink(fsmount mnt, std::string_view name) noexcept -> int override;
+ auto rmdir(fsmount mnt, std::string_view name) noexcept -> int override;
+ auto rename(fsmount mnt, std::string_view oldname, std::string_view newname) noexcept -> int override;
+ auto mkdir(fsmount mnt, std::string_view path, int mode) noexcept -> int override;
+
+ /** Directory support API */
+ auto diropen(fsmount mnt, std::string_view path) noexcept -> fsdir override;
+ auto dirreset(fsdir dirstate) noexcept -> int override;
+ auto dirnext(fsdir dirstate, std::string &filename, struct stat &filestat) -> int override;
+ auto dirclose(fsdir dirstate) noexcept -> int override;
+
+ /** Other fops API */
+ auto ftruncate(fsfile zfile, off_t len) noexcept -> int override;
+ auto fsync(fsfile zfile) noexcept -> int override;
+ auto isatty(fsfile zfile) noexcept -> int override;
+
+ auto chmod(fsmount mnt, std::string_view path, mode_t mode) noexcept -> int override;
+ auto fchmod(fsfile zfile, mode_t mode) noexcept -> int override;
+
+ private:
+ static auto stat(const char *mount_point, const char *path, struct stat *st, bool ro) noexcept -> int;
+ };
+
+} // namespace purefs::fs::drivers
M module-vfs/drivers/include/purefs/fs/drivers/filesystem_littlefs.hpp => module-vfs/drivers/include/purefs/fs/drivers/filesystem_littlefs.hpp +2 -1
@@ 8,7 8,7 @@
namespace purefs::fs::drivers
{
- /** Filesystem specific driver base class */
+ /** Filesystem specific driver for the littlefs */
class filesystem_littlefs final : public filesystem_operations
{
public:
@@ 35,6 35,7 @@ namespace purefs::fs::drivers
auto fstat(fsfile zfile, struct stat &st) noexcept -> int override;
auto stat(fsmount mnt, std::string_view file, struct stat &st) noexcept -> int override;
auto unlink(fsmount mnt, std::string_view name) noexcept -> int override;
+ auto rmdir(fsmount mnt, std::string_view name) noexcept -> int override;
auto rename(fsmount mnt, std::string_view oldname, std::string_view newname) noexcept -> int override;
auto mkdir(fsmount mnt, std::string_view path, int mode) noexcept -> int override;
auto fchmod(fsfile zfile, mode_t mode) noexcept -> int override;
M module-vfs/drivers/include/purefs/fs/drivers/filesystem_vfat.hpp => module-vfs/drivers/include/purefs/fs/drivers/filesystem_vfat.hpp +2 -1
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
@@ 30,6 30,7 @@ namespace purefs::fs::drivers
auto fstat(fsfile zfile, struct stat &st) noexcept -> int override;
auto stat(fsmount mnt, std::string_view file, struct stat &st) noexcept -> int override;
auto unlink(fsmount mnt, std::string_view name) noexcept -> int override;
+ auto rmdir(fsmount mnt, std::string_view name) noexcept -> int override;
auto rename(fsmount mnt, std::string_view oldname, std::string_view newname) noexcept -> int override;
auto mkdir(fsmount mnt, std::string_view path, int mode) noexcept -> int override;
A module-vfs/drivers/include/purefs/fs/drivers/mount_point_ext4.hpp => module-vfs/drivers/include/purefs/fs/drivers/mount_point_ext4.hpp +61 -0
@@ 0,0 1,61 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+#include <memory>
+#include <purefs/fs/mount_point.hpp>
+
+struct ext4_blockdev;
+namespace cpp_freertos
+{
+ class MutexRecursive;
+}
+
+namespace purefs::fs::drivers
+{
+ class mount_point_ext4 final : public purefs::fs::internal::mount_point
+ {
+ public:
+ mount_point_ext4(std::shared_ptr<blkdev::internal::disk_handle> diskh,
+ std::string_view path,
+ unsigned flags,
+ std::shared_ptr<filesystem_operations> fs);
+ virtual ~mount_point_ext4();
+ [[nodiscard]] auto block_dev() const noexcept
+ {
+ return m_bdev;
+ }
+ auto block_dev(ext4_blockdev *bdev) noexcept -> void
+ {
+ m_bdev = bdev;
+ }
+ auto lock() noexcept -> void;
+ auto unlock() noexcept -> void;
+
+ private:
+ auto native_root() const noexcept -> std::string_view override
+ {
+ return m_root;
+ }
+ ext4_blockdev *m_bdev{};
+ const std::string m_root;
+ std::unique_ptr<cpp_freertos::MutexRecursive> m_lock;
+ };
+
+ // Fs locker
+ class ext4_locker
+ {
+ public:
+ explicit ext4_locker(std::shared_ptr<mount_point_ext4> mnt_ext) : m_mnt_ext(mnt_ext)
+ {
+ m_mnt_ext->lock();
+ }
+ ~ext4_locker()
+ {
+ m_mnt_ext->unlock();
+ }
+
+ private:
+ const std::shared_ptr<mount_point_ext4> m_mnt_ext;
+ };
+} // namespace purefs::fs::drivers
A module-vfs/drivers/include/thirdparty/lwext4/ext4_bdev.hpp => module-vfs/drivers/include/thirdparty/lwext4/ext4_bdev.hpp +31 -0
@@ 0,0 1,31 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <purefs/blkdev/defs.hpp>
+
+namespace purefs::blkdev
+{
+ class disk_manager;
+}
+
+struct ext4_blockdev;
+
+namespace purefs::fs::drivers::ext4::internal
+{
+ /**
+ * Append volume and return ext4 block device
+ * @param diskmm Disk manager
+ * @param diskh Disk handle in the manager
+ * @return block device and error code
+ */
+ std::pair<ext4_blockdev *, int> append_volume(std::shared_ptr<blkdev::disk_manager> diskmm, blkdev::disk_fd diskh);
+
+ /** Remove ext4 block device from the table
+ * @param ext4_block Ext4 block device for free
+ * @return error code
+ */
+ int remove_volume(ext4_blockdev *ext4_block);
+
+} // namespace purefs::fs::drivers::ext4::internal
A module-vfs/drivers/src/purefs/fs/filesystem_ext4.cpp => module-vfs/drivers/src/purefs/fs/filesystem_ext4.cpp +503 -0
@@ 0,0 1,503 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <purefs/fs/drivers/filesystem_ext4.hpp>
+#include <purefs/fs/drivers/mount_point_ext4.hpp>
+#include <purefs/blkdev/disk_manager.hpp>
+#include <purefs/blkdev/disk_handle.hpp>
+#include <purefs/fs/drivers/file_handle_ext4.hpp>
+#include <purefs/fs/drivers/directory_handle_ext4.hpp>
+#include <lwext4/ext4_bdev.hpp>
+#include <log.hpp>
+#include <ext4.h>
+#include <ext4_inode.h>
+#include <ext4_super.h>
+
+#include <climits>
+#include <syslimits.h>
+#include <sys/statvfs.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <cstring>
+#include <algorithm>
+#include <sys/stat.h>
+
+namespace purefs::fs::drivers
+{
+ namespace
+ {
+ template <typename T, typename... Args>
+ auto invoke_efs(filesystem_ext4::fsfile zfil, T efs_fun, Args &&... args)
+ {
+ auto vfile = std::dynamic_pointer_cast<file_handle_ext4>(zfil);
+ if (!vfile) {
+ LOG_ERROR("Non ext4 filesystem file pointer");
+ return -EBADF;
+ }
+ auto mntp = std::static_pointer_cast<mount_point_ext4>(vfile->mntpoint());
+ if (!mntp) {
+ LOG_ERROR("Non ext4 mount point");
+ return -EBADF;
+ }
+ ext4_locker _lck(mntp);
+ auto err = efs_fun(vfile->filp(), std::forward<Args>(args)...);
+ return -err;
+ }
+ template <typename T>
+ auto invoke_efs(filesystem_ext4::fsmount mnt, T efs_fun, std::string_view oldpath, std::string_view newpath)
+ {
+ auto mntp = std::static_pointer_cast<mount_point_ext4>(mnt);
+ if (!mntp) {
+ LOG_ERROR("Non ext4 mount point");
+ return -EBADF;
+ }
+ const auto native_old = mntp->native_path(oldpath);
+ const auto native_new = mntp->native_path(newpath);
+ ext4_locker _lck(mntp);
+ auto err = efs_fun(native_old.c_str(), native_new.c_str());
+ return -err;
+ }
+ template <typename T, typename... Args>
+ auto invoke_efs(filesystem_ext4::fsmount fmnt, T efs_fun, std::string_view path, Args &&... args)
+ {
+ auto mntp = std::static_pointer_cast<mount_point_ext4>(fmnt);
+ if (!mntp) {
+ LOG_ERROR("Non ext4 mount point");
+ return -EBADF;
+ }
+ const auto native_path = mntp->native_path(path);
+ ext4_locker _lck(mntp);
+ auto err = efs_fun(native_path.c_str(), std::forward<Args>(args)...);
+ return -err;
+ }
+ template <typename T, typename... Args> auto invoke_efs(filesystem_ext4::fsdir zdir, T lfs_fun, Args &&... args)
+ {
+ auto vdir = std::dynamic_pointer_cast<directory_handle_ext4>(zdir);
+ if (!vdir) {
+ LOG_ERROR("Non ext4 filesystem directory pointer");
+ return -EBADF;
+ }
+ auto mntp = std::static_pointer_cast<mount_point_ext4>(vdir->mntpoint());
+ if (!mntp) {
+ LOG_ERROR("Non ext4 mount point");
+ return -EBADF;
+ }
+ ext4_locker _lck(mntp);
+ auto err = lfs_fun(vdir->dirp(), std::forward<Args>(args)...);
+ return err;
+ }
+ inline auto ino_to_st_mode(int dtype)
+ {
+ switch (dtype) {
+ case EXT4_DE_REG_FILE:
+ return S_IFREG;
+ case EXT4_DE_DIR:
+ return S_IFDIR;
+ case EXT4_DE_CHRDEV:
+ return S_IFCHR;
+ case EXT4_DE_BLKDEV:
+ return S_IFBLK;
+ case EXT4_DE_FIFO:
+ return S_IFIFO;
+ case EXT4_DE_SOCK:
+ return S_IFSOCK;
+ default:
+ return 0;
+ }
+ }
+
+ } // namespace
+ auto filesystem_ext4::mount_prealloc(std::shared_ptr<blkdev::internal::disk_handle> diskh,
+ std::string_view path,
+ unsigned flags) -> fsmount
+ {
+ return std::make_shared<mount_point_ext4>(diskh, path, flags, shared_from_this());
+ }
+
+ auto filesystem_ext4::mount(fsmount mnt, const void *data) noexcept -> int
+ {
+ auto disk = mnt->disk();
+ if (!disk) {
+ return -EIO;
+ }
+ auto vmnt = std::dynamic_pointer_cast<mount_point_ext4>(mnt);
+ if (!vmnt) {
+ LOG_ERROR("Non ext4 mount point");
+ return -EIO;
+ }
+ ext4_locker _lck(vmnt);
+ auto [bd, err] = ext4::internal::append_volume(disk_mngr(), disk);
+ if (err) {
+ LOG_ERROR("Unable to append volume err: %i", err);
+ return err;
+ }
+ // Test only
+ ext4_dmask_set(DEBUG_ALL);
+ err = ext4_device_register(bd, disk->name().c_str());
+ if (err) {
+ LOG_ERROR("Unable to register device with err: %i", err);
+ ext4::internal::remove_volume(bd);
+ return -err;
+ }
+ const auto mnt_path = vmnt->mount_path();
+ // Mount
+ err = ext4_mount(disk->name().c_str(), mnt_path.c_str(), 0);
+ if (err) {
+ LOG_ERROR("Unable to mount ext4 errno %i", err);
+ ext4_device_unregister(disk->name().c_str());
+ ext4::internal::remove_volume(bd);
+ return -err;
+ }
+ // Start ext4 recover
+ err = ext4_recover(mnt_path.c_str());
+ if (err) {
+ LOG_ERROR("Ext4 recover failed errno %i", err);
+ ext4_umount(mnt_path.c_str());
+ ext4_device_unregister(disk->name().c_str());
+ ext4::internal::remove_volume(bd);
+ return -err;
+ }
+ // Start journaling
+ err = ext4_journal_start(mnt_path.c_str());
+ if (err) {
+ LOG_WARN("Unable to start journalling errno %i", err);
+ }
+ err = ext4_block_cache_write_back(bd, true);
+ if (err) {
+ LOG_ERROR("Unable to switch to write back mode errno %i", err);
+ ext4_umount(mnt_path.c_str());
+ ext4_device_unregister(disk->name().c_str());
+ ext4::internal::remove_volume(bd);
+ return -err;
+ }
+ filesystem_operations::mount(mnt, data);
+ vmnt->block_dev(bd);
+ return err;
+ }
+
+ // Unmount filesystem
+ auto filesystem_ext4::umount(fsmount mnt) noexcept -> int
+ {
+ auto vmnt = std::dynamic_pointer_cast<mount_point_ext4>(mnt);
+ if (!vmnt) {
+ LOG_ERROR("Non ext4 mount point");
+ return -EIO;
+ }
+ ext4_locker _lck(vmnt);
+ auto err = ext4_cache_write_back(mnt->mount_path().c_str(), false);
+ if (err) {
+ LOG_WARN("Unable to disable cache wb errno %i", err);
+ err = 0;
+ }
+ err = ext4_journal_stop(mnt->mount_path().c_str());
+ if (err) {
+ LOG_WARN("Unable to stop ext4 journal %i", err);
+ err = 0;
+ }
+ err = ext4_umount(mnt->mount_path().c_str());
+ if (err) {
+ LOG_ERROR("Unable to umount device");
+ return -err;
+ }
+ //! NOTE: Bug in the lib it always return ENOENT
+ ext4_device_unregister(vmnt->disk()->name().c_str());
+ err = ext4::internal::remove_volume(vmnt->block_dev());
+ if (err) {
+ LOG_ERROR("Remove volume error %i", err);
+ return err;
+ }
+ filesystem_operations::umount(mnt);
+ return err;
+ }
+
+ // Stat the filesystem
+ auto filesystem_ext4::stat_vfs(fsmount mnt, std::string_view path, struct statvfs &stat) const noexcept -> int
+ {
+ auto vmnt = std::dynamic_pointer_cast<mount_point_ext4>(mnt);
+ if (!vmnt) {
+ LOG_ERROR("Non ext4 mount point");
+ return -EIO;
+ }
+ ext4_locker _lck(vmnt);
+ ext4_mount_stats estats;
+ auto err = ext4_mount_point_stats(vmnt->mount_path().c_str(), &estats);
+ if (err) {
+ LOG_ERROR("Mount point stats error %i", err);
+ return -err;
+ }
+ std::memset(&stat, 0, sizeof stat);
+ stat.f_bsize = estats.block_size;
+ stat.f_frsize = estats.block_size;
+ stat.f_blocks = estats.blocks_count;
+ stat.f_bfree = estats.free_blocks_count;
+ stat.f_bavail = stat.f_bfree;
+ stat.f_files = estats.inodes_count;
+ stat.f_ffree = estats.free_inodes_count;
+ stat.f_favail = stat.f_ffree;
+ stat.f_flag = vmnt->flags();
+ stat.f_namemax = PATH_MAX;
+ return err;
+ }
+
+ auto filesystem_ext4::open(fsmount mnt, std::string_view path, int flags, int mode) noexcept -> fsfile
+ {
+ auto vmnt = std::dynamic_pointer_cast<mount_point_ext4>(mnt);
+ if (!vmnt) {
+ LOG_ERROR("Non ext4 mount point");
+ return nullptr;
+ }
+ ext4_locker _lck(vmnt);
+ const auto fspath = vmnt->native_path(path);
+ auto filp = std::make_shared<file_handle_ext4>(mnt, fspath, flags);
+ auto err = ext4_fopen2(filp->filp(), fspath.c_str(), flags);
+ filp->error(-err);
+ return filp;
+ }
+
+ auto filesystem_ext4::close(fsfile zfile) noexcept -> int
+ {
+ return -invoke_efs(zfile, ::ext4_fclose);
+ }
+
+ auto filesystem_ext4::write(fsfile zfile, const char *ptr, size_t len) noexcept -> ssize_t
+ {
+ size_t n_written;
+ auto err = invoke_efs(zfile, ::ext4_fwrite, ptr, len, &n_written);
+ return (err) ? (-err) : (n_written);
+ }
+
+ auto filesystem_ext4::read(fsfile zfile, char *ptr, size_t len) noexcept -> ssize_t
+ {
+ size_t n_read;
+ auto err = invoke_efs(zfile, ::ext4_fread, ptr, len, &n_read);
+ return (err) ? (-err) : (n_read);
+ }
+
+ auto filesystem_ext4::seek(fsfile zfile, off_t pos, int dir) noexcept -> off_t
+ {
+
+ auto vfile = std::dynamic_pointer_cast<file_handle_ext4>(zfile);
+ if (!vfile) {
+ LOG_ERROR("Non ext4 filesystem file pointer");
+ return -EBADF;
+ }
+ auto mntp = std::static_pointer_cast<mount_point_ext4>(vfile->mntpoint());
+ if (!mntp) {
+ LOG_ERROR("Non ext4 mount point");
+ return -EBADF;
+ }
+ ext4_locker _lck(mntp);
+ auto err = ext4_fseek(vfile->filp(), pos, dir);
+ if (err) {
+ return -err;
+ }
+ auto rpos = ext4_ftell(vfile->filp());
+ return rpos;
+ }
+
+ auto filesystem_ext4::stat(const char *mount_point, const char *path, struct stat *st, bool ro) noexcept -> int
+ {
+ uint32_t inonum;
+ ext4_inode ino;
+ ext4_sblock *sb;
+ auto err = ext4_raw_inode_fill(path, &inonum, &ino);
+ if (err) {
+ return -err;
+ }
+ err = ext4_get_sblock(mount_point, &sb);
+ if (err) {
+ return -err;
+ }
+ std::memset(st, 0, sizeof(*st));
+ st->st_ino = inonum;
+ const auto btype = ext4_inode_type(sb, &ino);
+ st->st_mode = ext4_inode_get_mode(sb, &ino) | ino_to_st_mode(btype);
+ if (ro) {
+ st->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
+ }
+ // Update file type
+ st->st_nlink = ext4_inode_get_links_cnt(&ino);
+ st->st_uid = ext4_inode_get_uid(&ino);
+ st->st_gid = ext4_inode_get_gid(&ino);
+ st->st_blocks = ext4_inode_get_blocks_count(sb, &ino);
+ st->st_size = ext4_inode_get_size(sb, &ino);
+ st->st_blksize = ext4_sb_get_block_size(sb);
+ st->st_dev = ext4_inode_get_dev(&ino);
+ return err;
+ }
+
+ auto filesystem_ext4::fstat(fsfile zfile, struct stat &st) noexcept -> int
+ {
+ auto vfile = std::dynamic_pointer_cast<file_handle_ext4>(zfile);
+ if (!vfile) {
+ LOG_ERROR("Non ext4 filesystem file pointer");
+ return -EBADF;
+ }
+ auto mntp = std::static_pointer_cast<mount_point_ext4>(vfile->mntpoint());
+ if (!mntp) {
+ LOG_ERROR("Non ext4 mount point");
+ return -EBADF;
+ }
+ const auto path = vfile->open_path();
+ ext4_locker _lck(mntp);
+ return stat(mntp->mount_path().c_str(), vfile->open_path().c_str(), &st, zfile->mntpoint()->is_ro());
+ }
+
+ auto filesystem_ext4::stat(fsmount mnt, std::string_view file, struct stat &st) noexcept -> int
+ {
+ auto mntp = std::static_pointer_cast<mount_point_ext4>(mnt);
+ if (!mntp) {
+ LOG_ERROR("Non ext4 mount point");
+ return -EBADF;
+ }
+ const auto npath = mntp->native_path(file);
+ ext4_locker _lck(mntp);
+ return stat(mntp->mount_path().c_str(), npath.c_str(), &st, mntp->is_ro());
+ }
+
+ auto filesystem_ext4::link(fsmount mnt, std::string_view existing, std::string_view newlink) noexcept -> int
+ {
+ return invoke_efs(mnt, ::ext4_flink, existing, newlink);
+ }
+
+ auto filesystem_ext4::symlink(fsmount mnt, std::string_view existing, std::string_view newlink) noexcept -> int
+ {
+ return invoke_efs(mnt, ::ext4_fsymlink, existing, newlink);
+ }
+
+ auto filesystem_ext4::unlink(fsmount mnt, std::string_view name) noexcept -> int
+ {
+ return invoke_efs(
+ mnt,
+ [](const char *path) {
+ if (ext4_inode_exist(path, EXT4_DE_DIR) == 0) {
+ LOG_WARN("rmdir syscall instead of unlink is recommended for remove directory");
+ return -ext4_dir_rm(path);
+ }
+ else {
+ return -ext4_fremove(path);
+ }
+ },
+ name);
+ }
+
+ auto filesystem_ext4::rmdir(fsmount mnt, std::string_view name) noexcept -> int
+ {
+ return invoke_efs(mnt, ::ext4_dir_rm, name);
+ }
+
+ auto filesystem_ext4::rename(fsmount mnt, std::string_view oldname, std::string_view newname) noexcept -> int
+ {
+ return invoke_efs(mnt, ::ext4_frename, oldname, newname);
+ }
+
+ auto filesystem_ext4::mkdir(fsmount mnt, std::string_view path, int mode) noexcept -> int
+ {
+ return invoke_efs(mnt, ::ext4_dir_mk, path);
+ }
+
+ auto filesystem_ext4::diropen(fsmount mnt, std::string_view path) noexcept -> fsdir
+ {
+ auto vmnt = std::dynamic_pointer_cast<mount_point_ext4>(mnt);
+ if (!vmnt) {
+ LOG_ERROR("Non ext4 mount point");
+ return nullptr;
+ }
+ const auto fspath = vmnt->native_path(path);
+ const auto dirp = std::make_shared<directory_handle_ext4>(mnt, 0);
+ ext4_locker _lck(vmnt);
+ const auto lret = ext4_dir_open(dirp->dirp(), fspath.c_str());
+ dirp->error(-lret);
+ return dirp;
+ }
+
+ auto filesystem_ext4::dirreset(fsdir dirstate) noexcept -> int
+ {
+ return invoke_efs(dirstate, [](auto arg) {
+ ::ext4_dir_entry_rewind(arg);
+ return 0;
+ });
+ }
+
+ auto filesystem_ext4::dirnext(fsdir dirstate, std::string &filename, struct stat &st) -> int
+ {
+ const ext4_direntry *dentry{};
+ const auto err = invoke_efs(dirstate, [&dentry](auto arg) {
+ dentry = ext4_dir_entry_next(arg);
+ return dentry ? 0 : -ENODATA;
+ });
+ if (!err) {
+ std::memset(&st, 0, sizeof(st));
+ st.st_ino = dentry->inode;
+ st.st_mode = ino_to_st_mode(dentry->inode_type);
+ filename = std::string(reinterpret_cast<const char *>(dentry->name), dentry->name_length);
+ }
+ return err;
+ }
+
+ auto filesystem_ext4::dirclose(fsdir dirstate) noexcept -> int
+ {
+ return invoke_efs(dirstate, ::ext4_dir_close);
+ }
+
+ auto filesystem_ext4::isatty(fsfile zfile) noexcept -> int
+ {
+ return 0;
+ }
+
+ auto filesystem_ext4::chmod(fsmount mnt, std::string_view path, mode_t mode) noexcept -> int
+ {
+ return invoke_efs(mnt, ::ext4_mode_set, path, mode);
+ }
+
+ auto filesystem_ext4::fchmod(fsfile zfile, mode_t mode) noexcept -> int
+ {
+ auto vfile = std::dynamic_pointer_cast<file_handle_ext4>(zfile);
+ if (!vfile) {
+ LOG_ERROR("Non ext4 filesystem file pointer");
+ return -EBADF;
+ }
+ return invoke_efs(vfile->mntpoint(), ::ext4_mode_set, vfile->open_path().c_str(), mode);
+ }
+
+ auto filesystem_ext4::ftruncate(fsfile zfile, off_t len) noexcept -> int
+ {
+ return invoke_efs(
+ zfile,
+ [](ext4_file *file, uint64_t length) {
+ int err = ext4_ftruncate(file, length);
+ if (err == ENOTSUP) {
+ // NOTE: Ext4 ftruncate supports only shrinking
+ const size_t zbuf_len = 8192;
+ auto buf = std::make_unique<char[]>(zbuf_len);
+ err = 0;
+ for (size_t n = 0; n < length / zbuf_len; ++n) {
+ err = ext4_fwrite(file, buf.get(), zbuf_len, nullptr);
+ if (err) {
+ err = -err;
+ break;
+ }
+ }
+ if (!err) {
+ const ssize_t remain = length % zbuf_len;
+ if (remain > 0) {
+ err = -ext4_fwrite(file, buf.get(), remain, nullptr);
+ }
+ }
+ }
+ return err;
+ },
+ len);
+ }
+
+ auto filesystem_ext4::fsync(fsfile zfile) noexcept -> int
+ {
+ auto vfile = std::dynamic_pointer_cast<file_handle_ext4>(zfile);
+ if (!vfile) {
+ LOG_ERROR("Non ext4 filesystem file pointer");
+ return -EBADF;
+ }
+ return invoke_efs(vfile->mntpoint(), ::ext4_cache_flush, vfile->mntpoint()->mount_path().c_str());
+ }
+
+} // namespace purefs::fs::drivers
M module-vfs/drivers/src/purefs/fs/filesystem_littlefs.cpp => module-vfs/drivers/src/purefs/fs/filesystem_littlefs.cpp +5 -0
@@ 375,6 375,11 @@ namespace purefs::fs::drivers
return invoke_lfs(mnt, name, ::lfs_remove);
}
+ auto filesystem_littlefs::rmdir(fsmount mnt, std::string_view name) noexcept -> int
+ {
+ return invoke_lfs(mnt, name, ::lfs_remove);
+ }
+
auto filesystem_littlefs::rename(fsmount mnt, std::string_view oldname, std::string_view newname) noexcept -> int
{
auto mntp = std::static_pointer_cast<mount_point_littlefs>(mnt);
M module-vfs/drivers/src/purefs/fs/filesystem_vfat.cpp => module-vfs/drivers/src/purefs/fs/filesystem_vfat.cpp +13 -1
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include <purefs/fs/drivers/filesystem_vfat.hpp>
@@ 379,6 379,18 @@ namespace purefs::fs::drivers
return translate_error(fret);
}
+ auto filesystem_vfat::rmdir(fsmount mnt, std::string_view name) noexcept -> int
+ {
+ auto vmnt = std::dynamic_pointer_cast<mount_point_vfat>(mnt);
+ if (!vmnt) {
+ LOG_ERROR("Non VFAT mount point");
+ return -ENXIO;
+ }
+ const auto fspath = vmnt->native_path(name);
+ const auto fret = f_rmdir(fspath.c_str());
+ return translate_error(fret);
+ }
+
auto filesystem_vfat::rename(fsmount mnt, std::string_view oldname, std::string_view newname) noexcept -> int
{
auto vmnt = std::dynamic_pointer_cast<mount_point_vfat>(mnt);
A module-vfs/drivers/src/purefs/fs/mount_point_ext4.cpp => module-vfs/drivers/src/purefs/fs/mount_point_ext4.cpp +40 -0
@@ 0,0 1,40 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <purefs/fs/drivers/mount_point_ext4.hpp>
+#include <mutex.hpp>
+#include <string>
+
+namespace purefs::fs::drivers
+{
+ namespace
+ {
+ inline auto mount_path_mod(std::string_view path)
+ {
+ std::string ret{path};
+ if (ret.back() != '/') {
+ ret.push_back('/');
+ }
+ return ret;
+ }
+ } // namespace
+ mount_point_ext4::mount_point_ext4(std::shared_ptr<blkdev::internal::disk_handle> diskh,
+ std::string_view path,
+ unsigned flags,
+ std::shared_ptr<filesystem_operations> fs)
+ : mount_point(diskh, mount_path_mod(path), flags, fs), m_root(mount_path_mod(path)),
+ m_lock(std::make_unique<cpp_freertos::MutexRecursive>())
+ {}
+
+ mount_point_ext4::~mount_point_ext4()
+ {}
+ auto mount_point_ext4::lock() noexcept -> void
+ {
+ m_lock->Lock();
+ }
+ auto mount_point_ext4::unlock() noexcept -> void
+ {
+ m_lock->Unlock();
+ }
+
+} // namespace purefs::fs::drivers<
\ No newline at end of file
A module-vfs/drivers/src/thirdparty/lwext4/ext4_bdev.cpp => module-vfs/drivers/src/thirdparty/lwext4/ext4_bdev.cpp +140 -0
@@ 0,0 1,140 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <lwext4/ext4_bdev.hpp>
+#include <ext4_config.h>
+#include <ext4_blockdev.h>
+#include <ext4_errno.h>
+#include <unordered_map>
+#include <log.hpp>
+#include <mutex.hpp>
+#include <cstring>
+#include <purefs/blkdev/disk_manager.hpp>
+
+namespace purefs::fs::drivers::ext4::internal
+{
+ namespace
+ {
+ //! Global structure for single mount
+ struct ext4_config
+ {
+ ::ext4_blockdev bdev;
+ std::unique_ptr<uint8_t[]> buf;
+ ::ext4_blockdev_iface ifc;
+ };
+
+ // Global volumes list
+ std::unordered_map<::ext4_blockdev *, std::unique_ptr<ext4_config>> g_volumes;
+ // Global lock for recursive mutex
+ cpp_freertos::MutexRecursive g_lock;
+
+ namespace io
+ {
+ //! Global io context for the partition
+ struct context
+ {
+ context(std::shared_ptr<blkdev::disk_manager> diskmm, blkdev::disk_fd _disk_h)
+ : disk(diskmm), disk_h(_disk_h)
+ {}
+ const std::weak_ptr<blkdev::disk_manager> disk;
+ const blkdev::disk_fd disk_h;
+ mutable cpp_freertos::MutexRecursive mutex;
+ };
+
+ int write(struct ext4_blockdev *bdev, const void *buf, uint64_t blk_id, uint32_t blk_cnt)
+ {
+ auto ctx = reinterpret_cast<context *>(bdev->bdif->p_user);
+ if (!ctx) {
+ return -EIO;
+ }
+ auto diskmm = ctx->disk.lock();
+ if (!diskmm) {
+ return -EIO;
+ }
+ const auto err = diskmm->write(ctx->disk_h, buf, blk_id, blk_cnt);
+ if (err) {
+ LOG_ERROR("Sector write error errno: %i", err);
+ }
+ return -err;
+ }
+ int read(struct ext4_blockdev *bdev, void *buf, uint64_t blk_id, uint32_t blk_cnt)
+ {
+ auto ctx = reinterpret_cast<context *>(bdev->bdif->p_user);
+ if (!ctx) {
+ return -EIO;
+ }
+ auto diskmm = ctx->disk.lock();
+ if (!diskmm) {
+ return -EIO;
+ }
+ const auto err = diskmm->read(ctx->disk_h, buf, blk_id, blk_cnt);
+ if (err) {
+ LOG_ERROR("Sector write error errno: %i", err);
+ }
+ return -err;
+ }
+
+ int open(struct ext4_blockdev *bdev)
+ {
+ return 0;
+ }
+ int close(struct ext4_blockdev *bdev)
+ {
+ return 0;
+ }
+
+ } // namespace io
+
+ } // namespace
+
+ // Append volume
+ std::pair<ext4_blockdev *, int> append_volume(std::shared_ptr<blkdev::disk_manager> diskmm, blkdev::disk_fd diskh)
+ {
+ const auto sect_size = diskmm->get_info(diskh, blkdev::info_type::sector_size);
+ if (sect_size < 0) {
+ LOG_ERROR("Unable to get sector size %li", long(sect_size));
+ return {nullptr, sect_size};
+ }
+ const auto sect_count = diskmm->get_info(diskh, blkdev::info_type::sector_count);
+ if (sect_count < 0) {
+ LOG_ERROR("Unable to get sector count %li", long(sect_size));
+ return {nullptr, sect_count};
+ }
+
+ // Insert into the container
+ auto cfg = std::make_unique<ext4_config>();
+ std::memset(cfg.get(), 0, sizeof(ext4_config));
+ cfg->ifc.open = io::open;
+ cfg->ifc.bread = io::read;
+ cfg->ifc.bwrite = io::write;
+ cfg->ifc.close = io::close;
+ cfg->buf = std::make_unique<uint8_t[]>(sect_size);
+ cfg->ifc.ph_bbuf = cfg->buf.get();
+ cfg->ifc.ph_bcnt = sect_count;
+ cfg->ifc.ph_bsize = sect_size;
+ cfg->ifc.p_user = new io::context(diskmm, diskh);
+ cfg->bdev.bdif = &cfg->ifc;
+ cfg->bdev.part_offset = 0;
+ cfg->bdev.part_size = uint64_t(sect_size) * sect_count;
+
+ cpp_freertos::LockGuard _lck(g_lock);
+ auto bdev = &cfg->bdev;
+ g_volumes.insert(std::make_pair(&cfg->bdev, std::move(cfg)));
+ return {bdev, {}};
+ }
+
+ // Remove volume
+ int remove_volume(ext4_blockdev *ext4_block)
+ {
+ cpp_freertos::LockGuard _lck(g_lock);
+ auto vol = g_volumes.find(ext4_block);
+ if (vol == std::end(g_volumes)) {
+ LOG_ERROR("Unable to find LFS ");
+ return -ENXIO;
+ }
+ delete reinterpret_cast<io::context *>(vol->second->ifc.p_user);
+ g_volumes.erase(vol);
+ return 0;
+ }
+
+} // namespace purefs::fs::drivers::ext4::internal<
\ No newline at end of file
M module-vfs/include/user/newlib/vfs_io_syscalls.hpp => module-vfs/include/user/newlib/vfs_io_syscalls.hpp +1 -0
@@ 19,6 19,7 @@ namespace vfsn::internal::syscalls
int fstat(int &_errno_, int fd, struct stat *st);
int link(int &_errno_, const char *existing, const char *newLink);
int unlink(int &_errno_, const char *name);
+ int rmdir(int &_errno_, const char *name);
int fcntl(int &_errno_, int fd, int cmd, int arg);
int stat(int &_errno_, const char *file, struct stat *pstat);
int chdir(int &_errno_, const char *path);
M module-vfs/include/user/purefs/fs/filesystem.hpp => module-vfs/include/user/purefs/fs/filesystem.hpp +1 -0
@@ 128,6 128,7 @@ namespace purefs::fs
auto unlink(std::string_view name) noexcept -> int;
auto rename(std::string_view oldname, std::string_view newname) noexcept -> int;
auto mkdir(std::string_view path, int mode) noexcept -> int;
+ auto rmdir(std::string_view path) noexcept -> int;
/** Directory support API */
auto diropen(std::string_view path) noexcept -> fsdir;
M module-vfs/include/user/purefs/fs/filesystem_operations.hpp => module-vfs/include/user/purefs/fs/filesystem_operations.hpp +3 -2
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
@@ 47,7 47,7 @@ namespace purefs::fs
unsigned flags) -> fsmount = 0;
virtual auto mount(fsmount mnt, const void *data) noexcept -> int = 0;
virtual auto umount(fsmount mnt) noexcept -> int = 0;
- virtual auto stat_vfs(fsmount mnt, std::string_view path, statvfs &stat) const noexcept -> int;
+ virtual auto stat_vfs(fsmount mnt, std::string_view path, struct statvfs &stat) const noexcept -> int;
/** Standard file access API */
virtual auto open(fsmount mnt, std::string_view path, int flags, int mode) noexcept -> fsfile = 0;
@@ 60,6 60,7 @@ namespace purefs::fs
virtual auto link(fsmount mnt, std::string_view existing, std::string_view newlink) noexcept -> int;
virtual auto symlink(fsmount mnt, std::string_view existing, std::string_view newlink) noexcept -> int;
virtual auto unlink(fsmount mnt, std::string_view name) noexcept -> int;
+ virtual auto rmdir(fsmount mnt, std::string_view name) noexcept -> int;
virtual auto rename(fsmount mnt, std::string_view oldname, std::string_view newname) noexcept -> int;
virtual auto mkdir(fsmount mnt, std::string_view path, int mode) noexcept -> int;
M module-vfs/src/purefs/fs/filesystem.cpp => module-vfs/src/purefs/fs/filesystem.cpp +1 -3
@@ 18,9 18,7 @@ namespace purefs::fs
namespace
{
constexpr std::pair<short, std::string_view> part_types_to_vfs[] = {
- {0x0b, "vfat"},
- {0x9e, "littlefs"},
- };
+ {0x0b, "vfat"}, {0x9e, "littlefs"}, {0x83, "ext4"}};
}
filesystem::filesystem(std::shared_ptr<blkdev::disk_manager> diskmm)
: m_diskmm(diskmm), m_lock(std::make_unique<cpp_freertos::MutexRecursive>()),
M module-vfs/src/purefs/fs/filesystem_operations.cpp => module-vfs/src/purefs/fs/filesystem_operations.cpp +5 -1
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include <purefs/fs/filesystem_operations.hpp>
#include <purefs/fs/directory_handle.hpp>
@@ 49,6 49,10 @@ namespace purefs::fs
{
return -ENOTSUP;
}
+ auto filesystem_operations::rmdir(fsmount mnt, std::string_view name) noexcept -> int
+ {
+ return -ENOTSUP;
+ }
auto filesystem_operations::rename(fsmount mnt, std::string_view oldname, std::string_view newname) noexcept -> int
{
return -ENOTSUP;
M module-vfs/src/purefs/fs/filesystem_syscalls.cpp => module-vfs/src/purefs/fs/filesystem_syscalls.cpp +9 -0
@@ 31,6 31,15 @@ namespace purefs::fs
return err;
}
+ auto filesystem::rmdir(std::string_view name) noexcept -> int
+ {
+ const auto err = invoke_fops(iaccess::rw, &filesystem_operations::rmdir, name);
+ if (!err) {
+ m_notifier->notify(name, inotify_flags::del);
+ }
+ return err;
+ }
+
auto filesystem::mkdir(std::string_view path, int mode) noexcept -> int
{
const auto err = invoke_fops(iaccess::rw, &filesystem_operations::mkdir, path, mode);
M module-vfs/src/purefs/vfs_subsystem.cpp => module-vfs/src/purefs/vfs_subsystem.cpp +21 -8
@@ 4,6 4,7 @@
#include <purefs/fs/filesystem.hpp>
#include <purefs/fs/drivers/filesystem_vfat.hpp>
#include <purefs/fs/drivers/filesystem_littlefs.hpp>
+#include <purefs/fs/drivers/filesystem_ext4.hpp>
#include <purefs/blkdev/disk_manager.hpp>
#include <purefs/vfs_subsystem.hpp>
#include <purefs/vfs_subsystem_internal.hpp>
@@ 22,6 23,7 @@ namespace purefs::subsystem
constexpr auto default_nvrom_name = "nvrom0";
constexpr auto fat_part_code = 0x0b;
constexpr auto lfs_part_code = 0x9e;
+ constexpr auto linux_part_code = 0x83;
constexpr auto layout_part_count = 3;
constexpr auto boot_part_index = 0;
constexpr auto user_part_index = 2;
@@ 148,6 150,11 @@ namespace purefs::subsystem
LOG_FATAL("Unable to register lfs filesystem with error %i", err);
return {};
}
+ err = fs_core->register_filesystem("ext4", std::make_shared<fs::drivers::filesystem_ext4>());
+ if (err) {
+ LOG_FATAL("Unable to register ext4 filesystem with error %i", err);
+ return {};
+ }
g_disk_mgr = disk_mgr;
g_fs_core = fs_core;
@@ 186,7 193,7 @@ namespace purefs::subsystem
LOG_FATAL("Invalid boot partition type expected code: %i current code: %i", fat_part_code, boot_part.type);
return -EIO;
}
- if (user_part.type != lfs_part_code) {
+ if ((user_part.type != lfs_part_code) && (user_part.type != linux_part_code)) {
LOG_FATAL("Invalid user partition type expected code: %i current code: %i", lfs_part_code, user_part.type);
return -EIO;
}
@@ 200,14 207,20 @@ namespace purefs::subsystem
if (err) {
return err;
}
- const int lfs_block_log2 = read_mbr_lfs_erase_size(disk, default_blkdev_name, user_part.physical_number);
- uint32_t lfs_block_size = 0;
- uint32_t *lfs_block_size_ptr = nullptr;
- if (lfs_block_log2 >= block_size_min_shift && lfs_block_log2 <= block_size_max_shift) {
- lfs_block_size = 1U << lfs_block_log2;
- lfs_block_size_ptr = &lfs_block_size;
+ if (user_part.type == lfs_part_code) {
+ const int lfs_block_log2 = read_mbr_lfs_erase_size(disk, default_blkdev_name, user_part.physical_number);
+ uint32_t lfs_block_size = 0;
+ uint32_t *lfs_block_size_ptr = nullptr;
+ if (lfs_block_log2 >= block_size_min_shift && lfs_block_log2 <= block_size_max_shift) {
+ lfs_block_size = 1U << lfs_block_log2;
+ lfs_block_size_ptr = &lfs_block_size;
+ }
+ err =
+ vfs->mount(user_part.name, purefs::dir::getUserDiskPath().string(), "littlefs", 0, lfs_block_size_ptr);
+ }
+ else {
+ err = vfs->mount(user_part.name, purefs::dir::getUserDiskPath().string(), "ext4");
}
- err = vfs->mount(user_part.name, purefs::dir::getUserDiskPath().string(), "littlefs", 0, lfs_block_size_ptr);
const std::string json_file = (dir::getRootDiskPath() / file::boot_json).string();
const auto boot_dir_name = parse_boot_json_directory(json_file);
const auto user_dir = (dir::getRootDiskPath() / boot_dir_name).string();
M third-party/CMakeLists.txt => third-party/CMakeLists.txt +1 -0
@@ 11,6 11,7 @@ add_subdirectory(klib)
add_subdirectory(libical)
add_subdirectory(libphonenumber)
add_subdirectory(littlefs)
+add_subdirectory(lwext4)
add_subdirectory(magic_enum)
add_subdirectory(microtar)
add_subdirectory(minimp3)
A third-party/lwext4/CMakeLists.txt => third-party/lwext4/CMakeLists.txt +81 -0
@@ 0,0 1,81 @@
+cmake_minimum_required(VERSION 3.13)
+add_library(lwext4 STATIC)
+add_library(lwext4::lwext4 ALIAS lwext4)
+
+include(lwext4_macros.cmake)
+
+target_include_directories(lwext4
+ PUBLIC
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lwext4/include>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
+)
+
+target_compile_definitions(lwext4
+ PRIVATE
+ CONFIG_DEBUG_PRINTF=1
+ CONFIG_DEBUG_ASSERT=0
+ CONFIG_HAVE_OWN_OFLAGS=0
+ CONFIG_HAVE_OWN_ERRNO=0
+ CONFIG_BLOCK_DEV_CACHE_SIZE=256
+)
+target_compile_options(lwext4
+ PRIVATE
+ -Wno-format
+)
+
+target_sources(lwext4
+ PRIVATE
+ lwext4/src/ext4_balloc.c
+ lwext4/src/ext4_bcache.c
+ lwext4/src/ext4_bitmap.c
+ lwext4/src/ext4_blockdev.c
+ lwext4/src/ext4_block_group.c
+ lwext4/src/ext4.c
+ lwext4/src/ext4_crc32.c
+ lwext4/src/ext4_debug.c
+ lwext4/src/ext4_dir.c
+ lwext4/src/ext4_dir_idx.c
+ lwext4/src/ext4_extent.c
+ lwext4/src/ext4_fs.c
+ lwext4/src/ext4_hash.c
+ lwext4/src/ext4_ialloc.c
+ lwext4/src/ext4_inode.c
+ lwext4/src/ext4_journal.c
+ lwext4/src/ext4_mbr.c
+ lwext4/src/ext4_mkfs.c
+ lwext4/src/ext4_super.c
+ lwext4/src/ext4_trans.c
+ lwext4/src/ext4_xattr.c
+ PUBLIC
+ lwext4/include/ext4_balloc.h
+ lwext4/include/ext4_bcache.h
+ lwext4/include/ext4_bitmap.h
+ lwext4/include/ext4_blockdev.h
+ lwext4/include/ext4_block_group.h
+ lwext4/include/ext4_config.h
+ lwext4/include/ext4_crc32.h
+ lwext4/include/ext4_debug.h
+ lwext4/include/ext4_dir.h
+ lwext4/include/ext4_dir_idx.h
+ lwext4/include/ext4_errno.h
+ lwext4/include/ext4_extent.h
+ lwext4/include/ext4_fs.h
+ lwext4/include/ext4.h
+ lwext4/include/ext4_hash.h
+ lwext4/include/ext4_ialloc.h
+ lwext4/include/ext4_inode.h
+ lwext4/include/ext4_journal.h
+ lwext4/include/ext4_mbr.h
+ lwext4/include/ext4_misc.h
+ lwext4/include/ext4_mkfs.h
+ lwext4/include/ext4_oflags.h
+ lwext4/include/ext4_super.h
+ lwext4/include/ext4_trans.h
+ lwext4/include/ext4_types.h
+ lwext4/include/ext4_xattr.h
+ lwext4/include/misc/queue.h
+ lwext4/include/misc/tree.h
+)
+
+lwext4_output_configure()
+
A third-party/lwext4/lwext4 => third-party/lwext4/lwext4 +1 -0
@@ 0,0 1,1 @@
+Subproject commit 2869807352fb7c9c2ab69e8442efa0b2ce404673
A third-party/lwext4/lwext4_macros.cmake => third-party/lwext4/lwext4_macros.cmake +23 -0
@@ 0,0 1,23 @@
+macro(lwext4_output_configure)
+ get_property(
+ definitions
+ TARGET lwext4::lwext4
+ PROPERTY COMPILE_DEFINITIONS
+ )
+ file(WRITE
+ ${CMAKE_CURRENT_BINARY_DIR}/include/generated/ext4_config.h
+ "")
+ foreach(item ${definitions})
+ string(REGEX MATCH "^CONFIG_" match_res ${item})
+ if(match_res)
+ string(REGEX REPLACE "=(.+)$" "" replace_res ${item})
+ string(CONFIGURE
+ "#define ${replace_res} ${CMAKE_MATCH_1}"
+ output_str)
+ file(APPEND
+ ${CMAKE_CURRENT_BINARY_DIR}/include/generated/ext4_config.h
+ "${output_str}\n")
+ endif()
+ endforeach()
+endmacro()
+lwext4_output_configure()<
\ No newline at end of file
M tools/generate_image.sh => tools/generate_image.sh +36 -7
@@ 75,7 75,6 @@ PART3_SIZE=$(($DEVICE_BLK_COUNT - $PART1_SIZE - $PART2_SIZE - $PART1_START))
echo "Remove previous image file"
rm -f $IMAGE_NAME
-
truncate -s $(($DEVICE_BLK_COUNT * $DEVICE_BLK_SIZE)) $IMAGE_NAME
sfdisk $IMAGE_NAME << ==sfdisk
label: dos
@@ 83,8 82,8 @@ label-id: 0x09650eb4
unit: sectors
/dev/sdx1 : start= $PART1_START, size= $PART1_SIZE, type=b, bootable
-/dev/sdx2 : start= $PART2_START, size= $PART2_SIZE, type=9e
-/dev/sdx3 : start= $PART3_START, size= $PART3_SIZE, type=9e
+/dev/sdx2 : start= $PART2_START, size= $PART2_SIZE, type=83
+/dev/sdx3 : start= $PART3_START, size= $PART3_SIZE, type=83
==sfdisk
@@ 142,10 141,40 @@ fi
mcopy -s -i "$PART1" .boot.json ::
mcopy -s -i "$PART1" .boot.json.crc32 ::
-#Littlefs generate image
-echo $(pwd)
-$GENLFS --image=$IMAGE_NAME --block_size=4096 --overwrite --partition_num=2
-$GENLFS --image=$IMAGE_NAME --block_size=32768 --overwrite --partition_num=3 -- user/*
+# ^64bit - 64bit inodes are not supported by the lwext4
+# ^metadata_csum - Metatata checksums has buggy implementation in the lwext4
+
+# Ext4 backup partition used by updater
+mke2fs \
+ -F \
+ -L 'backup' \
+ -N 0 \
+ -E offset=$(($PART2_START*$DEVICE_BLK_SIZE)) \
+ -O ^64bit \
+ -O ^flex_bg \
+ -O ^metadata_csum \
+ -m 0 \
+ -r 1 \
+ -t ext4 \
+ "$IMAGE_NAME" \
+ $((($PART2_SIZE*$DEVICE_BLK_SIZE)/1024)) \
+;
+
+# EXT4 user partition
+mke2fs \
+ -F \
+ -L 'user' \
+ -N 0 \
+ -E offset=$(($PART3_START*$DEVICE_BLK_SIZE)) \
+ -O ^64bit \
+ -O ^flex_bg \
+ -O ^metadata_csum \
+ -d "user" \
+ -m 0 \
+ -r 1 \
+ -t ext4 \
+ "$IMAGE_NAME" \
+;
# back to previous dir
cd -