From 867c76a0f8ae8702598725e71a63626dea8ff88b Mon Sep 17 00:00:00 2001 From: "yuchen.cc" Date: Thu, 14 Dec 2023 19:20:29 +0800 Subject: [PATCH] untar: support pax xattr header remove overlaybd/extfs and use photon/extfs instead. Signed-off-by: yuchen.cc --- CMake/Finde2fs.cmake | 43 + CMake/Findext2fs.cmake | 21 - CMake/Findphoton.cmake | 7 +- CMakeLists.txt | 1 + src/CMakeLists.txt | 5 +- src/overlaybd/CMakeLists.txt | 2 - src/overlaybd/extfs/CMakeLists.txt | 20 - src/overlaybd/extfs/buffer_file.h | 215 ---- src/overlaybd/extfs/extfs.cpp | 1333 ----------------------- src/overlaybd/extfs/extfs.h | 34 - src/overlaybd/extfs/extfs_io.cpp | 222 ---- src/overlaybd/extfs/extfs_utils.h | 482 -------- src/overlaybd/extfs/mkfs.cpp | 143 --- src/overlaybd/extfs/test/CMakeLists.txt | 14 - src/overlaybd/extfs/test/test.cpp | 826 -------------- src/overlaybd/tar/header.cpp | 13 +- src/overlaybd/tar/libtar.cpp | 30 +- src/overlaybd/tar/libtar.h | 20 +- src/overlaybd/tar/test/CMakeLists.txt | 2 +- src/overlaybd/tar/test/test.cpp | 4 +- src/tools/comm_func.cpp | 2 +- src/tools/overlaybd-apply.cpp | 2 +- src/tools/overlaybd-create.cpp | 2 +- src/tools/turboOCI-apply.cpp | 2 +- 24 files changed, 115 insertions(+), 3330 deletions(-) create mode 100644 CMake/Finde2fs.cmake delete mode 100644 CMake/Findext2fs.cmake delete mode 100644 src/overlaybd/extfs/CMakeLists.txt delete mode 100644 src/overlaybd/extfs/buffer_file.h delete mode 100644 src/overlaybd/extfs/extfs.cpp delete mode 100644 src/overlaybd/extfs/extfs.h delete mode 100644 src/overlaybd/extfs/extfs_io.cpp delete mode 100644 src/overlaybd/extfs/extfs_utils.h delete mode 100644 src/overlaybd/extfs/mkfs.cpp delete mode 100644 src/overlaybd/extfs/test/CMakeLists.txt delete mode 100644 src/overlaybd/extfs/test/test.cpp diff --git a/CMake/Finde2fs.cmake b/CMake/Finde2fs.cmake new file mode 100644 index 00000000..9c40cfbe --- /dev/null +++ b/CMake/Finde2fs.cmake @@ -0,0 +1,43 @@ +if(NOT ORIGIN_EXT2FS) + message("Add and build standalone libext2fs") + include(FetchContent) + FetchContent_Declare( + e2fsprogs + GIT_REPOSITORY https://github.com/data-accelerator/e2fsprogs.git + GIT_TAG f8664ddfd662b1664104e0bbd5ac202a6e3b1da6 + ) + FetchContent_GetProperties(e2fsprogs) + + if(NOT TARGET libext2fs_build) + if (NOT e2fsprogs_POPULATED) + FetchContent_Populate(e2fsprogs) + endif() + set(LIBEXT2FS_INSTALL_DIR ${e2fsprogs_SOURCE_DIR}/build/libext2fs CACHE STRING "") + + add_custom_command( + OUTPUT ${LIBEXT2FS_INSTALL_DIR}/lib + WORKING_DIRECTORY ${e2fsprogs_SOURCE_DIR} + COMMAND chmod 755 build.sh && ./build.sh + ) + add_custom_target(libext2fs_build DEPENDS ${LIBEXT2FS_INSTALL_DIR}/lib) + endif() + + set(E2FS_FOUND yes) + set(E2FS_LIBRARY ${LIBEXT2FS_INSTALL_DIR}/lib/libext2fs.so) + set(E2FS_LIBRARIES ${E2FS_LIBRARY}) + set(E2FS_INCLUDE_DIR ${LIBEXT2FS_INSTALL_DIR}/include) + set(E2FS_INCLUDE_DIRS ${E2FS_INCLUDE_DIR}) + + if(NOT TARGET libext2fs) + add_library(libext2fs UNKNOWN IMPORTED) + endif() + add_dependencies(libext2fs libext2fs_build) + +else() + find_path(E2FS_INCLUDE_DIRS ext2fs/ext2fs.h) + find_library(E2FS_LIBRARIES ext2fs) +endif() + +find_package_handle_standard_args(e2fs DEFAULT_MSG E2FS_LIBRARIES E2FS_INCLUDE_DIRS) + +mark_as_advanced(E2FS_INCLUDE_DIRS E2FS_LIBRARIES) diff --git a/CMake/Findext2fs.cmake b/CMake/Findext2fs.cmake deleted file mode 100644 index 8ba7fb52..00000000 --- a/CMake/Findext2fs.cmake +++ /dev/null @@ -1,21 +0,0 @@ -include(FetchContent) -set(FETCHCONTENT_QUIET false) - -FetchContent_Declare( - e2fsprogs - GIT_REPOSITORY https://github.com/data-accelerator/e2fsprogs.git - GIT_TAG f8664ddfd662b1664104e0bbd5ac202a6e3b1da6 -) - -FetchContent_MakeAvailable(e2fsprogs) - -set(LIBEXT2FS_INSTALL_DIR ${e2fsprogs_SOURCE_DIR}/build/libext2fs) -add_custom_command( - OUTPUT ${LIBEXT2FS_INSTALL_DIR}/lib - WORKING_DIRECTORY ${e2fsprogs_SOURCE_DIR} - COMMAND chmod 755 build.sh && ./build.sh -) -add_custom_target(libext2fs ALL DEPENDS ${LIBEXT2FS_INSTALL_DIR}/lib) - -set(EXT2FS_INCLUDE_DIR ${LIBEXT2FS_INSTALL_DIR}/include) -set(EXT2FS_LIBRARY ${LIBEXT2FS_INSTALL_DIR}/lib/libext2fs.so) diff --git a/CMake/Findphoton.cmake b/CMake/Findphoton.cmake index 87ed5730..02927187 100644 --- a/CMake/Findphoton.cmake +++ b/CMake/Findphoton.cmake @@ -1,10 +1,11 @@ include(FetchContent) set(FETCHCONTENT_QUIET false) +set(PHOTON_ENABLE_EXTFS ON) FetchContent_Declare( photon GIT_REPOSITORY https://github.com/alibaba/PhotonLibOS.git - GIT_TAG v0.6.13 + GIT_TAG v0.6.14 ) if(BUILD_TESTING) @@ -21,4 +22,8 @@ if (BUILD_CURL_FROM_SOURCE) add_dependencies(photon_obj CURL::libcurl OpenSSL::SSL OpenSSL::Crypto) endif() +if(NOT ORIGIN_EXT2FS) + add_dependencies(photon_obj libext2fs) +endif() + set(PHOTON_INCLUDE_DIR ${photon_SOURCE_DIR}/include/) diff --git a/CMakeLists.txt b/CMakeLists.txt index 86b30a8b..223e274b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,7 @@ set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED on) set(ENABLE_MIMIC_VDSO off) option(BUILD_CURL_FROM_SOURCE "Compile static libcurl" off) +option(ORIGIN_EXT2FS "Use original libext2fs" off) find_package(photon REQUIRED) find_package(tcmu REQUIRED) find_package(yamlcpp) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9c79d142..c30dc72b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -56,8 +56,11 @@ install(TARGETS overlaybd-tcmu DESTINATION /opt/overlaybd/bin) install(FILES example_config/overlaybd-tcmu.service DESTINATION /opt/overlaybd/) install(FILES example_config/overlaybd.json DESTINATION /etc/overlaybd/) install(FILES example_config/cred.json DESTINATION /opt/overlaybd/) +if (NOT ORIGIN_EXT2FS) + install(DIRECTORY ${LIBEXT2FS_INSTALL_DIR}/lib DESTINATION /opt/overlaybd/ USE_SOURCE_PERMISSIONS) +endif() add_subdirectory(tools) if (BUILD_TESTING) add_subdirectory(test) -endif () \ No newline at end of file +endif () diff --git a/src/overlaybd/CMakeLists.txt b/src/overlaybd/CMakeLists.txt index d700f808..fd57ee26 100644 --- a/src/overlaybd/CMakeLists.txt +++ b/src/overlaybd/CMakeLists.txt @@ -3,7 +3,6 @@ add_subdirectory(lsmt) add_subdirectory(zfile) add_subdirectory(cache) add_subdirectory(tar) -add_subdirectory(extfs) add_subdirectory(gzip) add_subdirectory(gzindex) add_subdirectory(stream_convertor) @@ -19,7 +18,6 @@ target_link_libraries(overlaybd_lib INTERFACE zfile_lib cache_lib tar_lib - extfs_lib gzip_lib gzindex_lib ) diff --git a/src/overlaybd/extfs/CMakeLists.txt b/src/overlaybd/extfs/CMakeLists.txt deleted file mode 100644 index 1ce2378f..00000000 --- a/src/overlaybd/extfs/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -file(GLOB SOURCE_EXTFS "*.cpp") -add_library(extfs_lib STATIC ${SOURCE_EXTFS}) - -if(NOT ORIGIN_EXT2FS) - find_package(ext2fs REQUIRED) - add_dependencies(extfs_lib libext2fs) - target_include_directories(extfs_lib PUBLIC ${EXT2FS_INCLUDE_DIR}) - set(LIB_EXT2FS ${EXT2FS_LIBRARY}) - - install(DIRECTORY ${LIBEXT2FS_INSTALL_DIR}/lib DESTINATION /opt/overlaybd/ USE_SOURCE_PERMISSIONS) -else() - set(LIB_EXT2FS ext2fs) -endif() - -target_include_directories(extfs_lib PUBLIC ${PHOTON_INCLUDE_DIR}) -target_link_libraries(extfs_lib photon_static ${LIB_EXT2FS}) - -if(BUILD_TESTING) - add_subdirectory(test) -endif() diff --git a/src/overlaybd/extfs/buffer_file.h b/src/overlaybd/extfs/buffer_file.h deleted file mode 100644 index d620d423..00000000 --- a/src/overlaybd/extfs/buffer_file.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - Copyright The Overlaybd Authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include - -photon::fs::IFile *new_buffer_file(photon::fs::IFile *file); - -class BufferFile : public photon::fs::ForwardFile { -public: - BufferFile(photon::fs::IFile *file, uint32_t buffer_size = 8 << 20, uint32_t _block_size = 128 << 10) - : photon::fs::ForwardFile(file), block_size(_block_size) { - if (buffer_size % block_size != 0 \ - || block_size % EXT_BLOCK_SIZE != 0 \ - || lowbit(block_size) != block_size) { - LOG_ERROR("buffer_size must be a multiple of block_size, " \ - "block_size must be a multiple of EXT_IO_BLOCK_SIZE, " \ - "block_size must be a power of 2"); - return; - } - block_size_bit = __builtin_ffs(block_size) - 1; - block_size_mod = block_size - 1; - block_counts = DIV(buffer_size); - buffer = (char*) malloc(buffer_size); - head = tail = nullptr; - } - ~BufferFile() { - close(); - } - virtual int close() override { - for (auto &it : mp) { - int ret = flush_node(it.second); - if (ret) { - return -1; - } - delete it.second; - } - free(buffer); - LOG_INFO("buffer file flush and close, cache hit: `, cache miss: `, cache hit rate: `%", cache_hit, cache_miss, cache_hit * 100.0 / (cache_hit + cache_miss)); - LOG_INFO("mem_read: `, mem_write: `, disk_read: `, disk_write: `", mem_read, mem_write, disk_read, disk_write); - return 0; - } - virtual ssize_t pread(void *buf, size_t count, off_t offset) override { - if (count != EXT_BLOCK_SIZE || (offset & EXT_BLOCK_SIZE_MOD)) { - disk_read += count; - return m_file->pread(buf, count, offset); - } - ListNode *x = get_buffer_block(DIV(offset)); - if (!x) { - LOG_ERROR_RETURN(0, -1, "BufferFile: failed to pread from file to buffer"); - } - off_t buffer_offset = pos(x->buffer_block_id, MOD(offset)); - mem_read += count; - return std::copy_n(buffer + buffer_offset, count, (char*) buf) - (char*) buf; - } - virtual ssize_t pwrite(const void *buf, size_t count, off_t offset) override { - if (count != EXT_BLOCK_SIZE || (offset & EXT_BLOCK_SIZE_MOD)) { - disk_write += count; - return m_file->pwrite(buf, count, offset); - } - ListNode *x = get_buffer_block(DIV(offset)); - if (!x) { - LOG_ERROR_RETURN(0, -1, "BufferFile: failed to pwrite from file to buffer"); - } - x->is_dif = true; - off_t buffer_offset = pos(x->buffer_block_id, MOD(offset)); - mem_write += count; - return std::copy_n((char*) buf, count, buffer + buffer_offset) - (buffer + buffer_offset); - } - virtual int fdatasync() override { - auto write = disk_write; - for (auto &it : mp) { - int ret = flush_node(it.second); - if (ret) { - return -1; - } - } - write = disk_write - write; - LOG_DEBUG("flush data: `", write); - return 0; - } - -private: - size_t cache_hit = 0; - size_t cache_miss = 0; - uint64_t disk_read = 0; - uint64_t disk_write = 0; - uint64_t mem_read = 0; - uint64_t mem_write = 0; - static const uint32_t EXT_BLOCK_SIZE = 4 << 10; // ext I/O block size - - uint32_t block_size; // cache block size - size_t block_counts; - char *buffer; - - // LRU index data struct - struct ListNode { - bool is_dif; - ListNode* prv; - ListNode* nxt; - off_t block_id; - off_t buffer_block_id; - ListNode(): prv(nullptr), nxt(nullptr), block_id(0), buffer_block_id(0), is_dif(false) {}; - }; - std::map mp; - ListNode *head, *tail; - - ListNode *get_buffer_block(off_t block_id) { - ListNode *x; - if (mp.count(block_id)) { - x = mp[block_id]; - pop_node(x); - cache_hit++; - } else { - cache_miss++; - // cache miss - assert(mp.size() <= block_counts); - if (mp.size() != block_counts) { - x = new ListNode(); - x->block_id = block_id; - x->buffer_block_id = mp.size(); - } else { - x = tail; - int ret = flush_node(tail); - if (ret) { - return nullptr; - } - pop_node(tail); - mp.erase(x->block_id); - x->block_id = block_id; - } - disk_read += block_size; - auto ret = m_file->pread(buffer + pos(x->buffer_block_id, 0), block_size, pos(x->block_id, 0)); - if (ret != block_size) { - return nullptr; - } - mp[block_id] = x; - } - push_node(x); - return x; - } - - inline off_t pos(off_t block_id, off_t offset) { - return MULT(block_id) + offset; - } - void pop_node(ListNode *x) { - if (x == head) head = head->nxt; - if (x == tail) tail = tail->prv; - ListNode *prv = x->prv; - ListNode *nxt = x->nxt; - if (prv) prv->nxt = nxt; - if (nxt) nxt->prv = prv; - x->prv = nullptr; - x->nxt = nullptr; - } - void push_node(ListNode *x) { - if (head) head->prv = x; - x->nxt = head; - head = x; - if (!tail) tail = x; - } - int flush_node(ListNode *x) { - if (!(x->is_dif)) return 0; - - disk_write += block_size; - ssize_t ret = m_file->pwrite(buffer + pos(x->buffer_block_id, 0), block_size, pos(x->block_id, 0)); - if (ret != block_size) { - LOG_ERRNO_RETURN(0, -1, "BufferFile: failed to flush node"); - } - x->is_dif = false; - return 0; - } - - // bit calc - static const uint32_t EXT_BLOCK_SIZE_MOD = EXT_BLOCK_SIZE - 1; - uint16_t block_size_bit; // __builtin_ffs(block_size) - uint32_t block_size_mod; // block_size-1 - int64_t lowbit(int64_t x) { - return x & (-x); - } - inline off_t DIV(off_t x) { - return x >> block_size_bit; - } - inline off_t MOD(off_t x) { - return x & block_size_mod; - } - inline off_t MULT(off_t x) { - return x << block_size_bit; - } -}; - -photon::fs::IFile *new_buffer_file(photon::fs::IFile *file) { - photon::fs::IFile *buffer_file = new BufferFile(file); - return buffer_file; -} diff --git a/src/overlaybd/extfs/extfs.cpp b/src/overlaybd/extfs/extfs.cpp deleted file mode 100644 index a197fcb9..00000000 --- a/src/overlaybd/extfs/extfs.cpp +++ /dev/null @@ -1,1333 +0,0 @@ -/* - Copyright The Overlaybd Authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "extfs.h" -#include "extfs_utils.h" -#include "buffer_file.h" - -// add for debug -static uint64_t total_read_cnt = 0; -static uint64_t total_write_cnt = 0; - -ext2_filsys do_ext2fs_open(io_manager extfs_manager) { - ext2_filsys fs; - errcode_t ret = ext2fs_open( - "extfs", - EXT2_FLAG_RW, // flags - 0, // superblock - DEFAULT_BLOCK_SIZE, // block_size - extfs_manager, // io manager - &fs // ret_fs - ); - if (ret) { - errno = -parse_extfs_error(nullptr, 0, ret); - LOG_ERRNO_RETURN(0, nullptr, "failed ext2fs_open"); - } - ret = ext2fs_read_bitmaps(fs); - if (ret) { - errno = -parse_extfs_error(fs, 0, ret); - ext2fs_close(fs); - LOG_ERRNO_RETURN(0, nullptr, "failed ext2fs_read_bitmaps"); - } - LOG_INFO("ext2fs opened"); - return fs; -} - -ext2_file_t do_ext2fs_open_file(ext2_filsys fs, const char *path, unsigned int flags, unsigned int mode) { - DEFER(LOG_DEBUG("open_file" , VALUE(path))); - ext2_ino_t ino = string_to_inode(fs, path, !(flags & O_NOFOLLOW)); - errcode_t ret; - if (ino == 0) { - if (!(flags & O_CREAT)) { - errno = ENOENT; - return nullptr; - } - ret = create_file(fs, path, mode, &ino); - if (ret) { - errno = -ret; - LOG_ERROR("failed to create file ", VALUE(ret), VALUE(path)); - return nullptr; - } - } else if (flags & O_EXCL) { - errno = EEXIST; - return nullptr; - } - if ((flags & O_DIRECTORY) && ext2fs_check_directory(fs, ino)) { - errno = ENOTDIR; - return nullptr; - } - ext2_file_t file; - ret = ext2fs_file_open(fs, ino, extfs_open_flags(flags), &file); - if (ret) { - errno = -parse_extfs_error(fs, ino, ret); - return nullptr; - } - if (flags & O_TRUNC) { - ret = ext2fs_file_set_size2(file, 0); - if (ret) { - errno = -parse_extfs_error(fs, ino, ret); - return nullptr; - } - } - return file; -} - -int do_ext2fs_file_close(ext2_file_t file) { - errcode_t ret = ext2fs_file_close(file); - if (ret) return parse_extfs_error(nullptr, 0, ret); - return 0; -} - -long do_ext2fs_read( - ext2_file_t file, - int flags, - char *buffer, - size_t count, // requested count - off_t offset // offset in file, -1 for current offset -) { - errcode_t ret = 0; - if ((flags & O_WRONLY) != 0) { - // Don't try to read write only files. - return -EBADF; - } - if (offset != -1) { - ret = ext2fs_file_llseek(file, offset, EXT2_SEEK_SET, nullptr); - if (ret) return parse_extfs_error(nullptr, 0, ret); - } - unsigned int got; - LOG_DEBUG("read ", VALUE(offset), VALUE(count)); - ret = ext2fs_file_read(file, buffer, count, &got); - if (ret) return parse_extfs_error(nullptr, 0, ret); - total_read_cnt += got; - if ((flags & O_NOATIME) == 0) { - ret = update_xtime(file, EXT_ATIME); - if (ret) return ret; - } - return got; -} - -long do_ext2fs_write( - ext2_file_t file, - int flags, - const char *buffer, - size_t count, // requested count - off_t offset // offset in file, -1 for current offset -) { - if ((flags & (O_WRONLY | O_RDWR)) == 0) { - // Don't try to write to readonly files. - return -EBADF; - } - errcode_t ret = 0; - if ((flags & O_APPEND) != 0) { - // append mode: seek to the end before each write - ret = ext2fs_file_llseek(file, 0, EXT2_SEEK_END, nullptr); - } else if (offset != -1) { - ret = ext2fs_file_llseek(file, offset, EXT2_SEEK_SET, nullptr); - } - - if (ret) return parse_extfs_error(nullptr, 0, ret); - unsigned int written; - LOG_DEBUG("write ", VALUE(offset), VALUE(count)); - ret = ext2fs_file_write(file, buffer, count, &written); - if (ret) return parse_extfs_error(nullptr, 0, ret); - total_write_cnt += written; - // update_mtime - ret = update_xtime(file, EXT_CTIME | EXT_MTIME); - if (ret) return ret; - - ret = ext2fs_file_flush(file); - if (ret) { - return parse_extfs_error(nullptr, 0, ret); - } - - return written; -} - -int do_ext2fs_chmod(ext2_filsys fs, ext2_ino_t ino, int mode) { - struct ext2_inode inode; - memset(&inode, 0, sizeof(inode)); - - errcode_t ret = ext2fs_read_inode(fs, ino, &inode); - if (ret) return parse_extfs_error(fs, ino, ret); - - // keep only fmt (file or directory) - inode.i_mode &= LINUX_S_IFMT; - // apply new mode - inode.i_mode |= (mode & ~LINUX_S_IFMT); - increment_version(&inode); - - ret = ext2fs_write_inode(fs, ino, &inode); - if (ret) return parse_extfs_error(fs, ino, ret); - - return 0; -} - -int do_ext2fs_chmod(ext2_filsys fs, const char *path, int mode) { - LOG_DEBUG(VALUE(path)); - ext2_ino_t ino = string_to_inode(fs, path, 0); - if (!ino) return -ENOENT; - - return do_ext2fs_chmod(fs, ino, mode); -} - -int do_ext2fs_chown(ext2_filsys fs, ext2_ino_t ino, int uid, int gid) { - struct ext2_inode inode; - memset(&inode, 0, sizeof(inode)); - - // TODO handle 32 bit {u,g}ids - errcode_t ret = ext2fs_read_inode(fs, ino, &inode); - if (ret) return parse_extfs_error(fs, ino, ret); - // keep only the lower 16 bits - inode.i_uid = uid & 0xFFFF; - ext2fs_set_i_uid_high(inode, uid >> 16); - inode.i_gid = gid & 0xFFFF; - ext2fs_set_i_gid_high(inode, gid >> 16); - increment_version(&inode); - - ret = ext2fs_write_inode(fs, ino, &inode); - if (ret) return parse_extfs_error(fs, ino, ret); - - return 0; -} - -int do_ext2fs_chown(ext2_filsys fs, const char *path, int uid, int gid, int follow) { - LOG_DEBUG(VALUE(path)); - ext2_ino_t ino = string_to_inode(fs, path, follow); - if (!ino) return -ENOENT; - - return do_ext2fs_chown(fs, ino, uid, gid); -} - -int do_ext2fs_utimes(ext2_filsys fs, ext2_ino_t ino, const struct timeval tv[2]) { - struct ext2_inode inode; - memset(&inode, 0, sizeof(inode)); - - errcode_t ret = ext2fs_read_inode(fs, ino, &inode); - if (ret) return parse_extfs_error(fs, ino, ret); - - inode.i_atime = tv[0].tv_sec; - inode.i_mtime = tv[1].tv_sec; - inode.i_ctime = tv[1].tv_sec; - increment_version(&inode); - - ret = ext2fs_write_inode(fs, ino, &inode); - if (ret) return parse_extfs_error(fs, ino, ret); - - return 0; -} - -int do_ext2fs_utimes(ext2_filsys fs, const char *path, const struct timeval tv[2], int follow) { - LOG_DEBUG(VALUE(path)); - ext2_ino_t ino = string_to_inode(fs, path, follow); - if (!ino) return -ENOENT; - - return do_ext2fs_utimes(fs, ino, tv); -} - -int do_ext2fs_unlink(ext2_filsys fs, const char *path) { - ext2_ino_t ino; - errcode_t ret = 0; - - DEFER(LOG_DEBUG("unlink ", VALUE(path), VALUE(ino), VALUE(ret))); - ino = string_to_inode(fs, path, 0, true); - if (ino == 0) { - ret = ENOENT; - return -ENOENT; - } - - if (ext2fs_check_directory(fs, ino) == 0) { - ret = EISDIR; - return -EISDIR; - } - - ret = unlink_file_by_name(fs, path); - if (ret) return ret; - - ret = remove_inode(fs, ino); - if (ret) return ret; - - return 0; -} - -int do_ext2fs_mkdir(ext2_filsys fs, const char *path, int mode) { - ext2_ino_t parent, ino; - errcode_t ret = 0; - - DEFER(LOG_DEBUG("mkdir ", VALUE(path), VALUE(parent), VALUE(ino), VALUE(ret))); - ino = string_to_inode(fs, path, 0); - if (ino) { - ret = EEXIST; - return -EEXIST; - } - parent = get_parent_dir_ino(fs, path); - if (parent == 0) { - ret = ENOTDIR; - return -ENOTDIR; - } - char *filename = get_filename(path); - if (filename == nullptr) { - // This should never happen. - ret = EISDIR; - return -EISDIR; - } - - ret = ext2fs_new_inode(fs, parent, LINUX_S_IFDIR, 0, &ino); - if (ret) return parse_extfs_error(fs, 0, ret); - ret = ext2fs_mkdir(fs, parent, ino, filename); - if (ret == EXT2_ET_DIR_NO_SPACE) { - ret = ext2fs_expand_dir(fs, parent); - if (ret) return parse_extfs_error(fs, 0, ret); - - ret = ext2fs_mkdir(fs, parent, ino, filename); - } - if (ret) return parse_extfs_error(fs, 0, ret); - - struct ext2_inode_large inode; - memset(&inode, 0, sizeof(inode)); - ret = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, sizeof(inode)); - if (ret) return parse_extfs_error(fs, 0, ret); - inode.i_mode = (mode & ~LINUX_S_IFMT) | LINUX_S_IFDIR; - ret = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, sizeof(inode)); - if (ret) return parse_extfs_error(fs, 0, ret); - - return 0; -} - -int do_ext2fs_rmdir(ext2_filsys fs, const char *path) { - ext2_ino_t ino; - errcode_t ret = 0; - struct rd_struct rds; - - DEFER(LOG_DEBUG("rmdir ", VALUE(path), VALUE(ino), VALUE(ret))); - ino = string_to_inode(fs, path, 0, true); - if (ino == 0) { - ret = ENOENT; - return -ENOENT; - } - - rds.parent = 0; - rds.empty = 1; - - ret = ext2fs_dir_iterate2(fs, ino, 0, 0, rmdir_proc, &rds); - if (ret) return parse_extfs_error(fs, ino, ret); - - if (rds.empty == 0) { - ret = ENOTEMPTY; - return -ENOTEMPTY; - } - - ret = unlink_file_by_name(fs, path); - if (ret) return ret; - /* Directories have to be "removed" twice. */ - ret = remove_inode(fs, ino); - if (ret) return ret; - ret = remove_inode(fs, ino); - if (ret) return ret; - - if (rds.parent) { - struct ext2_inode_large inode; - memset(&inode, 0, sizeof(inode)); - ret = ext2fs_read_inode_full(fs, rds.parent, (struct ext2_inode *)&inode, sizeof(inode)); - if (ret) return parse_extfs_error(fs, rds.parent, ret); - - if (inode.i_links_count > 1) - inode.i_links_count--; - // update_mtime - ret = update_xtime(fs, rds.parent, (struct ext2_inode *)&inode, EXT_CTIME | EXT_MTIME); - if (ret) return ret; - ret = ext2fs_write_inode_full(fs, rds.parent, (struct ext2_inode *)&inode, sizeof(inode)); - if (ret) return parse_extfs_error(fs, rds.parent, ret); - } - - return 0; -} - -int do_ext2fs_rename(ext2_filsys fs, const char *from, const char *to) { - errcode_t ret = 0; - ext2_ino_t from_ino, to_ino, to_dir_ino, from_dir_ino; - struct ext2_inode inode; - struct update_dotdot ud; - - DEFER(LOG_DEBUG("rename ", VALUE(from), VALUE(to), VALUE(from_ino), VALUE(to_ino), VALUE(ret))); - - from_ino = string_to_inode(fs, from, 0, true); - if (from_ino == 0) { - ret = ENOENT; - return -ENOENT; - } - to_ino = string_to_inode(fs, to, 0); - if (to_ino == 0 && errno != ENOENT) { - ret = errno; - return -errno; - } - - /* Already the same file? */ - if (to_ino != 0 && to_ino == from_ino) - return 0; - - /* Find parent dir of the source and check write access */ - from_dir_ino = get_parent_dir_ino(fs, from); - if (from_dir_ino == 0) { - ret = ENOTDIR; - return -ENOTDIR; - } - - /* Find parent dir of the destination and check write access */ - to_dir_ino = get_parent_dir_ino(fs, to); - if (to_dir_ino == 0) { - ret = ENOTDIR; - return -ENOTDIR; - } - char *filename = get_filename(to); - if (filename == nullptr) { - ret = EISDIR; - return -EISDIR; - } - - /* If the target exists, unlink it first */ - if (to_ino != 0) { - ret = ext2fs_read_inode(fs, to_ino, &inode); - if (ret) return parse_extfs_error(fs, to_ino, ret); - - LOG_DEBUG("unlinking ` ino=`", LINUX_S_ISDIR(inode.i_mode) ? "dir" : "file", to_ino); - if (LINUX_S_ISDIR(inode.i_mode)) - ret = do_ext2fs_rmdir(fs, to); - else - ret = do_ext2fs_unlink(fs, to); - if (ret) return ret; - } - - /* Get ready to do the move */ - ret = ext2fs_read_inode(fs, from_ino, &inode); - if (ret) return parse_extfs_error(fs, from_ino, ret); - - /* Link in the new file */ - LOG_DEBUG("linking ino=`/path=` to dir=`", from_ino, filename, to_dir_ino); - ret = ext2fs_link(fs, to_dir_ino, filename, from_ino, ext2_file_type(inode.i_mode)); - if (ret == EXT2_ET_DIR_NO_SPACE) { - ret = ext2fs_expand_dir(fs, to_dir_ino); - if (ret) return parse_extfs_error(fs, to_dir_ino, ret); - - ret = ext2fs_link(fs, to_dir_ino, filename, from_ino, ext2_file_type(inode.i_mode)); - } - if (ret) return parse_extfs_error(fs, to_dir_ino, ret); - - /* Update '..' pointer if dir */ - ret = ext2fs_read_inode(fs, from_ino, &inode); - if (ret) return parse_extfs_error(fs, from_ino, ret); - - if (LINUX_S_ISDIR(inode.i_mode)) { - ud.new_dotdot = to_dir_ino; - LOG_DEBUG("updating .. entry for dir=`", to_dir_ino); - ret = ext2fs_dir_iterate2(fs, from_ino, 0, nullptr, update_dotdot_helper, &ud); - if (ret) return parse_extfs_error(fs, from_ino, ret); - - /* Decrease from_dir_ino's links_count */ - LOG_DEBUG("moving linkcount from dir=` to dir=`", from_dir_ino, to_dir_ino); - ret = ext2fs_read_inode(fs, from_dir_ino, &inode); - if (ret) return parse_extfs_error(fs, from_dir_ino, ret); - inode.i_links_count--; - ret = ext2fs_write_inode(fs, from_dir_ino, &inode); - if (ret) return parse_extfs_error(fs, from_dir_ino, ret); - - /* Increase to_dir_ino's links_count */ - ret = ext2fs_read_inode(fs, to_dir_ino, &inode); - if (ret) return parse_extfs_error(fs, to_dir_ino, ret); - inode.i_links_count++; - ret = ext2fs_write_inode(fs, to_dir_ino, &inode); - if (ret) return parse_extfs_error(fs, to_dir_ino, ret); - } - - /* Update timestamps */ - // update_ctime - ret = update_xtime(fs, from_ino, nullptr, EXT_CTIME); - if (ret) return ret; - // update_mtime - ret = update_xtime(fs, to_dir_ino, nullptr, EXT_CTIME | EXT_MTIME); - if (ret) return ret; - - /* Remove the old file */ - ret = unlink_file_by_name(fs, from); - if (ret) return ret; - - /* Flush the whole mess out */ - ret = ext2fs_flush2(fs, 0); - if (ret) return parse_extfs_error(fs, 0, ret); - - return 0; -} - -int do_ext2fs_link(ext2_filsys fs, const char *src, const char *dest) { - errcode_t ret = 0; - ext2_ino_t parent, ino; - - DEFER(LOG_DEBUG("link ", VALUE(src), VALUE(dest), VALUE(parent), VALUE(ino), VALUE(ret))); - - ino = string_to_inode(fs, dest, 0); - if (ino) { - ret = EEXIST; - return -EEXIST; - } - parent = get_parent_dir_ino(fs, dest); - if (parent == 0) { - ret = ENOTDIR; - return -ENOTDIR; - } - char *filename = get_filename(dest); - if (filename == nullptr) { - ret = EISDIR; - return -EISDIR; - } - ino = string_to_inode(fs, src, 0); - if (ino == 0) { - ret = ENOENT; - return -ENOENT; - } - - struct ext2_inode_large inode; - memset(&inode, 0, sizeof(inode)); - ret = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, sizeof(inode)); - if (ret) return parse_extfs_error(fs, ino, ret); - - inode.i_links_count++; - // update_ctime - ret = update_xtime(fs, ino, (struct ext2_inode *)&inode, EXT_CTIME); - if (ret) return ret; - - ret = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, sizeof(inode)); - if (ret) return parse_extfs_error(fs, ino, ret); - - ret = ext2fs_link(fs, parent, filename, ino, ext2_file_type(inode.i_mode)); - if (ret == EXT2_ET_DIR_NO_SPACE) { - ret = ext2fs_expand_dir(fs, parent); - if (ret) return parse_extfs_error(fs, parent, ret); - - ret = ext2fs_link(fs, parent, filename, ino, ext2_file_type(inode.i_mode)); - } - if (ret) return parse_extfs_error(fs, parent, ret); - - // update_mtime - ret = update_xtime(fs, parent, nullptr, EXT_CTIME | EXT_MTIME); - if (ret) return ret; - - return 0; -} - -int do_ext2fs_symlink(ext2_filsys fs, const char *src, const char *dest) { - ext2_ino_t parent, ino; - errcode_t ret = 0; - - DEFER(LOG_DEBUG("symlink ", VALUE(src), VALUE(dest), VALUE(parent), VALUE(ino), VALUE(ret))); - - ino = string_to_inode(fs, dest, 0); - if (ino) { - ret = EEXIST; - return -EEXIST; - } - parent = get_parent_dir_ino(fs, dest); - if (parent == 0) { - ret = ENOTDIR; - return -ENOTDIR; - } - char *filename = get_filename(dest); - if (filename == nullptr) { - ret = EISDIR; - return -EISDIR; - } - - /* Create symlink */ - ret = ext2fs_symlink(fs, parent, 0, filename, src); - if (ret == EXT2_ET_DIR_NO_SPACE) { - ret = ext2fs_expand_dir(fs, parent); - if (ret) return parse_extfs_error(fs, parent, ret); - - ret = ext2fs_symlink(fs, parent, 0, filename, src); - } - if (ret) return parse_extfs_error(fs, parent, ret); - - /* Update parent dir's mtime */ - ret = update_xtime(fs, parent, nullptr, EXT_CTIME | EXT_MTIME); - if (ret) return ret; - - /* Still have to update the uid/gid of the symlink */ - ino = string_to_inode(fs, dest, 0); - if (ino == 0) { - ret = ENOTDIR; - return -ENOTDIR; - } - - struct ext2_inode_large inode; - memset(&inode, 0, sizeof(inode)); - ret = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, sizeof(inode)); - if (ret) return parse_extfs_error(fs, ino, ret); - - ret = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, sizeof(inode)); - if (ret) return parse_extfs_error(fs, ino, ret); - - return 0; -} - -int do_ext2fs_mknod(ext2_filsys fs, const char *path, unsigned int st_mode, unsigned int st_rdev) { - ext2_ino_t parent, ino; - errcode_t ret = 0; - unsigned long devmajor, devminor; - int filetype; - - DEFER(LOG_DEBUG("mknod ", VALUE(path), VALUE(parent), VALUE(ino), VALUE(ret))); - ino = string_to_inode(fs, path, 0); - if (ino) { - ret = EEXIST; - return -EEXIST; - } - - parent = get_parent_dir_ino(fs, path); - if (parent == 0) { - ret = ENOTDIR; - return -ENOTDIR; - } - - char *filename = get_filename(path); - if (filename == nullptr) { - ret = EISDIR; - return -EISDIR; - } - - switch (st_mode & S_IFMT) { - case S_IFCHR: - filetype = EXT2_FT_CHRDEV; - break; - case S_IFBLK: - filetype = EXT2_FT_BLKDEV; - break; - case S_IFIFO: - filetype = EXT2_FT_FIFO; - break; -#ifndef _WIN32 - case S_IFSOCK: - filetype = EXT2_FT_SOCK; - break; -#endif - default: - return EXT2_ET_INVALID_ARGUMENT; - } - - ret = ext2fs_new_inode(fs, parent, 010755, 0, &ino); - if (ret) return parse_extfs_error(fs, 0, ret); - - ret = ext2fs_link(fs, parent, filename, ino, filetype); - if (ret == EXT2_ET_DIR_NO_SPACE) { - ret = ext2fs_expand_dir(fs, parent); - if (ret) return parse_extfs_error(fs, parent, ret); - - ret = ext2fs_link(fs, parent, filename, ino, filetype); - } - if (ret) return parse_extfs_error(fs, parent, ret); - - if (ext2fs_test_inode_bitmap2(fs->inode_map, ino)) - LOG_WARN("Warning: inode already set"); - ext2fs_inode_alloc_stats2(fs, ino, +1, 0); - - struct ext2_inode inode; - memset(&inode, 0, sizeof(inode)); - inode.i_mode = st_mode; -#ifndef NO_TIMESTAMP - inode.i_atime = inode.i_ctime = inode.i_mtime = - fs->now ? fs->now : time(0); -#endif - - if (filetype != S_IFIFO) { - devmajor = major(st_rdev); - devminor = minor(st_rdev); - - if ((devmajor < 256) && (devminor < 256)) { - inode.i_block[0] = devmajor * 256 + devminor; - inode.i_block[1] = 0; - } else { - inode.i_block[0] = 0; - inode.i_block[1] = (devminor & 0xff) | (devmajor << 8) | - ((devminor & ~0xff) << 12); - } - } - inode.i_links_count = 1; - - ret = ext2fs_write_new_inode(fs, ino, &inode); - if (ret) return parse_extfs_error(fs, ino, ret); - - return 0; -} - -int do_ext2fs_stat(ext2_filsys fs, ext2_ino_t ino, struct stat *statbuf) { - dev_t fakedev = 0; - errcode_t ret; - struct timespec tv; - - struct ext2_inode_large inode; - memset(&inode, 0, sizeof(inode)); - ret = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, sizeof(inode)); - if (ret) return parse_extfs_error(fs, ino, ret); - - memcpy(&fakedev, fs->super->s_uuid, sizeof(fakedev)); - statbuf->st_dev = fakedev; - statbuf->st_ino = ino; - statbuf->st_mode = inode.i_mode; - statbuf->st_nlink = inode.i_links_count; - statbuf->st_uid = inode_uid(inode); - statbuf->st_gid = inode_gid(inode); - statbuf->st_size = EXT2_I_SIZE(&inode); - statbuf->st_blksize = fs->blocksize; - statbuf->st_blocks = blocks_from_inode(fs, (struct ext2_inode *)&inode); - statbuf->st_atime = inode.i_atime; - statbuf->st_mtime = inode.i_mtime; - statbuf->st_ctime = inode.i_ctime; - if (LINUX_S_ISCHR(inode.i_mode) || - LINUX_S_ISBLK(inode.i_mode)) { - if (inode.i_block[0]) - statbuf->st_rdev = inode.i_block[0]; - else - statbuf->st_rdev = inode.i_block[1]; - } - - return 0; -} - -int do_ext2fs_stat(ext2_filsys fs, const char *path, struct stat *statbuf, int follow) { - LOG_DEBUG(VALUE(path)); - ext2_ino_t ino = string_to_inode(fs, path, follow); - if (!ino) return -ENOENT; - - return do_ext2fs_stat(fs, ino, statbuf); -} - -int do_ext2fs_readdir(ext2_filsys fs, const char *path, std::vector<::dirent> *dirs) { - ext2_ino_t ino = string_to_inode(fs, path, 1); - if (!ino) return -ENOENT; - - ext2_file_t file; - errcode_t ret = ext2fs_file_open( - fs, - ino, // inode, - 0, // flags TODO - &file); - if (ret) return parse_extfs_error(fs, ino, ret); - ret = ext2fs_check_directory(fs, ino); - if (ret) return parse_extfs_error(fs, ino, ret); - auto block_buf = (char *)malloc(fs->blocksize); - ret = ext2fs_dir_iterate( - fs, - ino, - 0, // flags - block_buf, - copy_dirent_to_result, - (void *)dirs); - free(block_buf); - if (ret) return parse_extfs_error(fs, ino, ret); - - return 0; -} - -int do_ext2fs_truncate(ext2_filsys fs, const char *path, off_t length) { - ext2_ino_t ino = string_to_inode(fs, path, 1); - if (!ino) return -ENOENT; - - ext2_file_t file; - errcode_t ret = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &file); - if (ret) return parse_extfs_error(fs, ino, ret); - - ret = ext2fs_file_set_size2(file, length); - if (ret) { - ext2fs_file_close(file); - return parse_extfs_error(fs, ino, ret); - } - - ret = ext2fs_file_close(file); - if (ret) return parse_extfs_error(fs, ino, ret); - ret = update_xtime(fs, ino, nullptr, EXT_CTIME | EXT_MTIME); - if (ret) return ret; - - return 0; -} - -int do_ext2fs_ftruncate(ext2_file_t file, int flags, off_t length) { - if ((flags & (O_WRONLY | O_RDWR)) == 0) { - return -EBADF; - } - errcode_t ret = 0; - ret = ext2fs_file_set_size2(file, length); - if (ret) return parse_extfs_error(nullptr, 0, ret); - ret = update_xtime(file, EXT_CTIME | EXT_MTIME); - if (ret) return ret; - ret = ext2fs_file_flush(file); - if (ret) return parse_extfs_error(nullptr, 0, ret); - - return 0; -} - -int do_ext2fs_access(ext2_filsys fs, const char *path, int mode) { - ext2_ino_t ino = string_to_inode(fs, path, 1); - if (!ino) return -ENOENT; - // existence check - if (mode == 0) return 0; - - struct ext2_inode inode; - errcode_t ret = ext2fs_read_inode(fs, ino, &inode); - if (ret) return parse_extfs_error(fs, ino, ret); - - mode_t perms = inode.i_mode & 0777; - if ((mode & W_OK) && (inode.i_flags & EXT2_IMMUTABLE_FL)) - return -EACCES; - if ((mode & perms) == (mode_t)mode) - return 0; - return -EACCES; -} - -int do_ext2fs_statvfs(ext2_filsys fs, const char *path, struct statvfs *buf) { - auto dblk = fs->desc_blocks + (blk64_t)fs->group_desc_count * (fs->inode_blocks_per_group + 2); - auto rblk = ext2fs_r_blocks_count(fs->super); - if (!rblk) rblk = ext2fs_blocks_count(fs->super) / 10; - auto fblk = ext2fs_free_blocks_count(fs->super); - - buf->f_bsize = fs->blocksize; - buf->f_frsize = fs->blocksize; - buf->f_blocks = ext2fs_blocks_count(fs->super) - dblk; - buf->f_bfree = fblk; - buf->f_bavail = (fblk < rblk) ? 0 : (fblk - rblk); - buf->f_files = fs->super->s_inodes_count; - buf->f_ffree = fs->super->s_free_inodes_count; - buf->f_favail = fs->super->s_free_inodes_count; - auto fptr = (uint64_t *)fs->super->s_uuid; - buf->f_fsid = *(fptr++) ^ *fptr; - buf->f_flag = 0; - if (!(fs->flags & EXT2_FLAG_RW)) buf->f_flag |= ST_RDONLY; - buf->f_namemax = EXT2_NAME_LEN; - - return 0; -} - -int do_ext2fs_statfs(ext2_filsys fs, const char *path, struct statfs *buf) { - auto dblk = fs->desc_blocks + (blk64_t)fs->group_desc_count * (fs->inode_blocks_per_group + 2); - auto rblk = ext2fs_r_blocks_count(fs->super); - if (!rblk) rblk = ext2fs_blocks_count(fs->super) / 10; - auto fblk = ext2fs_free_blocks_count(fs->super); - - buf->f_type = fs->magic; - buf->f_bsize = fs->blocksize; - buf->f_frsize = fs->blocksize; - buf->f_blocks = ext2fs_blocks_count(fs->super) - dblk; - buf->f_bfree = fblk; - buf->f_bavail = (fblk < rblk) ? 0 : (fblk - rblk); - buf->f_files = fs->super->s_inodes_count; - buf->f_ffree = fs->super->s_free_inodes_count; - auto fptr = (uint64_t *)fs->super->s_uuid; - auto fsid = *(fptr++) ^ *fptr; - memcpy(&(buf->f_fsid), &fsid, sizeof(buf->f_fsid)); - buf->f_flags = 0; - if (!(fs->flags & EXT2_FLAG_RW)) buf->f_flags |= ST_RDONLY; - buf->f_namelen = EXT2_NAME_LEN; - - return 0; -} - -ssize_t do_ext2fs_readlink(ext2_filsys fs, const char *path, char *buf, size_t bufsize) { - ext2_ino_t ino = string_to_inode(fs, path, 0); - if (!ino) return -ENOENT; - - struct ext2_inode inode; - errcode_t ret = ext2fs_read_inode(fs, ino, &inode); - if (ret) return parse_extfs_error(fs, ino, ret); - - if (!LINUX_S_ISLNK(inode.i_mode)) - return -EINVAL; - - size_t len = bufsize - 1; - if (inode.i_size < len) - len = inode.i_size; - - if (ext2fs_is_fast_symlink(&inode)) { - memcpy(buf, (char *)inode.i_block, len); - } else { - ext2_file_t file; - unsigned int got; - ret = ext2fs_file_open(fs, ino, 0, &file); - if (ret) return parse_extfs_error(fs, ino, ret); - ret = ext2fs_file_read(file, buf, len, &got); - if (ret) { - ext2fs_file_close(file); - return parse_extfs_error(fs, ino, ret); - } - ret = ext2fs_file_close(file); - if (ret) return parse_extfs_error(fs, ino, ret); - if (got != len) return -EINVAL; - } - buf[len] = 0; - - return (len + 1); -} - -int do_ext2fs_fallocate(ext2_filsys fs, ext2_ino_t ino, off_t offset, off_t len) { - struct ext2_inode inode; - memset(&inode, 0, sizeof(inode)); - - errcode_t ret = ext2fs_read_inode(fs, ino, &inode); - if (ret) return parse_extfs_error(fs, ino, ret); - - LOG_DEBUG("do_ext2fs_fallocate ", VALUE(offset), VALUE(len)); - auto start = offset / fs->blocksize; - auto end = (offset + len - 1) / fs->blocksize; - LOG_DEBUG("ext2fs_fallocate blocks `", end - start + 1); - - ret = ext2fs_fallocate(fs, EXT2_FALLOCATE_FORCE_INIT, ino, &inode, - ~0ULL, start, end - start + 1); - if (ret) return parse_extfs_error(fs, ino, ret); - - ret = ext2fs_inode_size_set(fs, (struct ext2_inode *)&inode, len); - if (ret) return parse_extfs_error(fs, ino, ret); - - ret = ext2fs_write_inode(fs, ino, &inode); - if (ret) return parse_extfs_error(fs, ino, ret); - - return 0; -} - -static int ino_iter_extents(ext2_filsys fs, ext2_ino_t ino, - ext2_extent_handle_t extents, - std::vector> &blocks) { - errcode_t retval; - int op = EXT2_EXTENT_ROOT; - struct ext2fs_extent extent; - - for (;;) { - retval = ext2fs_extent_get(extents, op, &extent); - if (retval) - break; - - op = EXT2_EXTENT_NEXT; - - if ((extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) || - !(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) - continue; - LOG_DEBUG("found block ` `", extent.e_pblk, extent.e_len); - blocks.push_back({extent.e_pblk, extent.e_len}); - } - - if (retval == EXT2_ET_EXTENT_NO_NEXT) - retval = 0; - if (retval) { - LOG_WARN("getting extends of ino ", VALUE(retval), VALUE(ino)); - } - return retval; -} - -// TODO make ino_iter_blocks() compatible with ext2/3 -static int ino_iter_blocks(ext2_filsys fs, ext2_ino_t ino, - std::vector> &blocks) -{ - struct ext2_inode inode; - ext2_extent_handle_t extents; - - auto retval = ext2fs_read_inode(fs, ino, &inode); - if (retval) return retval; - - if (!ext2fs_inode_has_valid_blocks2(fs, &inode)) { - LOG_DEBUG("ext2fs_inode_has_valid_blocks2"); - return 0; - // return format->inline_data(&(inode.i_block[0]), - // format->private); - } - - retval = ext2fs_extent_open(fs, ino, &extents); - if (retval == EXT2_ET_INODE_NOT_EXTENT) { - LOG_DEBUG("EXT2_ET_INODE_NOT_EXTENT"); - return 0; - // retval = ext2fs_block_iterate3(fs, ino, BLOCK_FLAG_READ_ONLY, - // NULL, walk_block, pdata); - // if (retval) { - // com_err(__func__, retval, _("listing blocks of ino \"%u\""), - // ino); - // } - // return retval; - } - - auto ret = ino_iter_extents(fs, ino, extents, blocks); - ext2fs_extent_free(extents); - return ret; -} - -int do_ext2fs_fiemap(ext2_filsys fs, ext2_ino_t ino, struct photon::fs::fiemap* map) { - std::vector> blocks; - errcode_t ret = ino_iter_blocks(fs, ino, blocks); - if (ret) return parse_extfs_error(fs, ino, ret); - map->fm_mapped_extents = blocks.size(); - photon::fs::fiemap_extent *ext_buf = &map->fm_extents[0]; - for (uint32_t i = 0; i < blocks.size(); i++) { - LOG_DEBUG("find block ` `", blocks[i].first * fs->blocksize, blocks[i].second * fs->blocksize); - ext_buf[i].fe_physical = blocks[i].first * fs->blocksize; - ext_buf[i].fe_length = blocks[i].second * fs->blocksize; - } - return 0; -} - - -#define DO_EXT2FS(func) \ - auto ret = func; \ - if (ret < 0) { \ - errno = -ret; \ - return -1; \ - } \ - return ret; - -class ExtFileSystem; -class ExtFile : public photon::fs::VirtualFile { -public: - ExtFile(ext2_file_t _file, int _flags, ExtFileSystem *_fs) : - file(_file), flags(_flags), m_fs(_fs) { - fs = ext2fs_file_get_fs(file); - ino = ext2fs_file_get_inode_num(file); - } - - ~ExtFile() { - close(); - } - - virtual ssize_t pread(void *buf, size_t count, off_t offset) override { - DO_EXT2FS(do_ext2fs_read(file, flags, (char *)buf, count, offset)) - } - virtual ssize_t pwrite(const void *buf, size_t count, off_t offset) override { - DO_EXT2FS(do_ext2fs_write(file, flags, (const char *)buf, count, offset)) - } - virtual int fchmod(mode_t mode) override { - DO_EXT2FS(do_ext2fs_chmod(fs, ino, mode)) - } - virtual int fchown(uid_t owner, gid_t group) override { - DO_EXT2FS(do_ext2fs_chown(fs, ino, owner, group)) - } - virtual int futimes(const struct timeval tv[2]) { - DO_EXT2FS(do_ext2fs_utimes(fs, ino, tv)) - } - virtual int fstat(struct stat *buf) override { - DO_EXT2FS(do_ext2fs_stat(fs, ino, buf)) - } - virtual int close() override { - DO_EXT2FS(do_ext2fs_file_close(file)) - } - virtual int fsync() override { - if ((flags & (O_WRONLY | O_RDWR)) == 0) { - errno = EBADF; - return -1; - } - errcode_t ret = ext2fs_file_flush(file); - if (ret) { - errno = -parse_extfs_error(fs, ino, ret); - return -1; - } - return flush_buffer(); - } - virtual int fdatasync() override { - return this->fsync(); - } - virtual int ftruncate(off_t length) override { - DO_EXT2FS(do_ext2fs_ftruncate(file, flags, length)) - } - // mode is not used - virtual int fallocate(int mode, off_t o_offset, off_t len) override { - DO_EXT2FS(do_ext2fs_fallocate(fs, ino, o_offset, len)); - } - virtual int fiemap(struct photon::fs::fiemap* map) override { - DO_EXT2FS(do_ext2fs_fiemap(fs, ino, map)); - } - - virtual photon::fs::IFileSystem *filesystem() override; - - int flush_buffer(); - -private: - ext2_file_t file; - ext2_filsys fs; - ext2_ino_t ino; - int flags; - ExtFileSystem *m_fs; -}; - -class ExtDIR : public photon::fs::DIR { -public: - std::vector<::dirent> m_dirs; - ::dirent *direntp = nullptr; - long loc; - ExtDIR(std::vector<::dirent> &dirs) : loc(0) { - m_dirs = std::move(dirs); - next(); - } - virtual ~ExtDIR() override { - closedir(); - } - virtual int closedir() override { - if (!m_dirs.empty()) { - m_dirs.clear(); - } - return 0; - } - virtual dirent *get() override { - return direntp; - } - virtual int next() override { - if (!m_dirs.empty()) { - if (loc < (long) m_dirs.size()) { - direntp = &m_dirs[loc++]; - } else { - direntp = nullptr; - } - } - return direntp != nullptr ? 1 : 0; - } - virtual void rewinddir() override { - loc = 0; - next(); - } - virtual void seekdir(long loc) override { - this->loc = loc; - next(); - } - virtual long telldir() override { - return loc; - } -}; - -static const uint64_t kMinimalInoLife = 1L * 1000 * 1000; // ino lives at least 1s -class ExtFileSystem : public photon::fs::IFileSystem { -public: - ext2_filsys fs; - IOManager *extfs_manager = nullptr; - ExtFileSystem(photon::fs::IFile *_image_file, bool buffer = true) : ino_cache(kMinimalInoLife) { - if (buffer) { - buffer_file = new_buffer_file(_image_file); - extfs_manager = new_io_manager(buffer_file); - } else { - extfs_manager = new_io_manager(_image_file); - } - fs = do_ext2fs_open(extfs_manager->get_io_manager()); - memset(fs->reserved, 0, sizeof(fs->reserved)); - auto reserved = reinterpret_cast(fs->reserved); - reserved[0] = reinterpret_cast(this); - } - ~ExtFileSystem() { - if (fs) { - ext2fs_flush(fs); - ext2fs_close(fs); - LOG_INFO("ext2fs flushed and closed"); - } - delete extfs_manager; - delete buffer_file; - LOG_INFO(VALUE(total_read_cnt), VALUE(total_write_cnt)); - } - photon::fs::IFile *open(const char *path, int flags, mode_t mode) override { - ext2_file_t file = do_ext2fs_open_file(fs, path, flags, mode); - if (!file) { - return nullptr; - } - return new ExtFile(file, flags, this); - } - photon::fs::IFile *open(const char *path, int flags) override { - return open(path, flags, 0666); - } - photon::fs::IFile *creat(const char *path, mode_t mode) override { - return open(path, O_WRONLY | O_CREAT | O_TRUNC, mode); - } - int mkdir(const char *path, mode_t mode) override { - DO_EXT2FS(do_ext2fs_mkdir(fs, path, mode)) - } - int rmdir(const char *path) override { - DO_EXT2FS(do_ext2fs_rmdir(fs, path)) - } - int symlink(const char *oldname, const char *newname) override { - DO_EXT2FS(do_ext2fs_symlink(fs, oldname, newname)) - } - int link(const char *oldname, const char *newname) override { - DO_EXT2FS(do_ext2fs_link(fs, oldname, newname)) - } - int rename(const char *oldname, const char *newname) override { - DO_EXT2FS(do_ext2fs_rename(fs, oldname, newname)) - } - int unlink(const char *path) override { - DO_EXT2FS(do_ext2fs_unlink(fs, path)) - } - int mknod(const char *path, mode_t mode, dev_t dev) override { - DO_EXT2FS(do_ext2fs_mknod(fs, path, mode, dev)) - } - int utime(const char *path, const struct utimbuf *file_times) override { - struct timeval tv[2]; - tv[0].tv_sec = file_times->actime; - tv[0].tv_usec = 0; - tv[1].tv_sec = file_times->modtime; - tv[1].tv_usec = 0; - DO_EXT2FS(do_ext2fs_utimes(fs, path, tv, 1)); - } - int utimes(const char *path, const struct timeval tv[2]) override { - DO_EXT2FS(do_ext2fs_utimes(fs, path, tv, 1)); - } - int lutimes(const char *path, const struct timeval tv[2]) override { - DO_EXT2FS(do_ext2fs_utimes(fs, path, tv, 0)); - } - int chown(const char *path, uid_t owner, gid_t group) override { - DO_EXT2FS(do_ext2fs_chown(fs, path, owner, group, 1)) - } - int lchown(const char *path, uid_t owner, gid_t group) override { - DO_EXT2FS(do_ext2fs_chown(fs, path, owner, group, 0)) - } - int chmod(const char *path, mode_t mode) override { - DO_EXT2FS(do_ext2fs_chmod(fs, path, mode)) - } - int stat(const char *path, struct stat *buf) override { - DO_EXT2FS(do_ext2fs_stat(fs, path, buf, 1)) - } - int lstat(const char *path, struct stat *buf) override { - DO_EXT2FS(do_ext2fs_stat(fs, path, buf, 0)) - } - ssize_t readlink(const char *path, char *buf, size_t bufsize) override { - DO_EXT2FS(do_ext2fs_readlink(fs, path, buf, bufsize)) - } - int statfs(const char *path, struct statfs *buf) override { - DO_EXT2FS(do_ext2fs_statfs(fs, path, buf)) - } - int statvfs(const char *path, struct statvfs *buf) override { - DO_EXT2FS(do_ext2fs_statvfs(fs, path, buf)) - } - int access(const char *path, int mode) override { - DO_EXT2FS(do_ext2fs_access(fs, path, mode)) - } - int truncate(const char *path, off_t length) override { - DO_EXT2FS(do_ext2fs_truncate(fs, path, length)) - } - int syncfs() override { - errcode_t ret = ext2fs_flush(fs); - if (ret) { - errno = -parse_extfs_error(fs, 0, ret); - return -1; - } - return flush_buffer(); - } - - photon::fs::DIR *opendir(const char *path) override { - std::vector<::dirent> dirs; - auto ret = do_ext2fs_readdir(fs, path, &dirs); - if (ret) { - errno = -ret; - return nullptr; - } - return new ExtDIR(dirs); - } - - IFileSystem *filesystem() { - return this; - } - - ext2_ino_t get_inode(const char *str, int follow, bool release) { - ext2_ino_t ino = 0; - DEFER(LOG_DEBUG("get_inode ", VALUE(str), VALUE(follow), VALUE(release), VALUE(ino))); - - ext2_ino_t *ptr = nullptr; - auto func = [&]() -> ext2_ino_t * { - ext2_ino_t *i = new ext2_ino_t; - errcode_t ret = 0; - if (follow) { - ret = ext2fs_namei_follow(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, str, i); - } else { - auto parent = get_parent_dir_ino(fs, str); - if (parent) { - auto filename = get_filename(str); - if (filename) - ret = ext2fs_namei(fs, EXT2_ROOT_INO, parent, filename, i); - else - ret = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, str, i); - } else { - ret = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, str, i); - } - } - if (ret) { - LOG_DEBUG("ext2fs_namei not found ", VALUE(str), VALUE(follow)); - errno = -parse_extfs_error(fs, 0, ret); - delete i; - return nullptr; - } - LOG_DEBUG("ext2fs_namei ", VALUE(str), VALUE(follow), VALUE(*i)); - return i; - }; - - if (follow) { - auto b = func(); - if (b) ino = *b; - - } else { - auto b = ino_cache.borrow(str, func); - if (b) ino = *b; - } - - if (release) { - LOG_DEBUG("release ino_cache ", VALUE(str), VALUE(release)); - auto b = ino_cache.borrow(str); - b.recycle(true); - } - - return ino; - } - int flush_buffer() { - return buffer_file ? buffer_file->fdatasync() : 0; - } - -private: - ObjectCache ino_cache; - photon::fs::IFile *buffer_file = nullptr; -}; - -photon::fs::IFileSystem *ExtFile::filesystem() { - return m_fs; -} -int ExtFile::flush_buffer() { - return m_fs->flush_buffer(); -} - -photon::fs::IFileSystem *new_extfs(photon::fs::IFile *file, bool buffer) { - auto extfs = new ExtFileSystem(file, buffer); - return extfs->fs ? extfs : nullptr; -} - -ext2_ino_t string_to_inode(ext2_filsys fs, const char *str, int follow, bool release) { - auto reserved = reinterpret_cast(fs->reserved); - auto extfs = reinterpret_cast(reserved[0]); - // LOG_DEBUG("string_to_inode ", VALUE(str), VALUE(follow), VALUE(release)); - return extfs->get_inode(str, follow, release); -} diff --git a/src/overlaybd/extfs/extfs.h b/src/overlaybd/extfs/extfs.h deleted file mode 100644 index 7bcde973..00000000 --- a/src/overlaybd/extfs/extfs.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - Copyright The Overlaybd Authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#pragma once -#include -#include - -#define DEFAULT_BLOCK_SIZE 4096 - -class IOManager { -public: - virtual io_manager get_io_manager()=0; - virtual ~IOManager() {} -}; - -IOManager *new_io_manager(photon::fs::IFile *file); -photon::fs::IFileSystem *new_extfs(photon::fs::IFile *file, bool buffer = true); - -// make extfs on an prezeroed IFile, -// should be truncated to specified size in advance -int make_extfs(photon::fs::IFile *file); diff --git a/src/overlaybd/extfs/extfs_io.cpp b/src/overlaybd/extfs/extfs_io.cpp deleted file mode 100644 index 8748f3ed..00000000 --- a/src/overlaybd/extfs/extfs_io.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/* - Copyright The Overlaybd Authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#include - -#include -#include -#include - -#include "extfs.h" - -errcode_t extfs_open(const char *name, int flags, io_channel *channel); -errcode_t extfs_close(io_channel channel); -errcode_t extfs_set_blksize(io_channel channel, int blksize); -errcode_t extfs_read_blk(io_channel channel, unsigned long block, int count, void *buf); -errcode_t extfs_read_blk64(io_channel channel, unsigned long long block, int count, void *buf); -errcode_t extfs_write_blk(io_channel channel, unsigned long block, int count, const void *buf); -errcode_t extfs_write_blk64(io_channel channel, unsigned long long block, int count, const void *buf); -errcode_t extfs_flush(io_channel channel); -errcode_t extfs_discard(io_channel channel, unsigned long long block, unsigned long long count); -errcode_t extfs_cache_readahead(io_channel channel, unsigned long long block, unsigned long long count); -errcode_t extfs_zeroout(io_channel channel, unsigned long long block, unsigned long long count); - -struct unix_private_data { - int magic; - int dev; - int flags; - int align; - int access_time; - ext2_loff_t offset; - void *bounce; - struct struct_io_stats io_stats; -}; - -template -struct CallBack; - -template -struct CallBack { - template - static Ret callback(Args... args) { return cb.fire(args...); } - static Delegate cb; -}; - -// Initialize the static member. -template -Delegate CallBack::cb; - -// add for debug -static uint64_t total_read_cnt = 0; -static uint64_t total_write_cnt = 0; - -class ExtfsIOManager : public IOManager { -public: - using OpenFunc = errcode_t(const char *, int, io_channel *); - using OpenCallback = CallBack; - - ExtfsIOManager(photon::fs::IFile *file) : m_file(file) { - OpenCallback::cb.bind(this, &ExtfsIOManager::m_extfs_open); - auto extfs_open = static_cast(OpenCallback::callback); - - extfs_io_manager = { - .magic = EXT2_ET_MAGIC_IO_MANAGER, - .name = "extfs I/O Manager", - .open = extfs_open, - .close = extfs_close, - .set_blksize = extfs_set_blksize, - .read_blk = extfs_read_blk, - .write_blk = extfs_write_blk, - .flush = extfs_flush, - .write_byte = nullptr, - .set_option = nullptr, - .get_stats = nullptr, - .read_blk64 = extfs_read_blk64, - .write_blk64 = extfs_write_blk64, - .discard = extfs_discard, - .cache_readahead = extfs_cache_readahead, - .zeroout = extfs_zeroout, - .reserved = {}, - }; - } - - ~ExtfsIOManager() { - LOG_INFO(VALUE(total_read_cnt), VALUE(total_write_cnt)); - } - - virtual io_manager get_io_manager() override { - return &extfs_io_manager; - } - -private: - errcode_t m_extfs_open(const char *name, int flags, io_channel *channel) { - LOG_INFO(VALUE(name)); - DEFER(LOG_INFO("opened")); - ExtfsIOManager::mutex.lock(); - DEFER(ExtfsIOManager::mutex.unlock()); - io_channel io = nullptr; - struct unix_private_data *data = nullptr; - errcode_t retval; - ext2fs_struct_stat st; - - retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io); - if (retval) - return -retval; - memset(io, 0, sizeof(struct struct_io_channel)); - io->magic = EXT2_ET_MAGIC_IO_CHANNEL; - retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data); - if (retval) - return -retval; - - io->manager = &extfs_io_manager; - retval = ext2fs_get_mem(strlen(name) + 1, &io->name); - if (retval) - return -retval; - - strcpy(io->name, name); - io->private_data = data; - io->block_size = 1024; - io->read_error = 0; - io->write_error = 0; - io->refcount = 1; - io->flags = 0; - io->reserved[0] = reinterpret_cast(m_file); - LOG_DEBUG(VALUE(m_file), VALUE((void *)io->reserved[0])); - - memset(data, 0, sizeof(struct unix_private_data)); - data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL; - data->io_stats.num_fields = 2; - data->flags = flags; - data->dev = 0; - - *channel = io; - return 0; - } - - struct struct_io_manager extfs_io_manager; - photon::fs::IFile *m_file; - static photon::mutex mutex; -}; - -// Initialize the static member. -photon::mutex ExtfsIOManager::mutex; - -IOManager *new_io_manager(photon::fs::IFile *file) { - return new ExtfsIOManager(file); -} - -errcode_t extfs_close(io_channel channel) { - LOG_INFO("extfs close"); - return ext2fs_free_mem(&channel); -} - -errcode_t extfs_set_blksize(io_channel channel, int blksize) { - LOG_DEBUG(VALUE(blksize)); - channel->block_size = blksize; - return 0; -} - -errcode_t extfs_read_blk(io_channel channel, unsigned long block, int count, void *buf) { - off_t offset = (ext2_loff_t)block * channel->block_size; - ssize_t size = count < 0 ? -count : (ext2_loff_t)count * channel->block_size; - auto file = reinterpret_cast(channel->reserved[0]); - // LOG_DEBUG("read ", VALUE(offset), VALUE(size)); - auto res = file->pread(buf, size, offset); - if (res == size) { - total_read_cnt += size; - return 0; - } - LOG_ERROR("failed to pread, got `, expect `", res, size); - return -1; -} - -errcode_t extfs_read_blk64(io_channel channel, unsigned long long block, int count, void *buf) { - return extfs_read_blk(channel, block, count, buf); -} - -errcode_t extfs_write_blk(io_channel channel, unsigned long block, int count, const void *buf) { - off_t offset = (ext2_loff_t)block * channel->block_size; - ssize_t size = count < 0 ? -count : (ext2_loff_t)count * channel->block_size; - auto file = reinterpret_cast(channel->reserved[0]); - // LOG_DEBUG("write ", VALUE(offset), VALUE(size)); - auto res = file->pwrite(buf, size, offset); - if (res == size) { - total_write_cnt += size; - return 0; - } - LOG_ERROR("failed to pwrite, got `, expect `", res, size); - return -1; -} - -errcode_t extfs_write_blk64(io_channel channel, unsigned long long block, int count, const void *buf) { - return extfs_write_blk(channel, block, count, buf); -} - -errcode_t extfs_flush(io_channel channel) { - return 0; -} - -errcode_t extfs_discard(io_channel channel, unsigned long long block, unsigned long long count) { - return 0; -} - -errcode_t extfs_cache_readahead(io_channel channel, unsigned long long block, unsigned long long count) { - return 0; -} - -errcode_t extfs_zeroout(io_channel channel, unsigned long long block, unsigned long long count) { - return 0; -} diff --git a/src/overlaybd/extfs/extfs_utils.h b/src/overlaybd/extfs/extfs_utils.h deleted file mode 100644 index 3ba21449..00000000 --- a/src/overlaybd/extfs/extfs_utils.h +++ /dev/null @@ -1,482 +0,0 @@ -/* - Copyright The Overlaybd Authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#include -#include -#include -#include -#include - -int __parse_extfs_error(ext2_filsys fs, errcode_t err, ext2_ino_t ino, std::string &err_msg); - -// parse_extfs_error parse extfs error to unix error code -// print ERROR log for unclassified extfs error -#define parse_extfs_error(fs, ino, err) ({ \ - std::string __msg; \ - int __err = __parse_extfs_error((fs), (err), (ino), __msg); \ - if (__msg != "") { \ - if (ino) { \ - LOG_ERROR("unclassified ext2fs error: `:` (inode #`)", err, __msg.c_str(), ino); \ - } else { \ - LOG_ERROR("unclassified ext2fs error: `:`", err, __msg.c_str()); \ - } \ - } \ - __err; \ -}) - -inline void increment_version(struct ext2_inode *inode) { - inode->osd1.linux1.l_i_version++; -} - -inline void get_now(struct timespec *now) { -#ifdef CLOCK_REALTIME - if (!clock_gettime(CLOCK_REALTIME, now)) - return; -#endif - now->tv_sec = time(NULL); - now->tv_nsec = 0; -} - -#define EXT_ATIME 1 -#define EXT_CTIME 2 -#define EXT_MTIME 4 - -int update_xtime(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *pinode, - int flags, struct timespec *file_time = nullptr) { -#ifndef NO_TIMESTAMP - errcode_t ret = 0; - struct ext2_inode inode, *pino; - - if (pinode) { - pino = pinode; - } else { - memset(&inode, 0, sizeof(inode)); - ret = ext2fs_read_inode(fs, ino, &inode); - if (ret) - return parse_extfs_error(fs, ino, ret); - pino = &inode; - } - - struct timespec now; - if (!file_time) { - get_now(&now); - } else { - now = *file_time; - } - - if (flags & EXT_ATIME) pino->i_atime = now.tv_sec; - if (flags & EXT_CTIME) pino->i_ctime = now.tv_sec; - if (flags & EXT_MTIME) pino->i_mtime = now.tv_sec; - increment_version(pino); - - if (!pinode) { - ret = ext2fs_write_inode(fs, ino, &inode); - if (ret) - return parse_extfs_error(fs, ino, ret); - } -#endif - return 0; -} - -int update_xtime(ext2_file_t file, int flags, struct timespec *file_time = nullptr) { -#ifndef NO_TIMESTAMP - errcode_t ret = 0; - ext2_filsys fs = ext2fs_file_get_fs(file); - ext2_ino_t ino = ext2fs_file_get_inode_num(file); - struct ext2_inode *inode = ext2fs_file_get_inode(file); - - ret = ext2fs_read_inode(fs, ino, inode); - if (ret) return parse_extfs_error(fs, ino, ret); - - ret = update_xtime(fs, ino, inode, flags, file_time); - if (ret) return ret; - - ret = ext2fs_write_inode(fs, ino, inode); - if (ret) return parse_extfs_error(fs, ino, ret); -#endif - return 0; -} - -int ext2_file_type(unsigned int mode) { - switch (mode & LINUX_S_IFMT) { - case LINUX_S_IFLNK: return EXT2_FT_SYMLINK; - case LINUX_S_IFREG: return EXT2_FT_REG_FILE; - case LINUX_S_IFDIR: return EXT2_FT_DIR; - case LINUX_S_IFCHR: return EXT2_FT_CHRDEV; - case LINUX_S_IFBLK: return EXT2_FT_BLKDEV; - case LINUX_S_IFIFO: return EXT2_FT_FIFO; - case LINUX_S_IFSOCK: return EXT2_FT_SOCK; - default: return EXT2_FT_UNKNOWN; - } -} - -unsigned int extfs_open_flags(unsigned int flags) { - unsigned int ret = 0; - if (flags & (O_WRONLY | O_RDWR)) ret |= EXT2_FILE_WRITE; - if (flags & O_CREAT) ret |= EXT2_FILE_CREATE; - return ret; -} - -ext2_ino_t string_to_inode(ext2_filsys fs, const char *str, int follow, bool release = false); - -int unlink_file_by_name(ext2_filsys fs, const char *path) { - errcode_t ret = 0; - ext2_ino_t ino; - - DEFER(LOG_DEBUG("unlink ", VALUE(path), VALUE(ino), VALUE(ret))); - char *filename = strdup(path); - DEFER(free(filename);); - char *base_name; - - base_name = strrchr(filename, '/'); - if (base_name) { - *base_name++ = '\0'; - ino = string_to_inode(fs, filename, 0); - if (ino == 0) { - ret = ENOENT; - return -ENOENT; - } - } else { - ino = EXT2_ROOT_INO; - base_name = filename; - } - - ret = ext2fs_unlink(fs, ino, base_name, 0, 0); - if (ret) return parse_extfs_error(fs, ino, ret); - return update_xtime(fs, ino, nullptr, EXT_CTIME | EXT_MTIME); -} - -int remove_inode(ext2_filsys fs, ext2_ino_t ino) { - errcode_t ret_err = 0; - errcode_t err = 0; - - DEFER(LOG_DEBUG("remove ", VALUE(ino), VALUE(ret_err))); - - struct ext2_inode_large inode; - memset(&inode, 0, sizeof(inode)); - ret_err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, sizeof(inode)); - if (ret_err) return parse_extfs_error(fs, ino, ret_err); - - if (inode.i_links_count == 0) return 0; - inode.i_links_count--; - if (inode.i_links_count == 0) { -#ifndef NO_TIMESTAMP - inode.i_dtime = time(0); -#else - inode.i_dtime = 0; -#endif - } - - ret_err = update_xtime(fs, ino, (struct ext2_inode *)&inode, EXT_CTIME); - if (ret_err) return ret_err; - - if (inode.i_links_count) goto write_out; - - /* Nobody holds this file; free its blocks! */ - err = ext2fs_free_ext_attr(fs, ino, &inode); - if (err) { - ret_err = parse_extfs_error(fs, ino, err); - LOG_ERROR("ext2fs_free_ext_attr failed, ret_err: `", ret_err); - goto write_out; - } - if (ext2fs_inode_has_valid_blocks2(fs, (struct ext2_inode *)&inode)) { - err = ext2fs_punch(fs, ino, (struct ext2_inode *)&inode, NULL, 0, ~0ULL); - if (err) { - ret_err = parse_extfs_error(fs, ino, err); - LOG_ERROR("ext2fs_punch failed, ret_err: `", ret_err); - goto write_out; - } - } - ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode)); - -write_out: - err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, sizeof(inode)); - if (err) ret_err = parse_extfs_error(fs, ino, err); - return ret_err; -} - -struct rd_struct { - ext2_ino_t parent; - int empty; -}; - -int rmdir_proc( - ext2_ino_t dir, - int entry, - struct ext2_dir_entry *dirent, - int offset, - int blocksize, - char *buf, - void *priv_data) { - - struct rd_struct *rds = (struct rd_struct *)priv_data; - - if (dirent->inode == 0) - return 0; - if (((dirent->name_len & 0xFF) == 1) && (dirent->name[0] == '.')) - return 0; - if (((dirent->name_len & 0xFF) == 2) && (dirent->name[0] == '.') && - (dirent->name[1] == '.')) { - rds->parent = dirent->inode; - return 0; - } - rds->empty = 0; - return 0; -} - -int __parse_extfs_error(ext2_filsys fs, errcode_t err, ext2_ino_t ino, std::string &err_msg) { - if (err < EXT2_ET_BASE) return -err; - - switch (err) { - case EXT2_ET_NO_MEMORY: case EXT2_ET_TDB_ERR_OOM: - return -ENOMEM; - - case EXT2_ET_INVALID_ARGUMENT: case EXT2_ET_LLSEEK_FAILED: - return -EINVAL; - - case EXT2_ET_NO_DIRECTORY: - return -ENOTDIR; - - case EXT2_ET_FILE_NOT_FOUND: - return -ENOENT; - - case EXT2_ET_TOOSMALL: case EXT2_ET_BLOCK_ALLOC_FAIL: case EXT2_ET_INODE_ALLOC_FAIL: case EXT2_ET_EA_NO_SPACE: - return -ENOSPC; - - case EXT2_ET_SYMLINK_LOOP: - return -EMLINK; - - case EXT2_ET_FILE_TOO_BIG: - return -EFBIG; - - case EXT2_ET_TDB_ERR_EXISTS: case EXT2_ET_FILE_EXISTS: case EXT2_ET_DIR_EXISTS: - return -EEXIST; - - case EXT2_ET_MMP_FAILED: case EXT2_ET_MMP_FSCK_ON: - return -EBUSY; - - case EXT2_ET_EA_KEY_NOT_FOUND: -#ifdef ENODATA - return -ENODATA; -#else - return -ENOENT; -#endif - break; - /* Sometimes fuse returns a garbage file handle pointer to us... */ - case EXT2_ET_MAGIC_EXT2_FILE: - return -EFAULT; - - case EXT2_ET_UNIMPLEMENTED: - return -EOPNOTSUPP; - - case EXT2_ET_FILE_RO: - return -EACCES; - } - - // unclassified extfs error - if (fs) { - ext2fs_mark_super_dirty(fs); - ext2fs_flush(fs); - } - // decode error message - switch (err) { - case EXT2_ET_DIR_NO_SPACE: - err_msg = "EXT2_ET_DIR_NO_SPACE"; - return -ENOSPC; - - case EXT2_ET_BAD_MAGIC: - err_msg = "EXT2_ET_BAD_MAGIC"; - return -EIO; - - case EXT2_ET_DIR_CORRUPTED: - err_msg = "EXT2_ET_DIR_CORRUPTED"; - return -EIO; - - case EXT2_ET_UNEXPECTED_BLOCK_SIZE: - err_msg = "EXT2_ET_UNEXPECTED_BLOCK_SIZE"; - return -EIO; - - default: - err_msg = "to be decode"; - return -EIO; - } -} - -struct update_dotdot { - ext2_ino_t new_dotdot; -}; - -int update_dotdot_helper( - ext2_ino_t dir, - int entry, - struct ext2_dir_entry *dirent, - int offset, - int blocksize, - char *buf, - void *priv_data) { - struct update_dotdot *ud = (struct update_dotdot *)priv_data; - - if (ext2fs_dirent_name_len(dirent) == 2 && - dirent->name[0] == '.' && dirent->name[1] == '.') { - dirent->inode = ud->new_dotdot; - return DIRENT_CHANGED | DIRENT_ABORT; - } - - return 0; -} - -ext2_ino_t get_parent_dir_ino(ext2_filsys fs, const char *path) { - char *last_slash = strrchr((char *)path, '/'); - if (last_slash == 0) { - return 0; - } - unsigned int parent_len = last_slash - path; - if (parent_len == 0) { - return EXT2_ROOT_INO; - } - char *parent_path = strndup(path, parent_len); - ext2_ino_t parent_ino = string_to_inode(fs, parent_path, 0); - // LOG_DEBUG(VALUE(path), VALUE(parent_path), VALUE(parent_ino)); - free(parent_path); - return parent_ino; -} - -char *get_filename(const char *path) { - char *last_slash = strrchr((char *)path, (int)'/'); - if (last_slash == nullptr) { - return nullptr; - } - char *filename = last_slash + 1; - if (strlen(filename) == 0) { - return nullptr; - } - return filename; -} - -int create_file(ext2_filsys fs, const char *path, unsigned int mode, ext2_ino_t *ino) { - ext2_ino_t parent; - errcode_t ret = 0; - - DEFER(LOG_DEBUG("create ", VALUE(path), VALUE(parent), VALUE(*ino), VALUE(ret))); - parent = get_parent_dir_ino(fs, path); - if (parent == 0) { - ret = ENOTDIR; - return -ENOTDIR; - } - ret = ext2fs_new_inode(fs, parent, mode, 0, ino); - if (ret) { - return parse_extfs_error(fs, parent, ret); - } - char *filename = get_filename(path); - if (filename == nullptr) { - // This should never happen. - ret = EISDIR; - return -EISDIR; - } - ret = ext2fs_link(fs, parent, filename, *ino, EXT2_FT_REG_FILE); - if (ret == EXT2_ET_DIR_NO_SPACE) { - ret = ext2fs_expand_dir(fs, parent); - if (ret) return parse_extfs_error(fs, parent, ret); - ret = ext2fs_link(fs, parent, filename, *ino, EXT2_FT_REG_FILE); - } - if (ret) return parse_extfs_error(fs, parent, ret); - if (ext2fs_test_inode_bitmap2(fs->inode_map, *ino)) { - LOG_WARN("inode already set ", VALUE(*ino)); - } - ext2fs_inode_alloc_stats2(fs, *ino, +1, 0); - - struct ext2_inode inode; - memset(&inode, 0, sizeof(inode)); - inode.i_mode = (mode & ~LINUX_S_IFMT) | LINUX_S_IFREG; -#ifndef NO_TIMESTAMP - inode.i_atime = inode.i_ctime = inode.i_mtime = time(0); -#endif - inode.i_links_count = 1; - ret = ext2fs_inode_size_set(fs, &inode, 0); // TODO: update size? also on write? - if (ret) return parse_extfs_error(fs, 0, ret); - if (ext2fs_has_feature_inline_data(fs->super)) { - inode.i_flags |= EXT4_INLINE_DATA_FL; - } else if (ext2fs_has_feature_extents(fs->super)) { - ext2_extent_handle_t handle; - inode.i_flags &= ~EXT4_EXTENTS_FL; - ret = ext2fs_extent_open2(fs, *ino, &inode, &handle); - if (ret) return parse_extfs_error(fs, 0, ret); - ext2fs_extent_free(handle); - } - ret = ext2fs_write_new_inode(fs, *ino, &inode); - if (ret) return parse_extfs_error(fs, 0, ret); - if (inode.i_flags & EXT4_INLINE_DATA_FL) { - ret = ext2fs_inline_data_init(fs, *ino); - if (ret) return parse_extfs_error(fs, 0, ret); - } - return 0; -} - -unsigned char ext2_file_type_to_d_type(int type) { - switch (type) { - case EXT2_FT_UNKNOWN: - return DT_UNKNOWN; - case EXT2_FT_REG_FILE: - return DT_REG; - case EXT2_FT_DIR: - return DT_DIR; - case EXT2_FT_CHRDEV: - return DT_CHR; - case EXT2_FT_BLKDEV: - return DT_BLK; - case EXT2_FT_FIFO: - return DT_FIFO; - case EXT2_FT_SOCK: - return DT_SOCK; - case EXT2_FT_SYMLINK: - return DT_LNK; - default: - return DT_UNKNOWN; - } -} - -int array_push_dirent(std::vector *dirs, struct ext2_dir_entry *dir, size_t len) { - struct dirent tmpdir; - tmpdir.d_ino = (ino_t)dir->inode; - tmpdir.d_off = 0; // ? - tmpdir.d_reclen = dir->rec_len; - tmpdir.d_type = ext2_file_type_to_d_type(ext2fs_dirent_file_type(dir)); - memset(tmpdir.d_name, 0, sizeof(tmpdir.d_name)); - memcpy(tmpdir.d_name, dir->name, len); - dirs->emplace_back(tmpdir); - LOG_DEBUG(VALUE(tmpdir.d_ino), VALUE(tmpdir.d_reclen), VALUE(tmpdir.d_type), VALUE(tmpdir.d_name), VALUE(len)); - return 0; -} - -int copy_dirent_to_result(struct ext2_dir_entry *dirent, int offset, int blocksize, char *buf, void *priv_data) { - size_t len = ext2fs_dirent_name_len(dirent); - if ((strncmp(dirent->name, ".", len) != 0) && - (strncmp(dirent->name, "..", len) != 0)) { - array_push_dirent((std::vector<::dirent> *)priv_data, dirent, len); - } - return 0; -} - -blkcnt_t blocks_from_inode(ext2_filsys fs, struct ext2_inode *inode) { - blk64_t ret = inode->i_blocks; - - if (ext2fs_has_feature_huge_file(fs->super)) { - ret += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32; - if (inode->i_flags & EXT4_HUGE_FILE_FL) - ret *= (fs->blocksize / 512); - } - return ret; -} diff --git a/src/overlaybd/extfs/mkfs.cpp b/src/overlaybd/extfs/mkfs.cpp deleted file mode 100644 index 2ab6ee84..00000000 --- a/src/overlaybd/extfs/mkfs.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - Copyright The Overlaybd Authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ -#include "extfs.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int mkdir_lost_found(ext2_filsys fs) { - std::string name = "lost+found"; - fs->umask = 077; - ext2_ino_t ret = ext2fs_mkdir(fs, EXT2_ROOT_INO, 0, name.c_str()); - if (ret) { - LOG_ERRNO_RETURN(0, -1, "error mkdir for /lost+found ", VALUE(ret)); - } - ext2_ino_t ino; - ret = ext2fs_lookup(fs, EXT2_ROOT_INO, name.c_str(), name.length(), 0, &ino); - if (ret) { - LOG_ERRNO_RETURN(0, -1, "error looking up for /lost+found ", VALUE(ret)); - } - // expand twice ensure at least 2 blocks - for (int i = 0; i < 2; i++) { - ret = ext2fs_expand_dir(fs, ino); - if (ret) { - LOG_ERRNO_RETURN(0, -1, "error expanding dir for /lost+found ", VALUE(ret)); - } - } - return 0; -} - -int do_mkfs(io_manager manager, size_t size) { - int blocksize = 4096; - blk64_t blocks_count = size / blocksize; - int inode_ratio = 16384; - int inode_size = 256; - double reserved_ratio = 0.05; - std::string uuid = "bdf7bb2e-c231-43ce-87c2-overlaybddev"; - - struct ext2_super_block fs_param; - memset(&fs_param, 0, sizeof(struct ext2_super_block)); - fs_param.s_rev_level = 1; - - ext2fs_set_feature_64bit(&fs_param); - ext2fs_set_feature_sparse_super(&fs_param); - ext2fs_set_feature_sparse_super2(&fs_param); - ext2fs_set_feature_filetype(&fs_param); - ext2fs_set_feature_resize_inode(&fs_param); - ext2fs_set_feature_dir_index(&fs_param); - ext2fs_set_feature_xattr(&fs_param); - ext2fs_set_feature_dir_nlink(&fs_param); - ext2fs_set_feature_large_file(&fs_param); - ext2fs_set_feature_huge_file(&fs_param); - ext2fs_set_feature_flex_bg(&fs_param); - ext2fs_set_feature_extents(&fs_param); - ext2fs_set_feature_extra_isize(&fs_param); - - fs_param.s_log_cluster_size = fs_param.s_log_block_size = 2; - fs_param.s_desc_size = EXT2_MIN_DESC_SIZE_64BIT; - fs_param.s_log_groups_per_flex = 0; - fs_param.s_inode_size = inode_size; - - ext2fs_blocks_count_set(&fs_param, blocks_count); - unsigned long long n = ext2fs_blocks_count(&fs_param) * blocksize / inode_ratio; - fs_param.s_inodes_count = (n > UINT_MAX) ? UINT_MAX : n; - - ext2fs_r_blocks_count_set(&fs_param, reserved_ratio * ext2fs_blocks_count(&fs_param)); - fs_param.s_backup_bgs[0] = 1; - fs_param.s_backup_bgs[1] = ~0; - - ext2_filsys fs; - // init superblock - errcode_t ret = ext2fs_initialize("virtual-dev", 0, &fs_param, manager, &fs); - if (ret) { - LOG_ERRNO_RETURN(0, -1, "error while setting up superblock ", VALUE(ret)); - } - - uuid4_parse((char*)uuid.c_str(), (char*)(fs->super->s_uuid)); - uuid4_parse((char*)uuid.c_str(), (char*)(fs_param.s_hash_seed)); - fs->super->s_kbytes_written = 1; - fs->super->s_def_hash_version = EXT2_HASH_HALF_MD4; - fs->super->s_max_mnt_count = -1; - fs->stride = fs->super->s_raid_stride; - // alloc tables - ret = ext2fs_allocate_tables(fs); - if (ret) { - LOG_ERRNO_RETURN(0, -1, "error while allocating tables ", VALUE(ret)); - } - // create root dir - ret = ext2fs_mkdir(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0); - if (ret) { - LOG_ERRNO_RETURN(0, -1, "error make root dir ", VALUE(ret)); - } - // mkdir for lost+found - ret = mkdir_lost_found(fs); - if (ret) { - return ret; - } - // reserve inodes - ext2fs_inode_alloc_stats2(fs, EXT2_BAD_INO, +1, 0); - for (ext2_ino_t i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->super); i++) - ext2fs_inode_alloc_stats2(fs, i, +1, 0); - ext2fs_mark_ib_dirty(fs); - // create resize inode - ret = ext2fs_create_resize_inode(fs); - if (ret) { - LOG_ERRNO_RETURN(0, -1, "error creating resize inode ", VALUE(ret)); - } - - ret = ext2fs_close_free(&fs); - if (ret) { - LOG_ERRNO_RETURN(0, -1, "error closing fs ", VALUE(ret)); - } - return 0; -} - -int make_extfs(photon::fs::IFile *file) { - struct stat st; - auto ret = file->fstat(&st); - if (ret) return ret; - auto manager = new_io_manager(file); - DEFER(delete manager); - ret = do_mkfs(manager->get_io_manager(), st.st_size); - return ret; -} diff --git a/src/overlaybd/extfs/test/CMakeLists.txt b/src/overlaybd/extfs/test/CMakeLists.txt deleted file mode 100644 index cca7ad2b..00000000 --- a/src/overlaybd/extfs/test/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -include_directories($ENV{GFLAGS}/include) -link_directories($ENV{GFLAGS}/lib) - -include_directories($ENV{GTEST}/googletest/include) -link_directories($ENV{GTEST}/lib) - -add_executable(extfs_test test.cpp) -target_include_directories(extfs_test PUBLIC ${PHOTON_INCLUDE_DIR}) -target_link_libraries(extfs_test gtest gtest_main gflags pthread photon_static overlaybd_lib) - -add_test( - NAME extfs_test - COMMAND ${EXECUTABLE_OUTPUT_PATH}/extfs_test -) diff --git a/src/overlaybd/extfs/test/test.cpp b/src/overlaybd/extfs/test/test.cpp deleted file mode 100644 index 7b2057a0..00000000 --- a/src/overlaybd/extfs/test/test.cpp +++ /dev/null @@ -1,826 +0,0 @@ -/* - Copyright The Overlaybd Authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#include "../extfs.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define FILE_SIZE (2 * 1024 * 1024) - -void print_stat(const char *path, struct stat *st) { - printf("File: %s\n", path); - printf("Size: %d, Blocks: %d, IO Blocks: %d, Type: %d\n", st->st_size, st->st_blocks, st->st_blksize, IFTODT(st->st_mode)); - printf("Device: %u/%u, Inode: %d, Links: %d, Device type: %u,%u\n", - major(st->st_dev), minor(st->st_dev), st->st_ino, st->st_nlink, major(st->st_rdev), minor(st->st_rdev)); - printf("Access: %05o, Uid: %d, Gid: %d\n", st->st_mode & 0xFFF, st->st_uid, st->st_gid); - printf("Access: %s", asctime(localtime(&(st->st_atim.tv_sec)))); - printf("Modify: %s", asctime(localtime(&(st->st_mtim.tv_sec)))); - printf("Change: %s", asctime(localtime(&(st->st_ctim.tv_sec)))); -} - -photon::fs::IFile *new_file(photon::fs::IFileSystem *fs, const char *path) { - auto file = fs->open(path, O_RDWR | O_CREAT | O_TRUNC, 0755); - if (!file) { - LOG_ERRNO_RETURN(0, nullptr, "failed open file ", VALUE(path)); - } - return file; -} - -int write_file(photon::fs::IFile *file) { - std::string bb = "abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz01"; - std::string aa; - while (aa.size() < FILE_SIZE) - aa.append(bb); - auto ret = file->pwrite(aa.data(), aa.size(), 0); - if (ret != (ssize_t)aa.size()) { - LOG_ERRNO_RETURN(0, -1, "failed write file ", VALUE(aa.size()), VALUE(ret)) - } - LOG_DEBUG("write ` byte", ret); - return 0; -} - -int stat(photon::fs::IFileSystem *fs, const char *path, struct stat *buf) { - auto ret = fs->stat(path, buf); - if (ret) { - LOG_ERRNO_RETURN(0, ret, "failed stat ", VALUE(path)); - } - return 0; -} - -int lstat(photon::fs::IFileSystem *fs, const char *path, struct stat *buf) { - auto ret = fs->lstat(path, buf); - if (ret) { - LOG_ERRNO_RETURN(0, ret, "failed lstat ", VALUE(path)); - } - return 0; -} - -int mkdir(photon::fs::IFileSystem *fs, const char *path) { - auto ret = fs->mkdir(path, 0755); - if (ret) { - LOG_ERRNO_RETURN(0, ret, "failed mkdir ", VALUE(path)); - } - return 0; -} - -int rmdir(photon::fs::IFileSystem *fs, const char *path) { - auto ret = fs->rmdir(path); - if (ret) { - LOG_ERRNO_RETURN(0, ret, "failed rmdir ", VALUE(path)); - } - return 0; -} - -int rename(photon::fs::IFileSystem *fs, const char *oldname, const char *newname) { - auto ret = fs->rename(oldname, newname); - if (ret) { - LOG_ERRNO_RETURN(0, ret, "failed rename ", VALUE(oldname), VALUE(newname)); - } - return 0; -} - -int chmod(photon::fs::IFileSystem *fs, const char *path, mode_t mode) { - auto ret = fs->chmod(path, mode); - if (ret) { - LOG_ERRNO_RETURN(0, ret, "failed chmod ", VALUE(path), VALUE(mode)); - } - return 0; -} - -int chown(photon::fs::IFileSystem *fs, const char *path, uid_t owner, gid_t group) { - auto ret = fs->chown(path, owner, group); - if (ret) { - LOG_ERRNO_RETURN(0, ret, "failed chown ", VALUE(path), VALUE(owner), VALUE(group)); - } - return 0; -} - -int lchown(photon::fs::IFileSystem *fs, const char *path, uid_t owner, gid_t group) { - auto ret = fs->lchown(path, owner, group); - if (ret) { - LOG_ERRNO_RETURN(0, ret, "failed lchown ", VALUE(path), VALUE(owner), VALUE(group)); - } - return 0; -} - -int link(photon::fs::IFileSystem *fs, const char *oldname, const char *newname) { - auto ret = fs->link(oldname, newname); - if (ret) { - LOG_ERRNO_RETURN(0, ret, "failed link ", VALUE(oldname), VALUE(newname)); - } - return 0; -} - -int symlink(photon::fs::IFileSystem *fs, const char *oldname, const char *newname) { - auto ret = fs->symlink(oldname, newname); - if (ret) { - LOG_ERRNO_RETURN(0, ret, "failed symlink ", VALUE(oldname), VALUE(newname)); - } - return 0; -} - -int unlink(photon::fs::IFileSystem *fs, const char *path) { - auto ret = fs->unlink(path); - if (ret) { - LOG_ERRNO_RETURN(0, ret, "failed unlink ", VALUE(path)); - } - return 0; -} - -int mknod(photon::fs::IFileSystem *fs, const char *path, mode_t mode, dev_t dev) { - auto ret = fs->mknod(path, mode, dev); - if (ret) { - LOG_ERRNO_RETURN(0, ret, "failed mknod ", VALUE(path), VALUE(mode), VALUE(dev)); - } - return 0; -} - -int utime(photon::fs::IFileSystem *fs, const char *path, const struct utimbuf *file_times) { - auto ret = fs->utime(path, file_times); - if (ret) { - LOG_ERRNO_RETURN(0, ret, "failed utime ", VALUE(path)); - } - return 0; -} - -int utimes(photon::fs::IFileSystem *fs, const char *path, const struct timeval tv[2]) { - auto ret = fs->utimes(path, tv); - if (ret) { - LOG_ERRNO_RETURN(0, ret, "failed utimes ", VALUE(path)); - } - return 0; -} - -int lutimes(photon::fs::IFileSystem *fs, const char *path, const struct timeval tv[2]) { - auto ret = fs->lutimes(path, tv); - if (ret) { - LOG_ERRNO_RETURN(0, ret, "failed utimes ", VALUE(path)); - } - return 0; -} - -int opendir(photon::fs::IFileSystem *fs, const char *path) { - auto ret = fs->opendir(path); - if (ret == nullptr) { - LOG_ERRNO_RETURN(0, -1, "failed opendir ", VALUE(path)); - } else { - delete ret; - return 0; - } -} - -int walkdir(photon::fs::IFileSystem *fs, const char *path) { - struct stat buf; - if (fs->lstat(path, &buf) < 0) { - LOG_ERRNO_RETURN(0, -1, "failed to lstat ", VALUE(path)); - } - LOG_DEBUG("walk dir ", VALUE(path)); - int count = 0; - for (auto file : enumerable(photon::fs::Walker(fs, path))) { - auto fn = std::string(file); - LOG_DEBUG(VALUE(fn)); - count++; - } - return count; -} - -int readlink(photon::fs::IFileSystem *fs, const char *path, char *buf, size_t bufsize) { - auto ret = fs->readlink(path, buf, bufsize); - if (ret < 0) { - LOG_ERRNO_RETURN(0, ret, "failed readlink ", VALUE(path), VALUE(buf)); - } - return ret; -} - -int access(photon::fs::IFileSystem *fs, const char *path, mode_t mode) { - auto ret = fs->access(path, mode); - if (ret) { - LOG_ERRNO_RETURN(0, ret, "failed access ", VALUE(path), VALUE(mode)); - } - return 0; -} - -int remove_all(photon::fs::IFileSystem *fs, const std::string &path) { - if (fs == nullptr || path.empty()) { - LOG_ERROR("remove_all ` failed, fs is null or path is empty", path); - return -1; - } - struct stat statBuf; - int ret = 0; - if (fs->lstat(path.c_str(), &statBuf) == 0) { // get stat - if (S_ISDIR(statBuf.st_mode) == 0) { // not dir - return fs->unlink(path.c_str()); - } - } else { - LOG_ERRNO_RETURN(0, -1, "get path ` stat failed", path); - } - - auto dirs = fs->opendir(path.c_str()); - if (dirs == nullptr) { - LOG_ERRNO_RETURN(0, -1, "open dir ` failed", path); - } - dirent *dirInfo; - while ((dirInfo = dirs->get()) != nullptr) { - if (strcmp(dirInfo->d_name, ".") != 0 && strcmp(dirInfo->d_name, "..") != 0) { - std::string npath(path); - if (npath.back() == '/') { - npath = npath.substr(0, npath.size() - 1); - } - LOG_DEBUG(VALUE(path), VALUE(npath)); - ret = remove_all(fs, npath + "/" + dirInfo->d_name); - if (ret) return ret; - } - dirs->next(); - } - - fs->closedir(dirs); - if (path == "/") - return 0; - ret = fs->rmdir(path.c_str()); - if (ret) return ret; - - return 0; -} - -photon::fs::IFileSystem *init_extfs() { - std::string rootfs = "/tmp/rootfs.img"; - // new extfs - auto image_file = photon::fs::open_localfile_adaptor(rootfs.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644, 0); - if (!image_file) { - LOG_ERRNO_RETURN(0, nullptr, "failed to open `", rootfs); - } - if (image_file->ftruncate(100 << 20) < 0) { - delete image_file; - LOG_ERRNO_RETURN(0, nullptr, "failed to truncate image to 100M"); - } - - if (make_extfs(image_file) < 0) { - delete image_file; - LOG_ERRNO_RETURN(0, nullptr, "failed to mkfs"); - } - - photon::fs::IFileSystem *extfs = new_extfs(image_file); - if (!extfs) { - delete image_file; - LOG_ERRNO_RETURN(0, nullptr, "failed open fs"); - } - - return extfs; -} -class ExtfsTest : public ::testing::Test { - protected: - virtual void SetUp() override { - } - virtual void TearDown() override { - } - - static void SetUpTestSuite() { - fs = init_extfs(); - ASSERT_NE(nullptr, fs); - } - - static void TearDownTestSuite() { - if (fs) - delete fs; - } - - static photon::fs::IFileSystem *fs; -}; - -photon::fs::IFileSystem *ExtfsTest::fs = nullptr; - -TEST_F(ExtfsTest, Regfile) { - photon::fs::IFile *file = new_file(fs, "/file1"); - ASSERT_NE(nullptr, file); - - auto ret = write_file(file); - ASSERT_EQ(0, ret); - - char buf[16]; - ret = file->pread(buf, 16, 0); - EXPECT_EQ(16, ret); - EXPECT_EQ(0, memcmp(buf, "abcdefghijklmnop", 16)); - ret = file->pread(buf, 16, 16384); - EXPECT_EQ(16, ret); - EXPECT_EQ(0, memcmp(buf, "abcdefghijklmnop", 16)); - delete file; - // stat - struct stat st; - ret = stat(fs, "/file1", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(FILE_SIZE, st.st_size); - EXPECT_EQ(DT_REG, IFTODT(st.st_mode)); -} - -TEST_F(ExtfsTest, Dir) { - // mkdir - auto ret = mkdir(fs, "/dir1"); - EXPECT_EQ(0, ret); - struct stat st; - ret = stat(fs, "/dir1", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(DT_DIR, IFTODT(st.st_mode)); - - ret = mkdir(fs, "/dir1/subdir1"); - EXPECT_EQ(0, ret); - ret = mkdir(fs, "/dir1"); - EXPECT_EQ(-1, ret); - EXPECT_EQ(EEXIST, errno); - ret = mkdir(fs, "/dir2/dir2"); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOTDIR, errno); - // rmdir - ret = mkdir(fs, "/dir2"); - EXPECT_EQ(0, ret); - ret = stat(fs, "/dir2", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(DT_DIR, IFTODT(st.st_mode)); - ret = rmdir(fs, "/dir2"); - EXPECT_EQ(0, ret); - ret = stat(fs, "/dir2", &st); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOENT, errno); - ret = rmdir(fs, "/dir1"); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOTEMPTY, errno); -} - -TEST_F(ExtfsTest, Link) { - auto ret = link(fs, "/file1", "/dir1/file1_link"); - EXPECT_EQ(0, ret); - struct stat st; - ret = stat(fs, "/dir1/file1_link", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(DT_REG, IFTODT(st.st_mode)); - EXPECT_EQ(2, st.st_nlink); - - ret = symlink(fs, "/file1", "/dir1/file1_symlink"); - EXPECT_EQ(0, ret); - ret = stat(fs, "/dir1/file1_symlink", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(DT_REG, IFTODT(st.st_mode)); - ret = lstat(fs, "/dir1/file1_symlink", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(DT_LNK, IFTODT(st.st_mode)); - - ret = link(fs, "/dir1/file1_symlink", "/file1_link"); - EXPECT_EQ(0, ret); - ret = stat(fs, "/file1_link", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(DT_REG, IFTODT(st.st_mode)); - ret = lstat(fs, "/file1_link", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(DT_LNK, IFTODT(st.st_mode)); - - ret = symlink(fs, "../file2", "/dir1/file2_symlink"); - EXPECT_EQ(0, ret); - ret = stat(fs, "/dir1/file2_symlink", &st); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOENT, errno); - ret = lstat(fs, "/dir1/file2_symlink", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(DT_LNK, IFTODT(st.st_mode)); - - ret = symlink(fs, "/file2", "/dir1/file1_symlink"); - EXPECT_EQ(-1, ret); - EXPECT_EQ(EEXIST, errno); - ret = symlink(fs, "/file1", "/dir2/file1_symlink"); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOTDIR, errno); - ret = symlink(fs, "..//file1", "/dir1/file5_symlink"); - EXPECT_EQ(0, ret); - ret = lstat(fs, "/dir1/file5_symlink", &st); - EXPECT_EQ(0, ret); - ret = stat(fs, "/dir1/file5_symlink", &st); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOENT, errno); -} - -TEST_F(ExtfsTest, Unlink) { - auto ret = symlink(fs, "/file2", "/dir1/file3_symlink"); - EXPECT_EQ(0, ret); - struct stat st; - ret = lstat(fs, "/dir1/file3_symlink", &st); - EXPECT_EQ(0, ret); - ret = unlink(fs, "/dir1/file3_symlink"); - EXPECT_EQ(0, ret); - ret = lstat(fs, "/dir1/file3_symlink", &st); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOENT, errno); - - ret = unlink(fs, "/dir1/file6_symlink"); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOENT, errno); - ret = unlink(fs, "/dir1"); - EXPECT_EQ(-1, ret); - EXPECT_EQ(EISDIR, errno); -} - -TEST_F(ExtfsTest, Chmod) { - auto ret = chmod(fs, "/file1", 0700); - EXPECT_EQ(0, ret); - struct stat st; - ret = lstat(fs, "/file1", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(0700, st.st_mode & 0xFFF); - - ret = chmod(fs, "/dir1", 0777); - EXPECT_EQ(0, ret); - ret = stat(fs, "/dir1", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(0777, st.st_mode & 0xFFF); - - ret = chmod(fs, "/file2", 0777); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOENT, errno); -} - -TEST_F(ExtfsTest, Chown) { - auto ret = chown(fs, "/dir1", 1001, 1010); - EXPECT_EQ(0, ret); - struct stat st; - ret = stat(fs, "/dir1", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(1001, st.st_uid); - EXPECT_EQ(1010, st.st_gid); - - ret = chown(fs, "/dir1/file1_symlink", 1002, 1020); - EXPECT_EQ(0, ret); - ret = stat(fs, "/dir1/file1_symlink", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(1002, st.st_uid); - EXPECT_EQ(1020, st.st_gid); - - ret = chown(fs, "/dir1/file2_symlink", 1003, 1030); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOENT, errno); - auto file = new_file(fs, "/file2"); - EXPECT_NE(nullptr, file); - DEFER(delete file;); - - struct stat st_old; - ret = stat(fs, "/dir1/file2_symlink", &st_old); - EXPECT_EQ(0, ret); - ret = lchown(fs, "/dir1/file2_symlink", 1003, 1030); - EXPECT_EQ(0, ret); - ret = lstat(fs, "/dir1/file2_symlink", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(1003, st.st_uid); - EXPECT_EQ(1030, st.st_gid); - ret = stat(fs, "/dir1/file2_symlink", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(st_old.st_uid, st.st_uid); - EXPECT_EQ(st_old.st_gid, st.st_gid); - ret = chown(fs, "/dir1/file2_symlink", 1004, 1040); - EXPECT_EQ(0, ret); - ret = stat(fs, "/dir1/file2_symlink", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(1004, st.st_uid); - EXPECT_EQ(1040, st.st_gid); - EXPECT_NE(st_old.st_uid, st.st_uid); - EXPECT_NE(st_old.st_gid, st.st_gid); - ret = unlink(fs, "/file2"); - EXPECT_EQ(0, ret); -} - -TEST_F(ExtfsTest, Mknod) { - auto ret = mkdir(fs, "/dev"); - EXPECT_EQ(0, ret); - ret = mknod(fs, "/dev/blkdev", 0755 | S_IFBLK, makedev(240, 0)); - EXPECT_EQ(0, ret); - struct stat st; - ret = stat(fs, "/dev/blkdev", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(DT_BLK, IFTODT(st.st_mode)); - - ret = mknod(fs, "/dev/chardev", 0700 | S_IFCHR, makedev(42, 0)); - EXPECT_EQ(0, ret); - ret = lstat(fs, "/dev/chardev", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(DT_CHR, IFTODT(st.st_mode)); - - ret = mknod(fs, "/fifo", S_IFIFO, makedev(0, 0)); - EXPECT_EQ(0, ret); - ret = lstat(fs, "/fifo", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(DT_FIFO, IFTODT(st.st_mode)); - - ret = mknod(fs, "/dev2/blkdev", 0755 | S_IFBLK, makedev(240, 0)); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOTDIR, errno); - ret = mknod(fs, "/dev/blkdev", 0755 | S_IFBLK, makedev(240, 0)); - EXPECT_EQ(-1, ret); - EXPECT_EQ(EEXIST, errno); -} - -TEST_F(ExtfsTest, Utime) { - struct timeval tv[2]; - gettimeofday(&tv[0], nullptr); - gettimeofday(&tv[1], nullptr); - - struct stat st, lst, st_old, lst_old; - auto ret = lstat(fs, "/dir1/file1_symlink", &lst_old); - EXPECT_EQ(0, ret); - tv[0].tv_sec = tv[0].tv_sec - 3661; - ret = utimes(fs, "/dir1/file1_symlink", tv); - EXPECT_EQ(0, ret); - ret = stat(fs, "/dir1/file1_symlink", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(tv[0].tv_sec, st.st_atim.tv_sec); - EXPECT_EQ(tv[1].tv_sec, st.st_mtim.tv_sec); - ret = lstat(fs, "/dir1/file1_symlink", &lst); - EXPECT_EQ(0, ret); - EXPECT_EQ(lst_old.st_atim.tv_sec, lst.st_atim.tv_sec); - EXPECT_EQ(lst_old.st_mtim.tv_sec, lst.st_mtim.tv_sec); - - ret = stat(fs, "/dir1/file1_symlink", &st_old); - EXPECT_EQ(0, ret); - tv[1].tv_sec = tv[1].tv_sec - 3661; - ret = lutimes(fs, "/dir1/file1_symlink", tv); - EXPECT_EQ(0, ret); - ret = stat(fs, "/dir1/file1_symlink", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(st_old.st_atim.tv_sec, st.st_atim.tv_sec); - EXPECT_EQ(st_old.st_mtim.tv_sec, st.st_mtim.tv_sec); - ret = lstat(fs, "/dir1/file1_symlink", &lst); - EXPECT_EQ(0, ret); - EXPECT_EQ(tv[0].tv_sec, lst.st_atim.tv_sec); - EXPECT_EQ(tv[1].tv_sec, lst.st_mtim.tv_sec); - - struct utimbuf ut; - ut.actime = tv[0].tv_sec - 3661; - ut.modtime = tv[1].tv_sec - 3661; - ret = lstat(fs, "/dir1/file1_symlink", &lst_old); - EXPECT_EQ(0, ret); - ret = utime(fs, "/dir1/file1_symlink", &ut); - EXPECT_EQ(0, ret); - ret = stat(fs, "/dir1/file1_symlink", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(ut.actime, st.st_atim.tv_sec); - EXPECT_EQ(ut.modtime, st.st_mtim.tv_sec); - ret = lstat(fs, "/dir1/file1_symlink", &lst); - EXPECT_EQ(0, ret); - EXPECT_EQ(lst_old.st_atim.tv_sec, lst.st_atim.tv_sec); - EXPECT_EQ(lst_old.st_mtim.tv_sec, lst.st_mtim.tv_sec); - - ret = utimes(fs, "/dir1/file2_symlink", tv); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOENT, errno); - ret = lutimes(fs, "/dir3/file1_symlink", tv); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOENT, errno); - ret = lutimes(fs, "/dir1/file2_symlink", tv); - EXPECT_EQ(0, ret); - ret = utime(fs, "/dir1/file2_symlink", &ut); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOENT, errno); -} - -TEST_F(ExtfsTest, Rename) { - struct stat st; - auto ret = stat(fs, "/file2", &st); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOENT, errno); - ret = rename(fs, "/file1", "/file2"); - EXPECT_EQ(0, ret); - ret = stat(fs, "/file1", &st); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOENT, errno); - ret = stat(fs, "/file2", &st); - EXPECT_EQ(0, ret); - - ret = rename(fs, "/file2", "/dir1"); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOTEMPTY, errno); - ret = rename(fs, "/dir1", "/dir2"); - EXPECT_EQ(0, ret); - ret = rename(fs, "/file2", "/dir2/file2"); - EXPECT_EQ(0, ret); - ret = rename(fs, "/file2", "/dir2/file2"); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOENT, errno); - ret = rename(fs, "/dir2/file2", "/dir1/file2"); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOTDIR, errno); - ret = rename(fs, "/dir2/file2", "/dir2/file1_link"); - EXPECT_EQ(0, ret); - auto file = new_file(fs, "/file2"); - EXPECT_NE(nullptr, file); - delete file; - ret = rename(fs, "/file2", "/dir2/file2"); - EXPECT_EQ(0, ret); - ret = rename(fs, "/dir2", "/dir1"); - EXPECT_EQ(0, ret); -} - -TEST_F(ExtfsTest, Readdir) { - auto ret = opendir(fs, "/dir3"); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOENT, errno); - ret = opendir(fs, "/"); - EXPECT_EQ(0, ret); - ret = walkdir(fs, "/test"); - EXPECT_EQ(-1, ret); - ret = walkdir(fs, "/dir1"); - LOG_INFO("found ` file", ret); - EXPECT_LT(0, ret); - ret = walkdir(fs, "/"); - LOG_INFO("found ` file", ret); - EXPECT_LT(0, ret); - // rm all - ret = remove_all(fs, "/test"); - EXPECT_EQ(-1, ret); - ret = remove_all(fs, "/dir1"); - EXPECT_EQ(0, ret); - ret = opendir(fs, "/dir1"); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOENT, errno); - ret = remove_all(fs, "/"); - EXPECT_EQ(0, ret); - ret = walkdir(fs, "/"); - LOG_INFO("found ` file", ret); - EXPECT_EQ(0, ret); -} - -TEST_F(ExtfsTest, Readlink) { - auto file = fs->creat("/file_to_readlink", 0755); - EXPECT_NE(nullptr, file); - delete file; - auto ret = mkdir(fs, "/dir_to_readlink"); - EXPECT_EQ(0, ret); - ret = symlink(fs, "/file_to_readlink", "/dir_to_readlink/short_readlink"); - EXPECT_EQ(0, ret); - - char buf[256] = {0}; - size_t len = sizeof("/file_to_readlink"); - ret = readlink(fs, "/dir_to_readlink/short_readlink", buf, sizeof(buf)); - EXPECT_EQ(len, ret); - EXPECT_EQ(0, strncmp("/file_to_readlink", buf, ret-1)); - - std::string long_name = "/bcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"; - file = fs->creat(long_name.c_str(), 0755); - EXPECT_NE(nullptr, file); - delete file; - ret = symlink(fs, long_name.c_str(), "/dir_to_readlink/long_readlink"); - EXPECT_EQ(0, ret); - memset(buf, 0 ,sizeof(buf)); - ret = readlink(fs, "/dir_to_readlink/long_readlink", buf, sizeof(buf)); - EXPECT_EQ(long_name.length() + 1, ret); - EXPECT_EQ(0, strncmp(long_name.c_str(), buf, ret-1)); - memset(buf, 0 ,sizeof(buf)); - ret = readlink(fs, "/dir_to_readlink/long_readlink", buf, 128); - EXPECT_EQ(128, ret); - EXPECT_EQ(0, strncmp(long_name.c_str(), buf, ret-1)); - - memset(buf, 0 ,sizeof(buf)); - ret = readlink(fs, "/dir_to_readlink/long_readlink_1", buf, sizeof(buf)); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOENT, errno); - ret = link(fs, "/file_to_readlink", "/dir_to_readlink/link"); - EXPECT_EQ(0, ret); - memset(buf, 0 ,sizeof(buf)); - ret = readlink(fs, "/dir_to_readlink/link", buf, sizeof(buf)); - EXPECT_EQ(-1, ret); - EXPECT_EQ(EINVAL, errno); -} - -TEST_F(ExtfsTest, Statfs) { - struct statvfs statv = {0}; - auto ret = fs->statvfs("/test_statfs", &statv); - EXPECT_EQ(0, ret); - EXPECT_EQ(4096, statv.f_bsize); - - memset(&statv, 0, sizeof(struct statvfs)); - ret = fs->statvfs(nullptr, &statv); - EXPECT_EQ(0, ret); - EXPECT_EQ(4096, statv.f_bsize); - - struct statfs stat = {0}; - ret = fs->statfs("/test_statfs", &stat); - EXPECT_EQ(0, ret); - EXPECT_EQ(4096, stat.f_bsize); -} - -TEST_F(ExtfsTest, Access) { - auto file = fs->creat("/test_access", 0755); - EXPECT_NE(nullptr, file); - delete file; - auto ret = access(fs, "/test_access", 0755); - EXPECT_EQ(0, ret); - ret = access(fs, "/test_access", 0700); - EXPECT_EQ(0, ret); - ret = access(fs, "/test_access", 0050); - EXPECT_EQ(0, ret); - ret = access(fs, "/test_access", 0070); - EXPECT_EQ(-1, ret); - EXPECT_EQ(EACCES, errno); - ret = access(fs, "/test_access", 0); - EXPECT_EQ(0, ret); - - ret = chmod(fs, "/test_access", 0644); - EXPECT_EQ(0, ret); - ret = access(fs, "/test_access", 0700); - EXPECT_EQ(-1, ret); - EXPECT_EQ(EACCES, errno); - ret = access(fs, "/test_access_1", 0); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOENT, errno); -} - -TEST_F(ExtfsTest, Truncate) { - auto file = fs->creat("/test_truncate", 0755); - EXPECT_NE(nullptr, file); - delete file; - - struct stat st; - auto ret = stat(fs, "/test_truncate", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(0, st.st_size); - - ret = fs->truncate("/test_truncate", 2048); - EXPECT_EQ(0, ret); - ret = stat(fs, "/test_truncate", &st); - EXPECT_EQ(0, ret); - EXPECT_EQ(2048, st.st_size); - - file = fs->open("/test_truncate", O_RDWR, 0); - EXPECT_NE(nullptr, file); - ret = file->ftruncate(1024); - EXPECT_EQ(0, ret); - ret = file->fstat(&st); - EXPECT_EQ(0, ret); - EXPECT_EQ(1024, st.st_size); - delete file; - - file = fs->open("/test_truncate", O_RDONLY, 0); - EXPECT_NE(nullptr, file); - ret = file->ftruncate(4096); - EXPECT_EQ(-1, ret); - EXPECT_EQ(EBADF, errno); - delete file; - ret = fs->truncate("/test_truncate_1", 2048); - EXPECT_EQ(-1, ret); - EXPECT_EQ(ENOENT, errno); -} - -TEST_F(ExtfsTest, Sync) { - auto file = fs->creat("/test_sync", 0755); - EXPECT_NE(nullptr, file); - delete file; - - auto ret = fs->syncfs(); - EXPECT_EQ(0, ret); - - file = fs->open("/test_sync", O_RDWR, 0); - ret = file->fsync(); - EXPECT_EQ(0, ret); - ret = write_file(file); - EXPECT_EQ(0, ret); - ret = file->fdatasync(); - EXPECT_EQ(0, ret); - delete file; - - file = fs->open("/test_sync", O_RDONLY, 0); - ret = file->fsync(); - EXPECT_EQ(-1, ret); - EXPECT_EQ(EBADF, errno); - delete file; - - ret = fs->syncfs(); - EXPECT_EQ(0, ret); -} - -int main(int argc, char **argv) { - photon::init(photon::INIT_EVENT_DEFAULT, photon::INIT_IO_DEFAULT); - DEFER(photon::fini();); - set_log_output_level(1); - - ::testing::InitGoogleTest(&argc, argv); - auto ret = RUN_ALL_TESTS(); - if (ret) LOG_ERROR_RETURN(0, ret, VALUE(ret)); -} diff --git a/src/overlaybd/tar/header.cpp b/src/overlaybd/tar/header.cpp index 7db5831c..3d704a1b 100644 --- a/src/overlaybd/tar/header.cpp +++ b/src/overlaybd/tar/header.cpp @@ -13,9 +13,10 @@ #include #include #include -#include +#include #include #include +#include /* * In place, rewrite name to compress multiple /, eliminate ., and process .. @@ -313,7 +314,7 @@ int PaxHeader::read_pax(size_t size) { return -1; std::string key = record.substr(0, pos); std::string value = record.substr(pos + 1); - LOG_DEBUG(VALUE(key.c_str()), VALUE(value.c_str())); + LOG_DEBUG(VALUE(key), VALUE(value)); records[key] = value; start += len; } @@ -324,13 +325,19 @@ int PaxHeader::read_pax(size_t size) { int PaxHeader::parse_pax_records() { // TODO: support more pax type for (auto rec : records) { - LOG_DEBUG("`->`", rec.first.c_str(), rec.second.c_str()); + LOG_DEBUG("`->`", rec.first, rec.second); if (rec.first == PAX_SIZE) { size = std::stol(rec.second); } else if (rec.first == PAX_PATH) { path = strdup(rec.second.data()); } else if (rec.first == PAX_LINKPATH) { linkpath = strdup(rec.second.data()); + } else if (estring_view(rec.first).starts_with(PAX_SCHILY_XATTR_PREFIX)) { + LOG_DEBUG("found pax record with 'SCHILY.xattr.' prefix: `", rec.first); + } else if (estring_view(rec.first).starts_with(PAX_GNU_SPARSE_PREFIX)) { + LOG_WARN("found and ignored pax record with 'GNU.sparse.' prefix: `", rec.first); + } else { + LOG_WARN("found and ignored unknown pax record: `", rec.first); } } return 0; diff --git a/src/overlaybd/tar/libtar.cpp b/src/overlaybd/tar/libtar.cpp index 9e06bc71..0c814ed5 100644 --- a/src/overlaybd/tar/libtar.cpp +++ b/src/overlaybd/tar/libtar.cpp @@ -26,9 +26,10 @@ #include #include #include +#include #include +#include #include -#include #include #include "../lsmt/file.h" #include "../lsmt/index.h" @@ -48,6 +49,33 @@ int UnTar::set_file_perms(const char *filename) { } } + /* change xattrs */ + if (xattr_fs && pax && !pax->records.empty()) { + std::string prefix(PAX_SCHILY_XATTR_PREFIX); + for (auto &rec : pax->records) { + if (estring_view(rec.first).starts_with(prefix)) { + auto name = rec.first.substr(prefix.size()); + auto value = rec.second; + LOG_DEBUG(VALUE(name), VALUE(value), VALUE(value.size())); + if (xattr_fs->lsetxattr(filename, name.c_str(), value.c_str(), value.size(), 0) == -1) { + ERRNO eno; + if (eno.no == EPERM && estring_view(name).starts_with("user.")) { + // In the user.* namespace, only regular files and directories can have extended attributes. + // See https://man7.org/linux/man-pages/man7/xattr.7.html for details. + if (!TH_ISREG(header) && !TH_ISDIR(header)) { + LOG_WARN("ignored xattr '`' in archive ", name, VALUE(eno)); + continue; + } + } else if (eno.no == ENOTSUP) { + LOG_WARN("ignored xattr '`' in archive ", name, VALUE(eno)); + continue; + } + LOG_ERRNO_RETURN(eno.no, -1, "lsetxattr failed, filename `, name `, value `", filename, name, value); + } + } + } + } + /* change access/modification time */ if (fs->lutimes(filename, tv) == -1) { LOG_ERRNO_RETURN(0, -1, "lutimes failed, filename `", filename); diff --git a/src/overlaybd/tar/libtar.h b/src/overlaybd/tar/libtar.h index 4222d6ab..5f769f32 100644 --- a/src/overlaybd/tar/libtar.h +++ b/src/overlaybd/tar/libtar.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -106,6 +107,8 @@ class TarHeader { #define PAX_PATH "path" #define PAX_LINKPATH "linkpath" #define PAX_SIZE "size" +#define PAX_SCHILY_XATTR_PREFIX "SCHILY.xattr." +// not supported #define PAX_UID "uid" #define PAX_GID "gid" #define PAX_UNAME "uname" @@ -113,6 +116,7 @@ class TarHeader { #define PAX_MTIME "mtime" #define PAX_ATIME "atime" #define PAX_CTIME "ctime" +#define PAX_GNU_SPARSE_PREFIX "GNU.sparse." class PaxHeader { public: char *path = nullptr; @@ -170,11 +174,11 @@ class TarCore { int options; uint64_t fs_blocksize; uint64_t fs_blockmask; + PaxHeader *pax = nullptr; private: char *th_pathname = nullptr; char *th_linkname = nullptr; - PaxHeader *pax = nullptr; int read_header_internal(photon::fs::IFile *dump = nullptr); int read_sepcial_file(char *&buf, photon::fs::IFile *dump = nullptr); @@ -183,10 +187,15 @@ class TarCore { class UnTar : public TarCore { public: UnTar(photon::fs::IFile *src_file, photon::fs::IFileSystem *target_fs, int options, - uint64_t fs_blocksize = FS_BLOCKSIZE, photon::fs::IFile *bf = nullptr, - bool meta_only = false, bool from_tar_idx = false) - : TarCore(src_file, options, fs_blocksize), fs(target_fs), - fs_base_file(bf), meta_only(meta_only), from_tar_idx(from_tar_idx){} + uint64_t fs_blocksize = FS_BLOCKSIZE, photon::fs::IFile *bf = nullptr, + bool meta_only = false, bool from_tar_idx = false) + : TarCore(src_file, options, fs_blocksize), fs(target_fs), + fs_base_file(bf), meta_only(meta_only), from_tar_idx(from_tar_idx) { + xattr_fs = dynamic_cast(target_fs); + if (!xattr_fs) { + LOG_WARN("xattr is not supported by target fs"); + } + } int extract_all(); // return number of objects in this tarfile @@ -194,6 +203,7 @@ class UnTar : public TarCore { private: photon::fs::IFileSystem *fs = nullptr; // target + photon::fs::IFileSystemXAttr *xattr_fs = nullptr; photon::fs::IFile *fs_base_file = nullptr; bool meta_only = false; bool from_tar_idx = false; diff --git a/src/overlaybd/tar/test/CMakeLists.txt b/src/overlaybd/tar/test/CMakeLists.txt index b96ac109..21499419 100644 --- a/src/overlaybd/tar/test/CMakeLists.txt +++ b/src/overlaybd/tar/test/CMakeLists.txt @@ -7,7 +7,7 @@ link_directories($ENV{GTEST}/lib) add_executable(untar_test test.cpp) target_include_directories(untar_test PUBLIC ${PHOTON_INCLUDE_DIR}) target_link_libraries(untar_test gtest gtest_main pthread photon_static - tar_lib extfs_lib lsmt_lib gzip_lib gzindex_lib checksum_lib) + tar_lib lsmt_lib gzip_lib gzindex_lib checksum_lib) add_test( NAME untar_test diff --git a/src/overlaybd/tar/test/test.cpp b/src/overlaybd/tar/test/test.cpp index a9d85388..70dc9b49 100644 --- a/src/overlaybd/tar/test/test.cpp +++ b/src/overlaybd/tar/test/test.cpp @@ -19,11 +19,11 @@ #include #include #include +#include #include #include #include #include "../../gzindex/gzfile.h" -#include "../../extfs/extfs.h" #include "../../lsmt/file.h" #include "../libtar.h" #include "../tar_file.cpp" @@ -382,4 +382,4 @@ int main(int argc, char **argv) { (void)ret; return 0; -} \ No newline at end of file +} diff --git a/src/tools/comm_func.cpp b/src/tools/comm_func.cpp index 8be821c7..fe50913e 100644 --- a/src/tools/comm_func.cpp +++ b/src/tools/comm_func.cpp @@ -19,7 +19,7 @@ #include #include #include -#include "../overlaybd/extfs/extfs.h" +#include #include "../image_service.h" #include "../image_file.h" diff --git a/src/tools/overlaybd-apply.cpp b/src/tools/overlaybd-apply.cpp index 54fe5a34..81010c37 100644 --- a/src/tools/overlaybd-apply.cpp +++ b/src/tools/overlaybd-apply.cpp @@ -18,11 +18,11 @@ #include #include #include +#include #include #include "../overlaybd/lsmt/file.h" #include "../overlaybd/zfile/zfile.h" #include "../overlaybd/tar/libtar.h" -#include "../overlaybd/extfs/extfs.h" #include "../overlaybd/gzindex/gzfile.h" #include "../overlaybd/gzip/gz.h" #include diff --git a/src/tools/overlaybd-create.cpp b/src/tools/overlaybd-create.cpp index 51d6221b..ffa7dda5 100644 --- a/src/tools/overlaybd-create.cpp +++ b/src/tools/overlaybd-create.cpp @@ -24,9 +24,9 @@ #include #include #include "../overlaybd/lsmt/file.h" -#include "../overlaybd/extfs/extfs.h" #include #include +#include #include #include #include "CLI11.hpp" diff --git a/src/tools/turboOCI-apply.cpp b/src/tools/turboOCI-apply.cpp index 41c82b42..9ef63366 100644 --- a/src/tools/turboOCI-apply.cpp +++ b/src/tools/turboOCI-apply.cpp @@ -18,11 +18,11 @@ #include #include #include +#include #include #include "../overlaybd/lsmt/file.h" #include "../overlaybd/zfile/zfile.h" #include "../overlaybd/tar/libtar.h" -#include "../overlaybd/extfs/extfs.h" #include "../overlaybd/gzindex/gzfile.h" #include "../overlaybd/gzip/gz.h" #include