commit 2d16528ac4c7e123107b164260ef47fb8474e0df Author: Launchcore Date: Thu Nov 6 10:49:44 2025 +0800 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..62a519b --- /dev/null +++ b/.gitignore @@ -0,0 +1,182 @@ +build/ + +### C++ ### +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +### CLion ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### CLion Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +# Azure Toolkit for IntelliJ plugin +# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij +.idea/**/azureSettings.xml + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide diff --git a/2330110900+张顾皓+2330110878+刘蕊菁_操作系统课程设计答辩记录.docx b/2330110900+张顾皓+2330110878+刘蕊菁_操作系统课程设计答辩记录.docx new file mode 100644 index 0000000..ac75b48 Binary files /dev/null and b/2330110900+张顾皓+2330110878+刘蕊菁_操作系统课程设计答辩记录.docx differ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..844ba10 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,56 @@ +cmake_minimum_required(VERSION 3.10) +project(SimpleFS CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +# Set include directory +include_directories(include) + +# mkfs.simplefs executable +add_executable(mkfs.simplefs + tools/mkfs.cpp + src/disk_io.cpp + src/utils.cpp +) +target_link_libraries(mkfs.simplefs PRIVATE m) + +# fsck.simplefs executable +add_executable(fsck.simplefs + tools/fsck.cpp + src/disk_io.cpp + src/utils.cpp +) +target_link_libraries(fsck.simplefs PRIVATE m) + + +# SimpleFS FUSE daemon +find_package(PkgConfig REQUIRED) +pkg_check_modules(FUSE REQUIRED fuse) +include_directories(${FUSE_INCLUDE_DIRS}) +link_directories(${FUSE_LIBRARY_DIRS}) +add_executable(simplefs + src/main.cpp + src/fuse_ops.cpp + src/disk_io.cpp + src/metadata.cpp + src/utils.cpp +) +target_link_libraries(simplefs PRIVATE ${FUSE_LIBRARIES}) +# Add required FUSE definitions specifically for simplefs target +target_compile_definitions(simplefs PRIVATE _FILE_OFFSET_BITS=64 FUSE_USE_VERSION=29) + + +# Enable warnings +if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -g") +endif() + +# Remove global add_definitions for FUSE if they were here, now target-specific + +message(STATUS "Project SimpleFS configured (mkfs.simplefs only)") +message(STATUS "CXX Standard: ${CMAKE_CXX_STANDARD}") +message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") +message(STATUS "Compiler: ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_VERSION}") +message(STATUS "Source directory: ${CMAKE_SOURCE_DIR}") +message(STATUS "Binary directory: ${CMAKE_BINARY_DIR}") diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..c520026 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,10 @@ +{ + "version": 4, + "configurePresets": [ + { + "name": "default", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build" + } + ] +} diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..88c2043 --- /dev/null +++ b/build.sh @@ -0,0 +1,10 @@ +#!/bin/bash +cmake --preset default +cd build +ninja +if [ $? -eq 0 ]; then + echo "Build successful!" +else + echo "Build failed!" + exit 1 +fi \ No newline at end of file diff --git a/include/disk_io.h b/include/disk_io.h new file mode 100644 index 0000000..af002d3 --- /dev/null +++ b/include/disk_io.h @@ -0,0 +1,16 @@ +#pragma once + +#include "simplefs.h" +#include +#include + +using DeviceFd = int; + +// 读取单个块 +int read_block(DeviceFd fd, uint32_t block_num, void* buffer); + +// 写入单个块 +int write_block(DeviceFd fd, uint32_t block_num, const void* buffer); + +// 写入零块 +int write_zero_blocks(DeviceFd fd, uint32_t start_block_num, uint32_t count); diff --git a/include/fuse_ops.h b/include/fuse_ops.h new file mode 100644 index 0000000..c228809 --- /dev/null +++ b/include/fuse_ops.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include "simplefs_context.h" +#include "simplefs.h" + +// 获取文件系统上下文 +SimpleFS_Context* get_fs_context(); + +// FUSE操作实现 +int simplefs_getattr(const char *path, struct stat *stbuf); +int simplefs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, + off_t offset, struct fuse_file_info *fi); +int simplefs_mknod(const char *path, mode_t mode, dev_t rdev); +int simplefs_mkdir(const char *path, mode_t mode); +int simplefs_unlink(const char *path); +int simplefs_rmdir(const char *path); +int simplefs_read(const char *path, char *buf, size_t size, off_t offset, + struct fuse_file_info *fi); +int simplefs_write(const char *path, const char *buf, size_t size, off_t offset, + struct fuse_file_info *fi); +int simplefs_truncate(const char *path, off_t size); +int simplefs_chmod(const char *path, mode_t mode); +int simplefs_chown(const char *path, uid_t uid, gid_t gid); +int simplefs_utimens(const char *path, const struct timespec tv[2]); +int simplefs_access(const char *path, int mask); +int simplefs_statfs(const char *path, struct statvfs *stbuf); +int simplefs_symlink(const char *target, const char *linkpath); +int simplefs_readlink(const char *path, char *buf, size_t size); + +// 初始化FUSE操作结构 +void init_fuse_operations(struct fuse_operations *ops); diff --git a/include/metadata.h b/include/metadata.h new file mode 100644 index 0000000..25f3a6e --- /dev/null +++ b/include/metadata.h @@ -0,0 +1,48 @@ +#pragma once + +#include "simplefs.h" +#include "simplefs_context.h" + +#include +#include +#include + +// inode管理 +uint32_t alloc_inode(SimpleFS_Context& context, mode_t mode); +void free_inode(SimpleFS_Context& context, uint32_t inode_num, mode_t mode_of_freed_inode); + +// 块管理 +uint32_t alloc_block(SimpleFS_Context& context, uint32_t preferred_group_for_inode = static_cast(-1)); +void free_block(SimpleFS_Context& context, uint32_t block_num); + +// inode读写 +int write_inode_to_disk(SimpleFS_Context& context, uint32_t inode_num, const SimpleFS_Inode* inode_data); +int read_inode_from_disk(SimpleFS_Context& context, uint32_t inode_num, SimpleFS_Inode* inode_struct); + +// 目录操作 +int add_dir_entry(SimpleFS_Context& context, SimpleFS_Inode* parent_inode, uint32_t parent_inode_num, + const std::string& entry_name, uint32_t child_inode_num, uint8_t file_type); +int remove_dir_entry(SimpleFS_Context& context, SimpleFS_Inode* parent_inode, uint32_t parent_inode_num, const std::string& entry_name_to_remove); + +// 路径解析 +void parse_path(const std::string& path, std::string& dirname, std::string& basename); + +// 位图操作 +void set_bitmap_bit(std::vector& bitmap_data, uint32_t bit_index); +void clear_bitmap_bit(std::vector& bitmap_data, uint32_t bit_index); +bool is_bitmap_bit_set(const std::vector& bitmap_data, uint32_t bit_index); + +// 元数据同步 +void sync_fs_metadata(SimpleFS_Context& context); + +// 权限检查 +struct fuse_context; +int check_access(const struct fuse_context* caller_context, const SimpleFS_Inode* inode, int requested_perm); + +// 块释放 +void free_all_inode_blocks(SimpleFS_Context& context, SimpleFS_Inode* inode); + +// 块映射 +uint32_t get_or_alloc_dir_block(SimpleFS_Context& context, SimpleFS_Inode* dir_inode, uint32_t dir_inode_num, uint32_t logical_block_idx); +uint32_t map_logical_to_physical_block(SimpleFS_Context& context, const SimpleFS_Inode* inode, uint32_t logical_block_idx); +void release_logical_block_range(SimpleFS_Context& context, SimpleFS_Inode* inode, uint32_t start_lbn, uint32_t end_lbn); diff --git a/include/simplefs.h b/include/simplefs.h new file mode 100644 index 0000000..ff8a07b --- /dev/null +++ b/include/simplefs.h @@ -0,0 +1,101 @@ +#pragma once + +#include +#include + +#pragma pack(push, 1) + +// 文件系统常量定义 +constexpr uint16_t SIMPLEFS_MAGIC = 0x5350; +constexpr uint32_t SIMPLEFS_BLOCK_SIZE = 4096; +constexpr uint32_t SIMPLEFS_ROOT_INODE_NUM = 2; +constexpr uint32_t SIMPLEFS_INODE_SIZE = 128; +constexpr uint32_t SIMPLEFS_NUM_DIRECT_BLOCKS = 12; +constexpr uint32_t SIMPLEFS_NUM_INDIRECT_BLOCKS = 1; +constexpr uint32_t SIMPLEFS_NUM_D_INDIRECT_BLOCKS = 1; +constexpr uint32_t SIMPLEFS_NUM_T_INDIRECT_BLOCKS = 1; +constexpr uint32_t SIMPLEFS_INODE_BLOCK_PTRS = SIMPLEFS_NUM_DIRECT_BLOCKS + \ + SIMPLEFS_NUM_INDIRECT_BLOCKS + \ + SIMPLEFS_NUM_D_INDIRECT_BLOCKS + \ + SIMPLEFS_NUM_T_INDIRECT_BLOCKS; + +constexpr uint32_t SIMPLEFS_MAX_FILENAME_LEN = 255; + +// 文件类型常量 +#ifndef S_IFMT +#define S_IFMT 0xF000 // 文件类型掩码 +#define S_IFSOCK 0xC000 // 套接字 +#define S_IFLNK 0xA000 // 符号链接 +#define S_IFREG 0x8000 // 普通文件 +#define S_IFBLK 0x6000 // 块设备 +#define S_IFDIR 0x4000 // 目录 +#define S_IFCHR 0x2000 // 字符设备 +#define S_IFIFO 0x1000 // 管道 +#endif + + +// 超级块结构 +struct SimpleFS_SuperBlock { + uint16_t s_magic; // 魔数 + uint32_t s_inodes_count; // 总inode数 + uint32_t s_blocks_count; // 总块数 + uint32_t s_free_blocks_count; // 空闲块数 + uint32_t s_free_inodes_count; // 空闲inode数 + uint32_t s_first_data_block; // 首个数据块 + uint32_t s_log_block_size; // 块大小的对数值 + uint32_t s_blocks_per_group; // 每组块数 + uint32_t s_inodes_per_group; // 每组inode数 + uint32_t s_mtime; // 最后挂载时间 + uint32_t s_wtime; // 最后写入时间 + uint16_t s_mnt_count; // 挂载次数 + uint16_t s_max_mnt_count; // 最大挂载次数 + uint16_t s_state; // 文件系统状态 + uint16_t s_errors; // 错误处理方式 + uint32_t s_first_ino; // 首个非保留inode号 + uint16_t s_inode_size; // inode大小 + uint16_t s_block_group_nr; // 块组号 + uint32_t s_root_inode; // 根inode号 + uint8_t s_padding[962]; // 填充到1024字节 +}; +static_assert(sizeof(SimpleFS_SuperBlock) == 1024, "超级块大小必须为1024字节"); + +// 块组描述符结构 +struct SimpleFS_GroupDesc { + uint32_t bg_block_bitmap; // 块位图块号 + uint32_t bg_inode_bitmap; // inode位图块号 + uint32_t bg_inode_table; // inode表起始块号 + uint16_t bg_free_blocks_count; // 空闲块数 + uint16_t bg_free_inodes_count; // 空闲inode数 + uint16_t bg_used_dirs_count; // 已使用目录数 + uint8_t bg_padding[14]; // 填充到32字节 +}; +static_assert(sizeof(SimpleFS_GroupDesc) == 32, "块组描述符大小必须为32字节"); + +// inode结构 +struct SimpleFS_Inode { + uint16_t i_mode; // 文件模式 + uint16_t i_uid; // 用户ID + uint32_t i_size; // 文件大小 + uint32_t i_atime; // 访问时间 + uint32_t i_ctime; // 创建时间 + uint32_t i_mtime; // 修改时间 + uint32_t i_dtime; // 删除时间 + uint16_t i_gid; // 组ID + uint16_t i_links_count; // 硬链接数 + uint32_t i_blocks; // 块数 + uint32_t i_flags; // 标志 + uint32_t i_block[SIMPLEFS_INODE_BLOCK_PTRS]; // 块指针数组 + uint8_t i_padding[32]; // 填充到128字节 +}; +static_assert(sizeof(SimpleFS_Inode) == 128, "inode大小必须为128字节"); + +// 目录项结构 +struct SimpleFS_DirEntry { + uint32_t inode; // inode号 + uint16_t rec_len; // 记录长度 + uint8_t name_len; // 文件名长度 + uint8_t file_type; // 文件类型 + char name[SIMPLEFS_MAX_FILENAME_LEN + 1]; // 文件名 +}; + +#pragma pack(pop) diff --git a/include/simplefs_context.h b/include/simplefs_context.h new file mode 100644 index 0000000..ba492b6 --- /dev/null +++ b/include/simplefs_context.h @@ -0,0 +1,13 @@ +#pragma once + +#include "simplefs.h" +#include "disk_io.h" +#include +#include + +// 文件系统全局上下文 +struct SimpleFS_Context { + DeviceFd device_fd; + SimpleFS_SuperBlock sb; + std::vector gdt; +}; diff --git a/include/utils.h b/include/utils.h new file mode 100644 index 0000000..10248d9 --- /dev/null +++ b/include/utils.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include +#include "simplefs.h" + +// 位图操作 +void set_bitmap_bit(std::vector& bitmap_data, uint32_t bit_index); +void clear_bitmap_bit(std::vector& bitmap_data, uint32_t bit_index); +bool is_bitmap_bit_set(const std::vector& bitmap_data, uint32_t bit_index); + +// 路径解析 +void parse_path(const std::string& path, std::string& dirname, std::string& basename); + +// 目录项长度计算 +inline uint16_t calculate_dir_entry_len(uint8_t name_len) { + uint16_t len = 8 + name_len; + return (len + 3) & ~3U; +} + +// 设备类型检查 +bool is_block_device(int fd); + +// 块组备份检查 +bool is_backup_group(uint32_t group_index); + diff --git a/src/disk_io.cpp b/src/disk_io.cpp new file mode 100644 index 0000000..c45443e --- /dev/null +++ b/src/disk_io.cpp @@ -0,0 +1,52 @@ +#include "disk_io.h" +#include "simplefs.h" + +#include +#include +#include +#include +#include +#include + +// 读取磁盘块 +int read_block(DeviceFd fd, uint32_t block_num, void* buffer) { + off_t offset = static_cast(block_num) * SIMPLEFS_BLOCK_SIZE; + ssize_t bytes_read = pread(fd, buffer, SIMPLEFS_BLOCK_SIZE, offset); + + if (bytes_read == -1) { + perror("磁盘读取失败"); + return -1; + } + if (bytes_read < SIMPLEFS_BLOCK_SIZE) { + return -1; + } + return 0; +} + +// 写入磁盘块 +int write_block(DeviceFd fd, uint32_t block_num, const void* buffer) { + off_t offset = static_cast(block_num) * SIMPLEFS_BLOCK_SIZE; + ssize_t bytes_written = pwrite(fd, buffer, SIMPLEFS_BLOCK_SIZE, offset); + + if (bytes_written == -1) { + perror("磁盘写入失败"); + return -1; + } + if (bytes_written < SIMPLEFS_BLOCK_SIZE) { + return -1; + } + return 0; +} + +// 批量写入零块 +int write_zero_blocks(DeviceFd fd, uint32_t start_block_num, uint32_t count) { + if (count == 0) return 0; + + std::vector zero_buffer(SIMPLEFS_BLOCK_SIZE, 0); + for (uint32_t i = 0; i < count; ++i) { + if (write_block(fd, start_block_num + i, zero_buffer.data()) != 0) { + return -1; + } + } + return 0; +} diff --git a/src/fuse_ops.cpp b/src/fuse_ops.cpp new file mode 100644 index 0000000..b0a4a47 --- /dev/null +++ b/src/fuse_ops.cpp @@ -0,0 +1,1618 @@ +#include "fuse_ops.h" +#include "disk_io.h" +#include "metadata.h" +#include "utils.h" // 路径解析和目录条目计算 + +#include +#include +#include +#include // S_ISDIR, S_IFMT, mode_t, S_ISUID, S_ISGID +#include // struct statvfs +#include +#include +#include +#include +#include // uid_t, gid_t, getgroups +#include // time_t, time(), timespec +#include // std::vector +#include // perror +#include // DT_REG, DT_DIR, DT_LNK + +// fuse_common.h (由fuse.h包含) 定义FUSE_SYMLINK_MAX +// 如果由于某种原因不可用,定义一个回退值 +#ifndef FUSE_SYMLINK_MAX +#define FUSE_SYMLINK_MAX 40 // 符号链接最大遍历深度 +#endif + + +// 从FUSE获取文件系统上下文的辅助函数 +SimpleFS_Context* get_fs_context() { + return static_cast(fuse_get_context()->private_data); +} + +// 前向声明 +static uint32_t resolve_path_recursive(const char* path_cstr, int depth, bool follow_last_symlink); +static uint32_t path_to_inode_num(const char* path_cstr); // resolve_path_recursive的包装器 + +// static uint32_t map_logical_to_physical_block(SimpleFS_Context& context, const SimpleFS_Inode* inode, uint32_t logical_block_idx); // 已移至metadata.h/cpp +static uint32_t allocate_block_for_write(SimpleFS_Context& context, SimpleFS_Inode* inode, uint32_t inode_num, uint32_t logical_block_idx, bool* p_was_newly_allocated); + + +// 给定路径,返回inode号 +// 这现在是resolve_path_recursive的包装器,用于应该跟随所有符号链接的外部调用 +static uint32_t path_to_inode_num(const char* path_cstr) { + return resolve_path_recursive(path_cstr, 0, true); // 默认:跟随最后的符号链接 +} + +// 递归路径解析函数 +static uint32_t resolve_path_recursive(const char* path_cstr, int depth, bool follow_last_symlink) { + if (depth > FUSE_SYMLINK_MAX) { + errno = ELOOP; + return 0; + } + + SimpleFS_Context* context = get_fs_context(); + if (!context) { + errno = EACCES; + return 0; + } + + std::string path(path_cstr); + if (path.empty()) { + errno = EINVAL; + return 0; + } + + uint32_t current_inode_num; + std::vector components; + + if (path == "/") { + return context->sb.s_root_inode; + } + + std::string path_to_tokenize = (path[0] == '/') ? path.substr(1) : path; + + size_t start = 0; + size_t end = 0; + while ((end = path_to_tokenize.find('/', start)) != std::string::npos) { + if (end != start) { + components.push_back(path_to_tokenize.substr(start, end - start)); + } + start = end + 1; + } + if (start < path_to_tokenize.length()) { + components.push_back(path_to_tokenize.substr(start)); + } + + if (components.empty() && path[0] == '/') { // 应由 path == "/" 处理 + return context->sb.s_root_inode; + } + if (components.empty()) { // 空路径或相对路径错误 + errno = EINVAL; // 无效相对路径 + return 0; + } + + current_inode_num = context->sb.s_root_inode; + + std::string current_path_for_symlink_resolution = "/"; + + for (size_t component_idx = 0; component_idx < components.size(); ++component_idx) { + const auto& component = components[component_idx]; + bool is_last_component = (component_idx == components.size() - 1); + + if (component.empty() || component == ".") { + continue; + } + + SimpleFS_Inode current_dir_inode_data; + if (read_inode_from_disk(*context, current_inode_num, ¤t_dir_inode_data) != 0) { + return 0; + } + + if (!S_ISDIR(current_dir_inode_data.i_mode)) { + errno = ENOTDIR; + return 0; + } + + int access_res = check_access(fuse_get_context(), ¤t_dir_inode_data, X_OK); + if (access_res != 0) { + errno = -access_res; + return 0; + } + + bool found_component_in_dir = false; + uint32_t next_inode_num_candidate = 0; + // SimpleFS_Inode component_inode_data; // 解析组件(文件/目录/符号链接)的数据 + + std::vector dir_data_block_buffer(SIMPLEFS_BLOCK_SIZE); + + // 遍历直接、一级、二级、三级间接块查找目录条目 + + // 搜索直接块 + for (int i = 0; i < SIMPLEFS_NUM_DIRECT_BLOCKS && !found_component_in_dir; ++i) { + uint32_t dir_block_ptr = current_dir_inode_data.i_block[i]; + if (dir_block_ptr == 0) continue; + if (read_block(context->device_fd, dir_block_ptr, dir_data_block_buffer.data()) != 0) { errno = EIO; return 0; } + uint16_t entry_offset = 0; + uint32_t block_start_offset_in_file = i * SIMPLEFS_BLOCK_SIZE; + uint32_t effective_size_in_this_block = (current_dir_inode_data.i_size > block_start_offset_in_file) ? + std::min((uint32_t)SIMPLEFS_BLOCK_SIZE, current_dir_inode_data.i_size - block_start_offset_in_file) : 0; + if (effective_size_in_this_block == 0 && i > 0 && current_dir_inode_data.i_size <= block_start_offset_in_file) continue; + + while (entry_offset < effective_size_in_this_block) { + SimpleFS_DirEntry* entry = reinterpret_cast(dir_data_block_buffer.data() + entry_offset); + if (entry->rec_len == 0 || (calculate_dir_entry_len(entry->name_len) > entry->rec_len) || (entry_offset + entry->rec_len > effective_size_in_this_block)) break; + if (entry->inode != 0 && entry->name_len == component.length() && strncmp(entry->name, component.c_str(), entry->name_len) == 0) { + next_inode_num_candidate = entry->inode; + found_component_in_dir = true; + break; + } + entry_offset += entry->rec_len; + } + } + // 搜索一级间接块 + if (!found_component_in_dir) { + uint32_t single_indirect_block_ptr = current_dir_inode_data.i_block[SIMPLEFS_NUM_DIRECT_BLOCKS]; + if (single_indirect_block_ptr != 0) { + std::vector indirect_block_content(SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t)); + if (read_block(context->device_fd, single_indirect_block_ptr, indirect_block_content.data()) == 0) { + for (uint32_t k = 0; k < (SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t)) && !found_component_in_dir; ++k) { + uint32_t data_block_ptr = indirect_block_content[k]; + if (data_block_ptr == 0) continue; + if (read_block(context->device_fd, data_block_ptr, dir_data_block_buffer.data()) != 0) { errno = EIO; return 0; } + uint16_t entry_offset = 0; + uint32_t logical_block_idx = SIMPLEFS_NUM_DIRECT_BLOCKS + k; + uint32_t block_start_offset_in_file = logical_block_idx * SIMPLEFS_BLOCK_SIZE; + uint32_t effective_size_in_this_block = (current_dir_inode_data.i_size > block_start_offset_in_file) ? + std::min((uint32_t)SIMPLEFS_BLOCK_SIZE, current_dir_inode_data.i_size - block_start_offset_in_file) : 0; + if(effective_size_in_this_block == 0 && current_dir_inode_data.i_size <= block_start_offset_in_file) continue; + while (entry_offset < effective_size_in_this_block) { + SimpleFS_DirEntry* entry = reinterpret_cast(dir_data_block_buffer.data() + entry_offset); + if (entry->rec_len == 0 || (calculate_dir_entry_len(entry->name_len) > entry->rec_len) || (entry_offset + entry->rec_len > effective_size_in_this_block) ) break; + if (entry->inode != 0 && entry->name_len == component.length() && strncmp(entry->name, component.c_str(), entry->name_len) == 0) { + next_inode_num_candidate = entry->inode; found_component_in_dir = true; break; + } + entry_offset += entry->rec_len; + } + } + } + } + } + // 搜索二级间接块 + if (!found_component_in_dir) { + uint32_t dbl_indirect_block_ptr = current_dir_inode_data.i_block[SIMPLEFS_NUM_DIRECT_BLOCKS + 1]; + if (dbl_indirect_block_ptr != 0) { + std::vector dbl_indirect_content(SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t)); + if (read_block(context->device_fd, dbl_indirect_block_ptr, dbl_indirect_content.data()) == 0) { + for (uint32_t l1_idx = 0; l1_idx < (SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t)) && !found_component_in_dir; ++l1_idx) { + uint32_t single_indirect_ptr = dbl_indirect_content[l1_idx]; + if (single_indirect_ptr == 0) continue; + std::vector single_indirect_content(SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t)); + if (read_block(context->device_fd, single_indirect_ptr, single_indirect_content.data()) == 0) { + for (uint32_t l2_idx = 0; l2_idx < (SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t)) && !found_component_in_dir; ++l2_idx) { + uint32_t data_block_ptr = single_indirect_content[l2_idx]; + if (data_block_ptr == 0) continue; + if (read_block(context->device_fd, data_block_ptr, dir_data_block_buffer.data()) != 0) { errno = EIO; return 0; } + uint16_t entry_offset = 0; + uint32_t logical_block_idx = SIMPLEFS_NUM_DIRECT_BLOCKS + (SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t)) + (l1_idx * (SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t))) + l2_idx; // 取消注释 + uint32_t block_start_offset_in_file = logical_block_idx * SIMPLEFS_BLOCK_SIZE; + uint32_t effective_size_in_this_block = (current_dir_inode_data.i_size > block_start_offset_in_file ) ? + std::min((uint32_t)SIMPLEFS_BLOCK_SIZE, (uint32_t)(current_dir_inode_data.i_size - block_start_offset_in_file) ) : 0; + if(effective_size_in_this_block == 0 && current_dir_inode_data.i_size <= block_start_offset_in_file) continue; + while (entry_offset < effective_size_in_this_block) { + SimpleFS_DirEntry* entry = reinterpret_cast(dir_data_block_buffer.data() + entry_offset); + if (entry->rec_len == 0 || (calculate_dir_entry_len(entry->name_len) > entry->rec_len) || (entry_offset + entry->rec_len > effective_size_in_this_block) ) break; + if (entry->inode != 0 && entry->name_len == component.length() && strncmp(entry->name, component.c_str(), entry->name_len) == 0) { + next_inode_num_candidate = entry->inode; found_component_in_dir = true; break; + } + entry_offset += entry->rec_len; + } + } + } + } + } + } + } + // 搜索三级间接块 + if (!found_component_in_dir) { + uint32_t tpl_indirect_block_ptr = current_dir_inode_data.i_block[SIMPLEFS_NUM_DIRECT_BLOCKS + 2]; + if (tpl_indirect_block_ptr != 0) { + std::vector tpl_indirect_content(SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t)); + if (read_block(context->device_fd, tpl_indirect_block_ptr, tpl_indirect_content.data()) == 0) { + for (uint32_t l0_idx = 0; l0_idx < (SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t)) && !found_component_in_dir; ++l0_idx) { + uint32_t dbl_indirect_ptr_from_tpl = tpl_indirect_content[l0_idx]; + if (dbl_indirect_ptr_from_tpl == 0) continue; + std::vector dbl_indirect_content_via_tpl(SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t)); + if (read_block(context->device_fd, dbl_indirect_ptr_from_tpl, dbl_indirect_content_via_tpl.data()) == 0) { + for (uint32_t l1_idx = 0; l1_idx < (SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t)) && !found_component_in_dir; ++l1_idx) { + uint32_t sgl_indirect_ptr_from_dbl = dbl_indirect_content_via_tpl[l1_idx]; + if (sgl_indirect_ptr_from_dbl == 0) continue; + std::vector sgl_indirect_content_via_dbl_tpl(SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t)); + if (read_block(context->device_fd, sgl_indirect_ptr_from_dbl, sgl_indirect_content_via_dbl_tpl.data()) == 0) { + for (uint32_t l2_idx = 0; l2_idx < (SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t)) && !found_component_in_dir; ++l2_idx) { + uint32_t data_block_ptr = sgl_indirect_content_via_dbl_tpl[l2_idx]; + if (data_block_ptr == 0) continue; + if (read_block(context->device_fd, data_block_ptr, dir_data_block_buffer.data()) != 0) { errno = EIO; return 0; } + uint16_t entry_offset = 0; + uint32_t tpl_logical_block_idx = SIMPLEFS_NUM_DIRECT_BLOCKS + (SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t)) + ((SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t)) * (SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t))) + (l0_idx * (SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t)) * (SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t))) + (l1_idx * (SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t))) + l2_idx; + uint32_t tpl_block_start_offset_in_file = tpl_logical_block_idx * SIMPLEFS_BLOCK_SIZE; + uint32_t effective_size_in_this_block = (current_dir_inode_data.i_size > tpl_block_start_offset_in_file) ? + std::min((uint32_t)SIMPLEFS_BLOCK_SIZE, current_dir_inode_data.i_size - tpl_block_start_offset_in_file) : 0; + if(effective_size_in_this_block == 0 && current_dir_inode_data.i_size <= tpl_block_start_offset_in_file) continue; + while (entry_offset < effective_size_in_this_block) { + SimpleFS_DirEntry* entry = reinterpret_cast(dir_data_block_buffer.data() + entry_offset); + if (entry->rec_len == 0 || (calculate_dir_entry_len(entry->name_len) > entry->rec_len) || (entry_offset + entry->rec_len > effective_size_in_this_block) ) break; + if (entry->inode != 0 && entry->name_len == component.length() && strncmp(entry->name, component.c_str(), entry->name_len) == 0) { + next_inode_num_candidate = entry->inode; found_component_in_dir = true; break; + } + entry_offset += entry->rec_len; + } + } + } + } + } + } + } + } + } + + if (!found_component_in_dir) { + errno = ENOENT; + return 0; + } + + SimpleFS_Inode component_inode_data; // 解析组件的数据 + if (read_inode_from_disk(*context, next_inode_num_candidate, &component_inode_data) != 0) { + std::cerr << "无法读取inode " << next_inode_num_candidate + << " 组件: \"" << component << "\"" << std::endl; + return 0; + } + + std::string component_path_part = component; + if (component == "..") { + if (current_path_for_symlink_resolution.length() > 1) { // 非根目录 + size_t last_slash = current_path_for_symlink_resolution.find_last_of('/'); + if (last_slash == 0) current_path_for_symlink_resolution = "/"; // 父目录是根目录 + else if (last_slash != std::string::npos) current_path_for_symlink_resolution.erase(last_slash); + } + } else if (component != ".") { + if (current_path_for_symlink_resolution.length() > 1) current_path_for_symlink_resolution += "/"; + current_path_for_symlink_resolution += component; + } + + if (S_ISLNK(component_inode_data.i_mode)) { + if (is_last_component && !follow_last_symlink) { + return next_inode_num_candidate; + } + + char target_path_buf[SIMPLEFS_BLOCK_SIZE]; + std::memset(target_path_buf, 0, sizeof(target_path_buf)); + + std::string target_path_str; + if (component_inode_data.i_blocks == 0) { + // 快速符号链接:数据存储在i_block数组中 + if (component_inode_data.i_size > sizeof(component_inode_data.i_block)) { + std::cerr << "快速符号链接大小超出存储空间" << std::endl; + errno = EIO; return 0; + } + std::memcpy(target_path_buf, component_inode_data.i_block, component_inode_data.i_size); + target_path_buf[component_inode_data.i_size] = '\0'; + target_path_str = target_path_buf; + } else { + // 传统符号链接存储在块中 + if (component_inode_data.i_size == 0 || component_inode_data.i_block[0] == 0) { + std::cerr << "符号链接inode " << next_inode_num_candidate << " 大小为零或无数据块" << std::endl; + errno = EIO; return 0; + } + if (read_block(context->device_fd, component_inode_data.i_block[0], target_path_buf) != 0) { + std::cerr << "无法读取inode " << next_inode_num_candidate << " 的符号链接目标数据块" << std::endl; + errno = EIO; return 0; + } + target_path_buf[std::min((size_t)SIMPLEFS_BLOCK_SIZE -1, (size_t)component_inode_data.i_size)] = '\0'; + target_path_str = target_path_buf; + } + + std::string next_resolve_path_str; + if (target_path_str[0] == '/') { + next_resolve_path_str = target_path_str; + } else { + std::string base_dir = current_path_for_symlink_resolution; + // 从current_path_for_symlink_resolution中删除当前组件以获取链接的目录 + if (base_dir.length() > component_path_part.length()) { + size_t pos = base_dir.rfind(component_path_part); + if (pos != std::string::npos && pos > 0 && base_dir[pos-1] == '/') { + base_dir.erase(pos-1); // 移除组件和尾随斜杠 + } else if (pos == 0 && base_dir == "/" + component_path_part) { // 如 /link + base_dir = "/"; + } + } + if (base_dir.empty()) base_dir = "/"; // 逻辑错误时不应发生 + + if (base_dir.length() > 1 && base_dir.back() == '/') { + next_resolve_path_str = base_dir + target_path_str; + } else if (base_dir == "/") { + next_resolve_path_str = "/" + target_path_str; + } else { + next_resolve_path_str = base_dir + "/" + target_path_str; + } + } + + std::string remaining_path_components; + if (!is_last_component) { + for (size_t k = component_idx + 1; k < components.size(); ++k) { + remaining_path_components += "/"; + remaining_path_components += components[k]; + } + } + if (!remaining_path_components.empty()) { + if (next_resolve_path_str.back() == '/') next_resolve_path_str.pop_back(); + next_resolve_path_str += remaining_path_components; + } + return resolve_path_recursive(next_resolve_path_str.c_str(), depth + 1, follow_last_symlink); + } + current_inode_num = next_inode_num_candidate; + if (is_last_component) { + return current_inode_num; + } + } + return current_inode_num; +} + +// 获取文件属性 +int simplefs_getattr(const char *path, struct stat *stbuf) { + std::memset(stbuf, 0, sizeof(struct stat)); + SimpleFS_Context* context = get_fs_context(); + if (!context) return -EACCES; + errno = 0; + uint32_t inode_num = resolve_path_recursive(path, 0, false); + if (inode_num == 0) return -errno; + SimpleFS_Inode inode; + if (read_inode_from_disk(*context, inode_num, &inode) != 0) return -errno; + stbuf->st_ino = inode_num; + stbuf->st_mode = inode.i_mode; + stbuf->st_nlink = inode.i_links_count; + stbuf->st_uid = inode.i_uid; + stbuf->st_gid = inode.i_gid; + stbuf->st_size = inode.i_size; + stbuf->st_blocks = inode.i_blocks; + stbuf->st_atime = inode.i_atime; + stbuf->st_mtime = inode.i_mtime; + stbuf->st_ctime = inode.i_ctime; + return 0; +} + +// 读取目录内容 +int simplefs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, + off_t offset, struct fuse_file_info *fi) { + (void) offset; (void) fi; + SimpleFS_Context* context = get_fs_context(); + if (!context) return -EACCES; + errno = 0; + uint32_t dir_inode_num = path_to_inode_num(path); + if (dir_inode_num == 0) return -errno; + SimpleFS_Inode dir_inode; + if (read_inode_from_disk(*context, dir_inode_num, &dir_inode) != 0) return -errno; + if (!S_ISDIR(dir_inode.i_mode)) return -ENOTDIR; + + std::vector block_buffer(SIMPLEFS_BLOCK_SIZE); + uint32_t total_bytes_iterated = 0; + + auto process_dir_block = [&](uint32_t data_block_num) { + if (read_block(context->device_fd, data_block_num, block_buffer.data()) != 0) return -EIO; + uint16_t entry_offset = 0; + uint32_t current_block_bytes_processed = 0; + + while(total_bytes_iterated < dir_inode.i_size && current_block_bytes_processed < SIMPLEFS_BLOCK_SIZE) { + SimpleFS_DirEntry* entry = reinterpret_cast(block_buffer.data() + entry_offset); + if (entry->rec_len == 0 || (calculate_dir_entry_len(entry->name_len) > entry->rec_len) || (entry_offset + entry->rec_len > SIMPLEFS_BLOCK_SIZE) ) { + break; + } + if (entry->inode != 0 && entry->name_len > 0) { + std::string filename(entry->name, entry->name_len); + struct stat st_entry; std::memset(&st_entry, 0, sizeof(struct stat)); + st_entry.st_ino = entry->inode; + + SimpleFS_Inode temp_inode_for_type; + if(read_inode_from_disk(*context, entry->inode, &temp_inode_for_type) == 0) { + st_entry.st_mode = temp_inode_for_type.i_mode; // 获取完整模式 + } else { + st_entry.st_mode = (entry->file_type << 12); // 从目录条目获取类型 + } + + if (filler(buf, filename.c_str(), &st_entry, 0) != 0) return -ENOMEM; + } + entry_offset += entry->rec_len; + current_block_bytes_processed += entry->rec_len; + total_bytes_iterated += entry->rec_len; + if(entry_offset >= SIMPLEFS_BLOCK_SIZE) break; + } + return 0; + }; + + // 遍历所有块级别 + uint32_t lbn = 0; + while(total_bytes_iterated < dir_inode.i_size) { + uint32_t physical_block = map_logical_to_physical_block(*context, &dir_inode, lbn); + if (physical_block == 0) { // 目录i_size正确时不应发生 + if (total_bytes_iterated >= dir_inode.i_size) break; // 到达末尾 + lbn++; continue; // 目录中的稀疏块或错误 + } + int res = process_dir_block(physical_block); + if (res != 0) return res; + if (total_bytes_iterated >= dir_inode.i_size) break; // 基于i_size确保循环终止 + lbn++; + if (lbn > (dir_inode.i_size / SIMPLEFS_BLOCK_SIZE) + SIMPLEFS_INODE_BLOCK_PTRS*1024*1024) { // 极端情况安全退出 + std::cerr << "目录 " << dir_inode_num << " LBN过大,可能出现无限循环" << std::endl; + return -EIO; + } + } + return 0; +} + +// FUSE操作函数 +int simplefs_getattr(const char *path, struct stat *stbuf); +int simplefs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi); +int simplefs_mknod(const char *path, mode_t mode, dev_t rdev); +int simplefs_mkdir(const char *path, mode_t mode); +int simplefs_unlink(const char *path); +int simplefs_rmdir(const char *path); +int simplefs_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi); +int simplefs_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi); +int simplefs_truncate(const char *path, off_t size); +int simplefs_chmod(const char *path, mode_t mode); +int simplefs_chown(const char *path, uid_t uid, gid_t gid); +int simplefs_utimens(const char *path, const struct timespec tv[2]); +int simplefs_statfs(const char *path, struct statvfs *stbuf); +int simplefs_access(const char *path, int mask); +int simplefs_symlink(const char *target, const char *linkpath); +int simplefs_readlink(const char *path, char *buf, size_t size); +int simplefs_link(const char *oldpath, const char *newpath); + + +// 初始化fuse_operations结构体 +void init_fuse_operations(struct fuse_operations *ops) { + std::memset(ops, 0, sizeof(struct fuse_operations)); + ops->getattr = simplefs_getattr; + ops->readdir = simplefs_readdir; + ops->mknod = simplefs_mknod; + ops->mkdir = simplefs_mkdir; + ops->unlink = simplefs_unlink; + ops->rmdir = simplefs_rmdir; + ops->read = simplefs_read; + ops->write = simplefs_write; + ops->truncate = simplefs_truncate; + ops->chmod = simplefs_chmod; + ops->chown = simplefs_chown; + ops->utimens = simplefs_utimens; + ops->statfs = simplefs_statfs; + ops->access = simplefs_access; + ops->symlink = simplefs_symlink; + ops->readlink = simplefs_readlink; + ops->link = simplefs_link; +} + +// 文件系统统计 +int simplefs_statfs(const char *path, struct statvfs *stbuf) { + (void)path; + SimpleFS_Context* context = get_fs_context(); + if (!context) return -EACCES; + std::memset(stbuf, 0, sizeof(struct statvfs)); + stbuf->f_bsize = SIMPLEFS_BLOCK_SIZE; + stbuf->f_frsize = SIMPLEFS_BLOCK_SIZE; + stbuf->f_blocks = context->sb.s_blocks_count; + stbuf->f_bfree = context->sb.s_free_blocks_count; + stbuf->f_bavail = context->sb.s_free_blocks_count; + stbuf->f_files = context->sb.s_inodes_count; + stbuf->f_ffree = context->sb.s_free_inodes_count; + stbuf->f_favail = context->sb.s_free_inodes_count; + stbuf->f_fsid = 0; + stbuf->f_flag = 0; + stbuf->f_namemax = SIMPLEFS_MAX_FILENAME_LEN; + return 0; +} + +// 检查文件访问权限 +int simplefs_access(const char *path, int mask) { + SimpleFS_Context* context = get_fs_context(); + if (!context) return -EACCES; + errno = 0; + uint32_t inode_num = path_to_inode_num(path); // 跟随符号链接进行访问检查 + if (inode_num == 0) return -errno; + SimpleFS_Inode inode_data; + if (read_inode_from_disk(*context, inode_num, &inode_data) != 0) return -errno; + return check_access(fuse_get_context(), &inode_data, mask); +} + +// 确保为给定逻辑块索引分配物理块的辅助函数 +static uint32_t allocate_block_for_write(SimpleFS_Context& context, SimpleFS_Inode* inode, uint32_t inode_num , + uint32_t logical_block_idx, bool* p_was_newly_allocated) { + if(p_was_newly_allocated) *p_was_newly_allocated = false; + if (!inode) { errno = EIO; return 0; } + uint32_t preferred_group = (inode_num -1) / context.sb.s_inodes_per_group; + uint32_t pointers_per_block = SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t); + std::vector indirect_block_buffer(pointers_per_block); + + if (logical_block_idx < SIMPLEFS_NUM_DIRECT_BLOCKS) { + if (inode->i_block[logical_block_idx] == 0) { + uint32_t new_physical_block = alloc_block(context, preferred_group); + if (new_physical_block == 0) { return 0; } + inode->i_block[logical_block_idx] = new_physical_block; + inode->i_blocks += (SIMPLEFS_BLOCK_SIZE / 512); + if(p_was_newly_allocated) *p_was_newly_allocated = true; + } + return inode->i_block[logical_block_idx]; + } + + uint32_t single_indirect_start_idx = SIMPLEFS_NUM_DIRECT_BLOCKS; + uint32_t single_indirect_end_idx = single_indirect_start_idx + pointers_per_block; + if (logical_block_idx < single_indirect_end_idx) { + uint32_t* p_single_indirect_block_num = &inode->i_block[SIMPLEFS_NUM_DIRECT_BLOCKS]; + if (*p_single_indirect_block_num == 0) { + uint32_t new_l1_block = alloc_block(context, preferred_group); + if (new_l1_block == 0) { errno = ENOSPC; return 0; } + inode->i_blocks += (SIMPLEFS_BLOCK_SIZE / 512); + std::fill(indirect_block_buffer.begin(), indirect_block_buffer.end(), 0); + if (write_block(context.device_fd, new_l1_block, indirect_block_buffer.data()) != 0) { + free_block(context, new_l1_block); + inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + errno = EIO; return 0; + } + *p_single_indirect_block_num = new_l1_block; + } + if (read_block(context.device_fd, *p_single_indirect_block_num, indirect_block_buffer.data()) != 0) { + errno = EIO; return 0; + } + uint32_t idx_in_indirect = logical_block_idx - single_indirect_start_idx; + if (indirect_block_buffer[idx_in_indirect] == 0) { + uint32_t new_data_block = alloc_block(context, preferred_group); + if (new_data_block == 0) { errno = ENOSPC; return 0; } + indirect_block_buffer[idx_in_indirect] = new_data_block; + inode->i_blocks += (SIMPLEFS_BLOCK_SIZE / 512); + if(p_was_newly_allocated) *p_was_newly_allocated = true; + if (write_block(context.device_fd, *p_single_indirect_block_num, indirect_block_buffer.data()) != 0) { + free_block(context, new_data_block); + inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + indirect_block_buffer[idx_in_indirect] = 0; + errno = EIO; return 0; + } + } + return indirect_block_buffer[idx_in_indirect]; + } + + uint32_t double_indirect_start_idx = single_indirect_end_idx; + uint32_t double_indirect_max_logical_blocks = pointers_per_block * pointers_per_block; + uint32_t double_indirect_end_idx = double_indirect_start_idx + double_indirect_max_logical_blocks; + if (logical_block_idx < double_indirect_end_idx) { + uint32_t* p_dbl_indirect_block_num = &inode->i_block[SIMPLEFS_NUM_DIRECT_BLOCKS + 1]; + if (*p_dbl_indirect_block_num == 0) { + uint32_t new_l2_block = alloc_block(context, preferred_group); + if (new_l2_block == 0) { errno = ENOSPC; return 0; } + inode->i_blocks += (SIMPLEFS_BLOCK_SIZE / 512); + std::fill(indirect_block_buffer.begin(), indirect_block_buffer.end(), 0); + if (write_block(context.device_fd, new_l2_block, indirect_block_buffer.data()) != 0) { + free_block(context, new_l2_block); + inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + errno = EIO; return 0; + } + *p_dbl_indirect_block_num = new_l2_block; + } + std::vector l2_buffer(pointers_per_block); + if (read_block(context.device_fd, *p_dbl_indirect_block_num, l2_buffer.data()) != 0) { errno = EIO; return 0; } + uint32_t logical_offset_in_dbl_range = logical_block_idx - double_indirect_start_idx; + uint32_t idx_in_l2_block = logical_offset_in_dbl_range / pointers_per_block; + uint32_t* p_l1_block_num_from_l2 = &l2_buffer[idx_in_l2_block]; + if (*p_l1_block_num_from_l2 == 0) { + uint32_t new_l1_block = alloc_block(context, preferred_group); + if (new_l1_block == 0) { errno = ENOSPC; return 0;} + inode->i_blocks += (SIMPLEFS_BLOCK_SIZE / 512); + std::fill(indirect_block_buffer.begin(), indirect_block_buffer.end(), 0); + if (write_block(context.device_fd, new_l1_block, indirect_block_buffer.data()) != 0) { + free_block(context, new_l1_block); + inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + errno = EIO; return 0; + } + *p_l1_block_num_from_l2 = new_l1_block; + if (write_block(context.device_fd, *p_dbl_indirect_block_num, l2_buffer.data()) != 0) { + free_block(context, new_l1_block); + inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + *p_l1_block_num_from_l2 = 0; + errno = EIO; return 0; + } + } + std::vector l1_buffer(pointers_per_block); + if (read_block(context.device_fd, *p_l1_block_num_from_l2, l1_buffer.data()) != 0) { errno = EIO; return 0;} + uint32_t idx_in_l1_block = logical_offset_in_dbl_range % pointers_per_block; + if (l1_buffer[idx_in_l1_block] == 0) { + uint32_t new_data_block = alloc_block(context, preferred_group); + if (new_data_block == 0) { errno = ENOSPC; return 0; } + l1_buffer[idx_in_l1_block] = new_data_block; + inode->i_blocks += (SIMPLEFS_BLOCK_SIZE / 512); + if(p_was_newly_allocated) *p_was_newly_allocated = true; + if (write_block(context.device_fd, *p_l1_block_num_from_l2, l1_buffer.data()) != 0) { + free_block(context, new_data_block); + inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + l1_buffer[idx_in_l1_block] = 0; + errno = EIO; return 0; + } + } + return l1_buffer[idx_in_l1_block]; + } + + uint32_t triple_indirect_start_idx = double_indirect_end_idx; + uint64_t triple_indirect_max_logical_blocks = (uint64_t)pointers_per_block * pointers_per_block * pointers_per_block; + uint64_t triple_indirect_end_idx = triple_indirect_start_idx + triple_indirect_max_logical_blocks; + if (logical_block_idx < triple_indirect_end_idx) { + uint32_t* p_tpl_indirect_block_num = &inode->i_block[SIMPLEFS_NUM_DIRECT_BLOCKS + 2]; + if (*p_tpl_indirect_block_num == 0) { + uint32_t new_l3_block = alloc_block(context, preferred_group); + if (new_l3_block == 0) { errno = ENOSPC; return 0; } + inode->i_blocks += (SIMPLEFS_BLOCK_SIZE / 512); + std::fill(indirect_block_buffer.begin(), indirect_block_buffer.end(), 0); + if (write_block(context.device_fd, new_l3_block, indirect_block_buffer.data()) != 0) { + free_block(context, new_l3_block); + inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + errno = EIO; return 0; + } + *p_tpl_indirect_block_num = new_l3_block; + } + std::vector l3_buffer(pointers_per_block); + if (read_block(context.device_fd, *p_tpl_indirect_block_num, l3_buffer.data()) != 0) { errno = EIO; return 0; } + uint32_t logical_offset_in_tpl_range = logical_block_idx - triple_indirect_start_idx; + uint32_t idx_in_l3_block = logical_offset_in_tpl_range / (pointers_per_block * pointers_per_block); + uint32_t* p_l2_block_num_from_l3 = &l3_buffer[idx_in_l3_block]; + if (*p_l2_block_num_from_l3 == 0) { + uint32_t new_l2_block = alloc_block(context, preferred_group); + if (new_l2_block == 0) { errno = ENOSPC; return 0; } + inode->i_blocks += (SIMPLEFS_BLOCK_SIZE / 512); + std::fill(indirect_block_buffer.begin(), indirect_block_buffer.end(), 0); + if (write_block(context.device_fd, new_l2_block, indirect_block_buffer.data()) != 0) { + free_block(context, new_l2_block); + inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + errno = EIO; return 0; + } + *p_l2_block_num_from_l3 = new_l2_block; + if (write_block(context.device_fd, *p_tpl_indirect_block_num, l3_buffer.data()) != 0) { + free_block(context, new_l2_block); + inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + *p_l2_block_num_from_l3 = 0; + errno = EIO; return 0; + } + } + std::vector l2_buffer(pointers_per_block); + if (read_block(context.device_fd, *p_l2_block_num_from_l3, l2_buffer.data()) != 0) { errno = EIO; return 0; } + uint32_t logical_offset_in_l2_from_tpl = logical_offset_in_tpl_range % (pointers_per_block * pointers_per_block); + uint32_t idx_in_l2_from_tpl = logical_offset_in_l2_from_tpl / pointers_per_block; + uint32_t* p_l1_block_num_from_l2 = &l2_buffer[idx_in_l2_from_tpl]; + if (*p_l1_block_num_from_l2 == 0) { + uint32_t new_l1_block = alloc_block(context, preferred_group); + if (new_l1_block == 0) { errno = ENOSPC; return 0; } + inode->i_blocks += (SIMPLEFS_BLOCK_SIZE / 512); + std::fill(indirect_block_buffer.begin(), indirect_block_buffer.end(), 0); + if (write_block(context.device_fd, new_l1_block, indirect_block_buffer.data()) != 0) { + free_block(context, new_l1_block); + inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + errno = EIO; return 0; + } + *p_l1_block_num_from_l2 = new_l1_block; + if (write_block(context.device_fd, *p_l2_block_num_from_l3, l2_buffer.data()) != 0) { + free_block(context, new_l1_block); + inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + *p_l1_block_num_from_l2 = 0; + errno = EIO; return 0; + } + } + std::vector l1_buffer(pointers_per_block); + if (read_block(context.device_fd, *p_l1_block_num_from_l2, l1_buffer.data()) != 0) { errno = EIO; return 0; } + uint32_t idx_in_l1_final = logical_offset_in_l2_from_tpl % pointers_per_block; + if (l1_buffer[idx_in_l1_final] == 0) { + uint32_t new_data_block = alloc_block(context, preferred_group); + if (new_data_block == 0) { errno = ENOSPC; return 0; } + l1_buffer[idx_in_l1_final] = new_data_block; + inode->i_blocks += (SIMPLEFS_BLOCK_SIZE / 512); + if(p_was_newly_allocated) *p_was_newly_allocated = true; + if (write_block(context.device_fd, *p_l1_block_num_from_l2, l1_buffer.data()) != 0) { + free_block(context, new_data_block); + inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + l1_buffer[idx_in_l1_final] = 0; + errno = EIO; return 0; + } + } + return l1_buffer[idx_in_l1_final]; + } + + std::cerr << "写入时分配块失败: 逻辑块 " << logical_block_idx + << " is beyond implemented allocation support (direct + single + double + triple indirect)." << std::endl; + errno = EFBIG; + return 0; +} + +// 创建文件节点 +int simplefs_mknod(const char *path, mode_t mode, dev_t rdev) { + (void)rdev; + SimpleFS_Context* context = get_fs_context(); + if (!context) return -EACCES; + if (!S_ISREG(mode) && !S_ISFIFO(mode)) { // 也允许FIFO + // 本项目只计划支持S_IFREG,符号链接是分开的 + // 如果严格只要S_IFREG: + if(!S_ISREG(mode)) { + std::cerr << "mknod: Unsupported file type in mode: 0x" << std::hex << mode << std::dec << ". Only regular files allowed." << std::endl; + return -EPERM; + } + } + + std::string path_str(path); + std::string dirname_str, basename_str; + parse_path(path_str, dirname_str, basename_str); + + if (basename_str.empty() || basename_str == "." || basename_str == ".." || basename_str == "/") + return -EINVAL; + if (basename_str.length() > SIMPLEFS_MAX_FILENAME_LEN) return -ENAMETOOLONG; + + errno = 0; + uint32_t parent_inode_num = path_to_inode_num(dirname_str.c_str()); + if (parent_inode_num == 0) return -errno; + SimpleFS_Inode parent_inode_data; + if (read_inode_from_disk(*context, parent_inode_num, &parent_inode_data) != 0) return -errno; + if (!S_ISDIR(parent_inode_data.i_mode)) return -ENOTDIR; + + int access_res = check_access(fuse_get_context(), &parent_inode_data, W_OK | X_OK); + if (access_res != 0) return access_res; + + errno = 0; + uint32_t existing_inode_check = resolve_path_recursive(path_str.c_str(), 0, false); // 检查不跟随最后链接 + if (existing_inode_check != 0) return -EEXIST; + if (errno != 0 && errno != ENOENT) return -errno; + + uint32_t new_inode_num = alloc_inode(*context, mode); + if (new_inode_num == 0) return -errno; + + SimpleFS_Inode new_inode; + std::memset(&new_inode, 0, sizeof(SimpleFS_Inode)); + new_inode.i_mode = mode; // 包含S_IFREG和权限设置 + new_inode.i_uid = fuse_get_context()->uid; + new_inode.i_gid = fuse_get_context()->gid; + new_inode.i_links_count = 1; + new_inode.i_size = 0; + new_inode.i_atime = new_inode.i_mtime = new_inode.i_ctime = time(nullptr); + new_inode.i_blocks = 0; + + if (write_inode_to_disk(*context, new_inode_num, &new_inode) != 0) { + free_inode(*context, new_inode_num, new_inode.i_mode); + return -errno; + } + + uint8_t dentry_file_type = 0; + if (S_ISREG(mode)) dentry_file_type = DT_REG; // DT_REG是8 + else if (S_ISDIR(mode)) dentry_file_type = DT_DIR; // DT_DIR是4 + else if (S_ISLNK(mode)) dentry_file_type = DT_LNK; // DT_LNK是10 + // else if (S_ISFIFO(mode)) dentry_file_type = DT_FIFO; // DT_FIFO是1,需要确保simplefs.h中有这些定义 + // 现在,如果DT_xxx常量未定义/使用不一致,使用S_IFMT >> 12技巧 + // DirEntry file_type通常从S_IFMT位派生 + dentry_file_type = (mode & S_IFMT) >> 12; + + + int add_entry_res = add_dir_entry(*context, &parent_inode_data, parent_inode_num, basename_str, new_inode_num, dentry_file_type); + if (add_entry_res != 0) { + // 回滚:释放inode(新文件还未分配块) + new_inode.i_dtime = time(nullptr); + new_inode.i_links_count = 0; + write_inode_to_disk(*context, new_inode_num, &new_inode); + free_inode(*context, new_inode_num, new_inode.i_mode); + return add_entry_res; + } + sync_fs_metadata(*context); + return 0; +} + +// 创建目录 +int simplefs_mkdir(const char *path, mode_t mode) { + SimpleFS_Context* context = get_fs_context(); + if (!context) return -EACCES; + std::string path_str(path); + std::string dirname_str, basename_str; + parse_path(path_str, dirname_str, basename_str); + + if (basename_str.empty() || basename_str == "." || basename_str == ".." || basename_str == "/") + return -EINVAL; + if (basename_str.length() > SIMPLEFS_MAX_FILENAME_LEN) return -ENAMETOOLONG; + + errno = 0; + uint32_t parent_inode_num = path_to_inode_num(dirname_str.c_str()); + if (parent_inode_num == 0) return -errno; + SimpleFS_Inode parent_inode_data; + if (read_inode_from_disk(*context, parent_inode_num, &parent_inode_data) != 0) return -errno; + if (!S_ISDIR(parent_inode_data.i_mode)) return -ENOTDIR; + + int access_res = check_access(fuse_get_context(), &parent_inode_data, W_OK | X_OK); + if (access_res != 0) return access_res; + + errno = 0; + uint32_t existing_inode_check = resolve_path_recursive(path_str.c_str(), 0, false); + if (existing_inode_check != 0) return -EEXIST; + if (errno != 0 && errno != ENOENT) return -errno; + + uint32_t new_dir_inode_num = alloc_inode(*context, S_IFDIR | (mode & 07777)); + if (new_dir_inode_num == 0) return -errno; + + uint32_t new_dir_data_block = alloc_block(*context, (new_dir_inode_num -1) / context->sb.s_inodes_per_group); + if (new_dir_data_block == 0) { + free_inode(*context, new_dir_inode_num, S_IFDIR | (mode & 07777)); + return -errno; + } + + SimpleFS_Inode new_dir_inode; + std::memset(&new_dir_inode, 0, sizeof(SimpleFS_Inode)); + new_dir_inode.i_mode = S_IFDIR | (mode & 07777); // 应用模式权限 + new_dir_inode.i_uid = fuse_get_context()->uid; + new_dir_inode.i_gid = fuse_get_context()->gid; + new_dir_inode.i_links_count = 2; // 用于'.'和父目录中的条目 + new_dir_inode.i_size = 0; // 将由add_dir_entry为"."和".."设置 + new_dir_inode.i_blocks = 0; // 计算"."和".."数据块时设置 + new_dir_inode.i_atime = new_dir_inode.i_mtime = new_dir_inode.i_ctime = time(nullptr); + // new_dir_inode.i_block[0] = new_dir_data_block; // 块准备后设置 + + // 准备包含"."和".."的目录块 + std::vector dir_block_buffer(SIMPLEFS_BLOCK_SIZE, 0); + uint16_t current_offset = 0; + uint8_t dot_file_type = (S_IFDIR & S_IFMT) >> 12; + + SimpleFS_DirEntry dot_entry; + dot_entry.inode = new_dir_inode_num; + dot_entry.name_len = 1; + dot_entry.file_type = dot_file_type; + std::strncpy(dot_entry.name, ".", 1); + dot_entry.rec_len = calculate_dir_entry_len(dot_entry.name_len); + std::memcpy(dir_block_buffer.data() + current_offset, &dot_entry, (size_t)calculate_dir_entry_len(0) + dot_entry.name_len); + current_offset += dot_entry.rec_len; + + SimpleFS_DirEntry dotdot_entry; + dotdot_entry.inode = parent_inode_num; + dotdot_entry.name_len = 2; + dotdot_entry.file_type = dot_file_type; + std::strncpy(dotdot_entry.name, "..", 2); + dotdot_entry.rec_len = SIMPLEFS_BLOCK_SIZE - current_offset; // 使".."填充剩余空间 + std::memcpy(dir_block_buffer.data() + current_offset, &dotdot_entry, (size_t)calculate_dir_entry_len(0) + dotdot_entry.name_len); + current_offset += dotdot_entry.rec_len; + + if (write_block(context->device_fd, new_dir_data_block, dir_block_buffer.data()) != 0) { + free_block(*context, new_dir_data_block); + free_inode(*context, new_dir_inode_num, new_dir_inode.i_mode); + return -EIO; + } + + new_dir_inode.i_block[0] = new_dir_data_block; + new_dir_inode.i_blocks = SIMPLEFS_BLOCK_SIZE / 512; + new_dir_inode.i_size = current_offset; // "."和".."使用的实际大小 + + if (write_inode_to_disk(*context, new_dir_inode_num, &new_dir_inode) != 0) { + // 回滚数据块 + std::fill(dir_block_buffer.begin(), dir_block_buffer.end(), 0); + write_block(context->device_fd, new_dir_data_block, dir_block_buffer.data()); // 尝试清理 + free_block(*context, new_dir_data_block); + // 回滚inode + new_dir_inode.i_dtime = time(nullptr); new_dir_inode.i_links_count = 0; + write_inode_to_disk(*context, new_dir_inode_num, &new_dir_inode); + free_inode(*context, new_dir_inode_num, new_dir_inode.i_mode); + return -errno; + } + + uint8_t dentry_file_type_for_parent = (S_IFDIR & S_IFMT) >> 12; + int add_entry_res_parent = add_dir_entry(*context, &parent_inode_data, parent_inode_num, basename_str, new_dir_inode_num, dentry_file_type_for_parent); + + if (add_entry_res_parent != 0) { + // 完全回滚 + std::fill(dir_block_buffer.begin(), dir_block_buffer.end(), 0); + write_block(context->device_fd, new_dir_data_block, dir_block_buffer.data()); + free_block(*context, new_dir_data_block); + new_dir_inode.i_dtime = time(nullptr); new_dir_inode.i_links_count = 0; + write_inode_to_disk(*context, new_dir_inode_num, &new_dir_inode); + free_inode(*context, new_dir_inode_num, S_IFDIR | (mode & 07777)); // 使用原始模式计算目录数 + return add_entry_res_parent; + } + + // 如果add_dir_entry为父目录分配新块,父目录的链接数会被增加 + // 但是,mkdir传统上增加父目录的链接数,因为新的".."条目指向它 + // 我们的add_dir_entry不处理parent_inode.i_links_count + // 对于mkdir,父目录的i_links_count应该增加1 + parent_inode_data.i_links_count++; + parent_inode_data.i_mtime = parent_inode_data.i_ctime = time(nullptr); + if(write_inode_to_disk(*context, parent_inode_num, &parent_inode_data) != 0) { + // 完全回滚有些复杂,现在记录并继续 + std::cerr << "mkdir: 父目录链接数更新失败,文件系统可能不一致" << std::endl; + } + + sync_fs_metadata(*context); + return 0; +} + +// 删除文件 +int simplefs_unlink(const char *path) { + SimpleFS_Context* context = get_fs_context(); + if (!context) return -EACCES; + + std::string path_str(path); + std::string dirname_str, basename_str; + parse_path(path_str, dirname_str, basename_str); + + if (basename_str.empty() || basename_str == "." || basename_str == ".." || basename_str == "/") { + return -EINVAL; + } + + errno = 0; + uint32_t parent_inode_num = path_to_inode_num(dirname_str.c_str()); + if (parent_inode_num == 0) { + return -errno; + } + SimpleFS_Inode parent_inode_data; + if (read_inode_from_disk(*context, parent_inode_num, &parent_inode_data) != 0) { + return -errno; + } + if (!S_ISDIR(parent_inode_data.i_mode)) { + return -ENOTDIR; + } + + // 权限检查:父目录的W_OK和X_OK + int access_res = check_access(fuse_get_context(), &parent_inode_data, W_OK | X_OK); + if (access_res != 0) { + return access_res; + } + + errno = 0; + // unlink操作的是文件/符号链接本身,不是其目标 + uint32_t target_inode_num = resolve_path_recursive(path_str.c_str(), 0, false); + if (target_inode_num == 0) { + return -errno; + } + + SimpleFS_Inode target_inode_data; + if (read_inode_from_disk(*context, target_inode_num, &target_inode_data) != 0) { + return -errno; + } + + // 粘滞位(S_ISVTX)检查删除权限 + if ((parent_inode_data.i_mode & S_ISVTX)) { + if (!S_ISDIR(target_inode_data.i_mode)) { + struct fuse_context *caller_ctx = fuse_get_context(); + if (caller_ctx->uid != 0 && + caller_ctx->uid != parent_inode_data.i_uid && + caller_ctx->uid != target_inode_data.i_uid) { + std::cout << "父目录 " << parent_inode_num + << " 对项目 " << target_inode_num << " 的粘滞位权限拒绝" << std::endl; + return -EACCES; + } + } + } + + // 现在检查目标是否为目录(unlink无法移除) + if (S_ISDIR(target_inode_data.i_mode)) { + return -EISDIR; + } + + int remove_res = remove_dir_entry(*context, &parent_inode_data, parent_inode_num, basename_str); + if (remove_res != 0) { + return remove_res; + } + + target_inode_data.i_links_count--; + target_inode_data.i_ctime = time(nullptr); + + if (target_inode_data.i_links_count == 0) { + + // 重要:仅在非快速符号链接时释放块 + // 快速符号链接i_blocks==0且数据存储在i_block数组中 + if (!(S_ISLNK(target_inode_data.i_mode) && target_inode_data.i_blocks == 0)) { + free_all_inode_blocks(*context, &target_inode_data); + } + + target_inode_data.i_size = 0; + target_inode_data.i_dtime = time(nullptr); + + if (write_inode_to_disk(*context, target_inode_num, &target_inode_data) != 0) { + std::cerr << "unlink: 释放前目标inode " << target_inode_num << " 写入失败,继续释放inode" << std::endl; + } + free_inode(*context, target_inode_num, target_inode_data.i_mode); + } else { + if (write_inode_to_disk(*context, target_inode_num, &target_inode_data) != 0) { + std::cerr << "unlink: 目标inode " << target_inode_num << " 链接数更新失败" << std::endl; + return -EIO; + } + } + sync_fs_metadata(*context); + return 0; +} + +// 删除目录 +int simplefs_rmdir(const char *path) { + SimpleFS_Context* context = get_fs_context(); + if (!context) return -EACCES; + std::string path_str(path); + std::string dirname_str, basename_str; + parse_path(path_str, dirname_str, basename_str); + + if (basename_str.empty() || basename_str == "." || basename_str == ".." || basename_str == "/") + return -EINVAL; + + errno = 0; + uint32_t parent_inode_num = path_to_inode_num(dirname_str.c_str()); + if (parent_inode_num == 0) return -errno; + SimpleFS_Inode parent_inode_data; + if (read_inode_from_disk(*context, parent_inode_num, &parent_inode_data) != 0) return -errno; + if (!S_ISDIR(parent_inode_data.i_mode)) return -ENOTDIR; + + int access_res = check_access(fuse_get_context(), &parent_inode_data, W_OK | X_OK); + if (access_res != 0) return access_res; + + errno = 0; + uint32_t target_inode_num = resolve_path_recursive(path_str.c_str(), 0, false); + if (target_inode_num == 0) return -errno; + SimpleFS_Inode target_inode_data; + if (read_inode_from_disk(*context, target_inode_num, &target_inode_data) != 0) return -errno; + + if ((parent_inode_data.i_mode & S_ISVTX)) { + struct fuse_context *caller_ctx = fuse_get_context(); + if (caller_ctx->uid != 0 && + caller_ctx->uid != parent_inode_data.i_uid && + caller_ctx->uid != target_inode_data.i_uid) { + return -EACCES; + } + } + + if (!S_ISDIR(target_inode_data.i_mode)) return -ENOTDIR; + + bool is_empty = true; + if (target_inode_data.i_size > 0) { // 检查目录是否为空(只包含"."和"..") + std::vector block_buffer(SIMPLEFS_BLOCK_SIZE); + uint32_t total_dir_bytes_iterated = 0; + int non_dot_entries = 0; + + uint32_t dir_lbn = 0; + while(total_dir_bytes_iterated < target_inode_data.i_size && non_dot_entries == 0) { + uint32_t physical_block = map_logical_to_physical_block(*context, &target_inode_data, dir_lbn); + if (physical_block == 0) { // 目录通常应该是连续的 + if (total_dir_bytes_iterated >= target_inode_data.i_size) break; + dir_lbn++; continue; + } + if (read_block(context->device_fd, physical_block, block_buffer.data()) != 0) return -EIO; + + uint16_t entry_offset = 0; + uint32_t current_block_dir_bytes_processed = 0; + while(total_dir_bytes_iterated < target_inode_data.i_size && current_block_dir_bytes_processed < SIMPLEFS_BLOCK_SIZE) { + SimpleFS_DirEntry* entry = reinterpret_cast(block_buffer.data() + entry_offset); + if (entry->rec_len == 0 || (calculate_dir_entry_len(entry->name_len) > entry->rec_len) || (entry_offset + entry->rec_len > SIMPLEFS_BLOCK_SIZE)) break; + if (entry->inode != 0 && entry->name_len > 0) { + std::string entry_s_name(entry->name, entry->name_len); + if (entry_s_name != "." && entry_s_name != "..") { + non_dot_entries++; + break; + } + } + entry_offset += entry->rec_len; + current_block_dir_bytes_processed += entry->rec_len; + total_dir_bytes_iterated += entry->rec_len; + if(entry_offset >= SIMPLEFS_BLOCK_SIZE) break; + } + if (non_dot_entries > 0) break; + dir_lbn++; + if (dir_lbn > (target_inode_data.i_size / SIMPLEFS_BLOCK_SIZE) + SIMPLEFS_INODE_BLOCK_PTRS*1024*1024) { + std::cerr << "rmdir: Excessive LBN for dir " << target_inode_num << std::endl; return -EIO; + } + } + if (non_dot_entries > 0) is_empty = false; + } + if (!is_empty) return -ENOTEMPTY; + + int remove_res = remove_dir_entry(*context, &parent_inode_data, parent_inode_num, basename_str); + if (remove_res != 0) return remove_res; + + // 减少父目录链接数,因为被删除目录的".."不再指向它 + parent_inode_data.i_links_count--; + parent_inode_data.i_mtime = parent_inode_data.i_ctime = time(nullptr); + if (write_inode_to_disk(*context, parent_inode_num, &parent_inode_data) != 0) { /* Log error, but proceed */ } + + // 释放被删除目录的块(应该只有一个包含"."和".."的块) + free_all_inode_blocks(*context, &target_inode_data); + + target_inode_data.i_links_count = 0; // 父目录链接消失,"."消失 + target_inode_data.i_dtime = time(nullptr); + target_inode_data.i_size = 0; + // i_blocks由free_all_inode_blocks处理 + + mode_t mode_of_target = target_inode_data.i_mode; + if(write_inode_to_disk(*context, target_inode_num, &target_inode_data) !=0) { + std::cerr << "rmdir: 释放前目标inode " << target_inode_num << " 写入失败" << std::endl; + } + free_inode(*context, target_inode_num, mode_of_target); // mode_of_target用于bg_used_dirs_count + sync_fs_metadata(*context); + return 0; +} + +// 从打开的文件读取数据 +int simplefs_read(const char *path, char *buf, size_t size, off_t offset, + struct fuse_file_info *fi) { + (void)fi; + SimpleFS_Context* context = get_fs_context(); + if (!context) return -EACCES; + errno = 0; + uint32_t inode_num = path_to_inode_num(path); + if (inode_num == 0) return -errno; + SimpleFS_Inode inode_data; + if (read_inode_from_disk(*context, inode_num, &inode_data) != 0) return -errno; + if (S_ISDIR(inode_data.i_mode)) return -EISDIR; + int access_res = check_access(fuse_get_context(), &inode_data, R_OK); + if (access_res != 0) return access_res; + + if (offset >= (off_t)inode_data.i_size) return 0; + if (offset + size > inode_data.i_size) { + size = inode_data.i_size - offset; + } + + size_t total_bytes_read = 0; + std::vector block_buffer(SIMPLEFS_BLOCK_SIZE); + while (total_bytes_read < size) { + uint32_t current_offset_in_file = offset + total_bytes_read; + uint32_t logical_block_idx = current_offset_in_file / SIMPLEFS_BLOCK_SIZE; + uint32_t offset_in_block = current_offset_in_file % SIMPLEFS_BLOCK_SIZE; + uint32_t physical_block_num = map_logical_to_physical_block(*context, &inode_data, logical_block_idx); + if (physical_block_num == 0) { + size_t bytes_to_zero_in_this_block = SIMPLEFS_BLOCK_SIZE - offset_in_block; + if (bytes_to_zero_in_this_block > (size - total_bytes_read)) { + bytes_to_zero_in_this_block = size - total_bytes_read; + } + std::memset(buf + total_bytes_read, 0, bytes_to_zero_in_this_block); + total_bytes_read += bytes_to_zero_in_this_block; + if (errno != 0 && errno != ENOENT) { + if (total_bytes_read > 0) break; + return -errno; + } + errno = 0; + continue; + } + if (read_block(context->device_fd, physical_block_num, block_buffer.data()) != 0) { + if (total_bytes_read > 0) break; + return -EIO; + } + size_t bytes_to_read_from_this_block = SIMPLEFS_BLOCK_SIZE - offset_in_block; + if (bytes_to_read_from_this_block > (size - total_bytes_read)) { + bytes_to_read_from_this_block = size - total_bytes_read; + } + std::memcpy(buf + total_bytes_read, block_buffer.data() + offset_in_block, bytes_to_read_from_this_block); + total_bytes_read += bytes_to_read_from_this_block; + } + inode_data.i_atime = time(nullptr); + if (write_inode_to_disk(*context, inode_num, &inode_data) != 0) { + std::cerr << "read: inode " << inode_num << " atime更新失败" << std::endl; + } + return total_bytes_read; +} + +// 向打开的文件写入数据 +int simplefs_write(const char *path, const char *buf, size_t size, off_t offset, + struct fuse_file_info *fi) { + (void)fi; + SimpleFS_Context* context = get_fs_context(); + if (!context) return -EACCES; + errno = 0; + uint32_t inode_num = path_to_inode_num(path); + if (inode_num == 0) return -errno; + SimpleFS_Inode inode_data; + if (read_inode_from_disk(*context, inode_num, &inode_data) != 0) return -errno; + if (S_ISDIR(inode_data.i_mode)) return -EISDIR; + int access_res = check_access(fuse_get_context(), &inode_data, W_OK); + if (access_res != 0) return access_res; + + size_t total_bytes_written = 0; + std::vector block_rw_buffer(SIMPLEFS_BLOCK_SIZE); + while (total_bytes_written < size) { + uint32_t current_offset_in_file = offset + total_bytes_written; + uint32_t logical_block_idx = current_offset_in_file / SIMPLEFS_BLOCK_SIZE; + uint32_t offset_in_block = current_offset_in_file % SIMPLEFS_BLOCK_SIZE; + bool block_was_newly_allocated = false; + uint32_t physical_block_num = allocate_block_for_write(*context, &inode_data, inode_num, logical_block_idx, &block_was_newly_allocated); + if (physical_block_num == 0) { + if (total_bytes_written > 0) break; + return -errno; + } + size_t bytes_to_write_in_this_block = SIMPLEFS_BLOCK_SIZE - offset_in_block; + if (bytes_to_write_in_this_block > (size - total_bytes_written)) { + bytes_to_write_in_this_block = size - total_bytes_written; + } + bool is_partial_block_overwrite = (offset_in_block != 0 || bytes_to_write_in_this_block < SIMPLEFS_BLOCK_SIZE); + if (is_partial_block_overwrite && !block_was_newly_allocated) { + if (read_block(context->device_fd, physical_block_num, block_rw_buffer.data()) != 0) { + if (total_bytes_written > 0) break; + return -EIO; + } + } else { + if (is_partial_block_overwrite && block_was_newly_allocated) + std::fill(block_rw_buffer.begin(), block_rw_buffer.end(), 0); + } + std::memcpy(block_rw_buffer.data() + offset_in_block, buf + total_bytes_written, bytes_to_write_in_this_block); + if (write_block(context->device_fd, physical_block_num, block_rw_buffer.data()) != 0) { + if (total_bytes_written > 0) break; + return -EIO; + } + total_bytes_written += bytes_to_write_in_this_block; + } + if ((offset + total_bytes_written) > inode_data.i_size) { + inode_data.i_size = offset + total_bytes_written; + } + inode_data.i_mtime = inode_data.i_ctime = time(nullptr); + if (write_inode_to_disk(*context, inode_num, &inode_data) != 0) { + if (total_bytes_written == 0 && size > 0) return -EIO; + } + sync_fs_metadata(*context); + return total_bytes_written; +} + +// 更改文件大小 +int simplefs_truncate(const char *path, off_t size) { + SimpleFS_Context* context = get_fs_context(); + if (!context) return -EACCES; + errno = 0; + uint32_t inode_num = path_to_inode_num(path); // 跟随符号链接 + if (inode_num == 0) return -errno; + SimpleFS_Inode inode_data; + if (read_inode_from_disk(*context, inode_num, &inode_data) != 0) return -errno; + if (S_ISDIR(inode_data.i_mode)) return -EISDIR; + int access_res = check_access(fuse_get_context(), &inode_data, W_OK); + if (access_res != 0) return access_res; + + if (inode_data.i_size == (uint32_t)size) { + inode_data.i_ctime = time(nullptr); + if (write_inode_to_disk(*context, inode_num, &inode_data) != 0) return -errno; + return 0; + } + uint32_t old_size = inode_data.i_size; + inode_data.i_size = size; + if (size == 0) { + free_all_inode_blocks(*context, &inode_data); + } else if (size < old_size) { + uint32_t old_num_fs_blocks = (old_size + SIMPLEFS_BLOCK_SIZE - 1) / SIMPLEFS_BLOCK_SIZE; + if (inode_data.i_size == (uint32_t)size) { + return 0; + } + uint32_t old_size = inode_data.i_size; + inode_data.i_size = size; + uint32_t new_num_fs_blocks = (size + SIMPLEFS_BLOCK_SIZE - 1) / SIMPLEFS_BLOCK_SIZE; + if (size == 0) new_num_fs_blocks = 0; + if (new_num_fs_blocks < old_num_fs_blocks) { + release_logical_block_range(*context, &inode_data, new_num_fs_blocks, old_num_fs_blocks); + } + } + inode_data.i_mtime = time(nullptr); + inode_data.i_ctime = time(nullptr); + if (write_inode_to_disk(*context, inode_num, &inode_data) != 0) return -errno; + if (size < old_size || size == 0) { + sync_fs_metadata(*context); + } + return 0; +} + +// 更改文件的权限位 +int simplefs_chmod(const char *path, mode_t mode) { + SimpleFS_Context* context = get_fs_context(); + if (!context) return -EACCES; + errno = 0; + uint32_t inode_num = path_to_inode_num(path); // 跟随符号链接 + if (inode_num == 0) return -errno; + SimpleFS_Inode inode_data; + if (read_inode_from_disk(*context, inode_num, &inode_data) != 0) return -errno; + struct fuse_context *caller_context = fuse_get_context(); + if (caller_context->uid != 0 && caller_context->uid != inode_data.i_uid) { + return -EPERM; + } + inode_data.i_mode = (inode_data.i_mode & S_IFMT) | (mode & 07777); + inode_data.i_ctime = time(nullptr); + if (write_inode_to_disk(*context, inode_num, &inode_data) != 0) return -errno; + return 0; +} + +// 更改文件的所有者和组 +int simplefs_chown(const char *path, uid_t uid, gid_t gid) { + SimpleFS_Context* context = get_fs_context(); + if (!context) return -EACCES; + errno = 0; + uint32_t inode_num = resolve_path_recursive(path, 0, false); // 如果是链接则操作链接本身 + if (inode_num == 0) return -errno; + SimpleFS_Inode inode_data; + if (read_inode_from_disk(*context, inode_num, &inode_data) != 0) return -errno; + struct fuse_context *caller_context = fuse_get_context(); + + if (caller_context->uid != 0) { + bool uid_changing = (uid != (uid_t)-1 && uid != inode_data.i_uid); + bool gid_changing = (gid != (gid_t)-1 && gid != inode_data.i_gid); + if (uid_changing) return -EPERM; + if (gid_changing) { + if (caller_context->uid != inode_data.i_uid) return -EPERM; + bool new_gid_is_valid_for_user = false; + if (gid == caller_context->gid) { + new_gid_is_valid_for_user = true; + } else { + int num_supp_groups = getgroups(0, nullptr); + if (num_supp_groups < 0) { + perror("获取组数失败"); return -EIO; + } + if (num_supp_groups > 0) { + std::vector supp_group_list(num_supp_groups); + if (getgroups(num_supp_groups, supp_group_list.data()) < 0) { + perror("获取组列表失败"); return -EIO; + } + for (gid_t supp_gid : supp_group_list) { + if (gid == supp_gid) { + new_gid_is_valid_for_user = true; break; + } + } + } + } + if (!new_gid_is_valid_for_user) { + return -EPERM; + } + } + } + bool changed = false; + if (uid != (uid_t)-1 && inode_data.i_uid != uid) { + inode_data.i_uid = uid; changed = true; + } + if (gid != (gid_t)-1 && inode_data.i_gid != gid) { + inode_data.i_gid = gid; changed = true; + } + if (changed) { + if (caller_context->uid != 0) { + inode_data.i_mode &= ~(S_ISUID | S_ISGID); + } + inode_data.i_ctime = time(nullptr); + if (write_inode_to_disk(*context, inode_num, &inode_data) != 0) return -errno; + } + return 0; +} + +// 创建符号链接 +int simplefs_symlink(const char *target, const char *linkpath) { + SimpleFS_Context* context = get_fs_context(); + if (!context) return -EACCES; + std::string linkpath_str(linkpath); + std::string target_str(target); + std::string dirname_str, basename_str; + if (target_str.empty()) return -EINVAL; + parse_path(linkpath_str, dirname_str, basename_str); + if (basename_str.empty() || basename_str == "." || basename_str == ".." || basename_str == "/") return -EINVAL; + if (basename_str.length() > SIMPLEFS_MAX_FILENAME_LEN) return -ENAMETOOLONG; + + errno = 0; + uint32_t parent_inode_num = path_to_inode_num(dirname_str.c_str()); + if (parent_inode_num == 0) return -errno; + SimpleFS_Inode parent_inode_data; + if (read_inode_from_disk(*context, parent_inode_num, &parent_inode_data) != 0) return -errno; + if (!S_ISDIR(parent_inode_data.i_mode)) return -ENOTDIR; + + int access_res = check_access(fuse_get_context(), &parent_inode_data, W_OK | X_OK); + if (access_res != 0) return access_res; + + errno = 0; + uint32_t existing_inode_check = resolve_path_recursive(linkpath_str.c_str(), 0, false); // 检查linkpath本身是否存在 + if (existing_inode_check != 0) return -EEXIST; + if (errno != 0 && errno != ENOENT) return -errno; + + uint32_t symlink_inode_num = alloc_inode(*context, S_IFLNK | 0777); + if (symlink_inode_num == 0) return -errno; + + SimpleFS_Inode symlink_inode; + std::memset(&symlink_inode, 0, sizeof(SimpleFS_Inode)); + symlink_inode.i_mode = S_IFLNK | 0777; + symlink_inode.i_uid = fuse_get_context()->uid; + symlink_inode.i_gid = fuse_get_context()->gid; + symlink_inode.i_links_count = 1; + symlink_inode.i_size = target_str.length(); + symlink_inode.i_atime = symlink_inode.i_mtime = symlink_inode.i_ctime = time(nullptr); + + // 快速符号链接优化 + if (target_str.length() < sizeof(symlink_inode.i_block)) { + // 路径足够短,直接存储在inode的块指针中 + std::memcpy(symlink_inode.i_block, target_str.c_str(), target_str.length()); + symlink_inode.i_blocks = 0; // 快速符号链接标识 + std::cout << "[符号链接] 创建快速符号链接: " << target_str << std::endl; + } else { + // 路径太长,使用数据块(慢速符号链接) + if (target_str.length() >= SIMPLEFS_BLOCK_SIZE) { + free_inode(*context, symlink_inode_num, symlink_inode.i_mode); return -ENAMETOOLONG; + } + uint32_t data_block_num = alloc_block(*context, (symlink_inode_num - 1) / context->sb.s_inodes_per_group); + if (data_block_num == 0) { + free_inode(*context, symlink_inode_num, symlink_inode.i_mode); return -errno; + } + std::vector block_buffer_vec(SIMPLEFS_BLOCK_SIZE, 0); + std::memcpy(block_buffer_vec.data(), target_str.c_str(), target_str.length()); + if (write_block(context->device_fd, data_block_num, block_buffer_vec.data()) != 0) { + free_block(*context, data_block_num); + free_inode(*context, symlink_inode_num, symlink_inode.i_mode); return -EIO; + } + symlink_inode.i_block[0] = data_block_num; + symlink_inode.i_blocks = SIMPLEFS_BLOCK_SIZE / 512; + } + + if (write_inode_to_disk(*context, symlink_inode_num, &symlink_inode) != 0) { + if (symlink_inode.i_blocks > 0 && symlink_inode.i_block[0] != 0) { + free_block(*context, symlink_inode.i_block[0]); + } + free_inode(*context, symlink_inode_num, symlink_inode.i_mode); return -errno; + } + + uint8_t dentry_file_type = (S_IFLNK & S_IFMT) >> 12; + int add_entry_res = add_dir_entry(*context, &parent_inode_data, parent_inode_num, basename_str, symlink_inode_num, dentry_file_type); + if (add_entry_res != 0) { + if (symlink_inode.i_blocks > 0 && symlink_inode.i_block[0] != 0) { + free_block(*context, symlink_inode.i_block[0]); + } + symlink_inode.i_dtime = time(nullptr); symlink_inode.i_links_count = 0; + write_inode_to_disk(*context, symlink_inode_num, &symlink_inode); + free_inode(*context, symlink_inode_num, symlink_inode.i_mode); + return add_entry_res; + } + sync_fs_metadata(*context); + return 0; +} + +// 读取符号链接的目标 +int simplefs_readlink(const char *path, char *buf, size_t size) { + SimpleFS_Context* context = get_fs_context(); + if (!context) return -EACCES; + errno = 0; + uint32_t inode_num = resolve_path_recursive(path, 0, false); + if (inode_num == 0) return -errno; + SimpleFS_Inode inode_data; + if (read_inode_from_disk(*context, inode_num, &inode_data) != 0) return -errno; + if (!S_ISLNK(inode_data.i_mode)) return -EINVAL; + if (inode_data.i_size == 0) return 0; + + size_t actual_bytes_copied = 0; + + // 检查是快速符号链接(i_blocks==0)还是慢速符号链接 + if (inode_data.i_blocks == 0) { + // 快速符号链接:目标路径存储在inode的i_block数组中 + size_t symlink_target_len = inode_data.i_size; + actual_bytes_copied = std::min(size - 1, symlink_target_len); // 为null终止符留空间 + if (actual_bytes_copied > 0) { + std::memcpy(buf, inode_data.i_block, actual_bytes_copied); + } + } else { + // 慢速符号链接:目标路径在数据块中 + if (inode_data.i_block[0] == 0) return -EIO; + size_t symlink_target_len = inode_data.i_size; + std::vector block_buffer_vec(SIMPLEFS_BLOCK_SIZE); + if (read_block(context->device_fd, inode_data.i_block[0], block_buffer_vec.data()) != 0) return -EIO; + actual_bytes_copied = std::min(size - 1, symlink_target_len); // 为null终止符留空间 + if (actual_bytes_copied > 0) { + std::memcpy(buf, block_buffer_vec.data(), actual_bytes_copied); + } + } + + buf[actual_bytes_copied] = '\0'; // 总是null终止缓冲区 + + inode_data.i_atime = time(nullptr); + if (write_inode_to_disk(*context, inode_num, &inode_data) != 0) { + std::cerr << "readlink: inode " << inode_num << " atime更新失败" << std::endl; + } + return 0; // 成功时readlink应返回0,并填充缓冲区 +} + +// 创建硬链接 +int simplefs_link(const char *oldpath, const char *newpath) { + SimpleFS_Context* context = get_fs_context(); + if (!context) return -EACCES; + + std::string oldpath_str(oldpath); + std::string newpath_str(newpath); + + // 1. 解析oldpath到其inode + errno = 0; + uint32_t target_inode_num = path_to_inode_num(oldpath_str.c_str()); + if (target_inode_num == 0) return -errno; + + SimpleFS_Inode target_inode_data; + if (read_inode_from_disk(*context, target_inode_num, &target_inode_data) != 0) return -errno; + + // 硬链接到目录是不允许的 + if (S_ISDIR(target_inode_data.i_mode)) return -EPERM; + + // 2. 解析newpath的父目录 + std::string new_dirname_str, new_basename_str; + parse_path(newpath_str, new_dirname_str, new_basename_str); + + if (new_basename_str.empty() || new_basename_str == "." || new_basename_str == ".." || new_basename_str == "/") return -EINVAL; + if (new_basename_str.length() > SIMPLEFS_MAX_FILENAME_LEN) return -ENAMETOOLONG; + + errno = 0; + uint32_t parent_inode_num = path_to_inode_num(new_dirname_str.c_str()); + if (parent_inode_num == 0) return -errno; + + SimpleFS_Inode parent_inode_data; + if (read_inode_from_disk(*context, parent_inode_num, &parent_inode_data) != 0) return -errno; + + if (!S_ISDIR(parent_inode_data.i_mode)) return -ENOTDIR; + + // 3. 检查父目录权限 + int access_res = check_access(fuse_get_context(), &parent_inode_data, W_OK | X_OK); + if (access_res != 0) return access_res; + + // 4. 检查newpath是否已存在 + errno = 0; + uint32_t existing_inode_check = resolve_path_recursive(newpath_str.c_str(), 0, false); + if (existing_inode_check != 0) return -EEXIST; + if (errno != 0 && errno != ENOENT) return -errno; + + // 5. 为新硬链接添加目录条目 + uint8_t dentry_file_type = (target_inode_data.i_mode & S_IFMT) >> 12; + int add_entry_res = add_dir_entry(*context, &parent_inode_data, parent_inode_num, new_basename_str, target_inode_num, dentry_file_type); + if (add_entry_res != 0) return add_entry_res; + + // 6. 增加目标inode的链接数 + target_inode_data.i_links_count++; + target_inode_data.i_ctime = time(nullptr); + if (write_inode_to_disk(*context, target_inode_num, &target_inode_data) != 0) { + // 尝试回滚目录条目添加 + remove_dir_entry(*context, &parent_inode_data, parent_inode_num, new_basename_str); + return -errno; + } + + sync_fs_metadata(*context); + return 0; +} + +// 以纳秒精度更改文件的访问和修改时间 +int simplefs_utimens(const char *path, const struct timespec tv[2]) { + SimpleFS_Context* context = get_fs_context(); + if (!context) return -EACCES; + errno = 0; + uint32_t inode_num = path_to_inode_num(path); // 跟随符号链接进行utimens + if (inode_num == 0) return -errno; + SimpleFS_Inode inode_data; + if (read_inode_from_disk(*context, inode_num, &inode_data) != 0) return -errno; + + struct fuse_context *caller_ctx = fuse_get_context(); + bool specific_times_given = true; + if (tv == nullptr) { + specific_times_given = false; + } else { + #ifndef UTIME_NOW + #define UTIME_NOW ((1l << 30) - 1l) + #endif + #ifndef UTIME_OMIT + #define UTIME_OMIT ((1l << 30) - 2l) + #endif + if ((tv[0].tv_nsec == UTIME_NOW || tv[0].tv_nsec == UTIME_OMIT) && + (tv[1].tv_nsec == UTIME_NOW || tv[1].tv_nsec == UTIME_OMIT)) { + if (tv[0].tv_nsec == UTIME_OMIT && tv[1].tv_nsec == UTIME_OMIT) { + // 无变化 + } else { + specific_times_given = false; + } + } + } + if (specific_times_given) { + if (caller_ctx->uid != 0 && caller_ctx->uid != inode_data.i_uid) return -EPERM; + } else { + int access_res = check_access(caller_ctx, &inode_data, W_OK); + if (access_res != 0) return access_res; + } + time_t current_time = time(nullptr); + if (tv == nullptr) { + inode_data.i_atime = current_time; + inode_data.i_mtime = current_time; + } else { + #ifndef UTIME_NOW // 如果全局包含中不可用则在本地重新定义 + #define UTIME_NOW ((1l << 30) - 1l) + #endif + #ifndef UTIME_OMIT + #define UTIME_OMIT ((1l << 30) - 2l) + #endif + if (tv[0].tv_nsec != UTIME_OMIT) { + inode_data.i_atime = (tv[0].tv_nsec == UTIME_NOW) ? current_time : tv[0].tv_sec; + } + if (tv[1].tv_nsec != UTIME_OMIT) { + inode_data.i_mtime = (tv[1].tv_nsec == UTIME_NOW) ? current_time : tv[1].tv_sec; + } + } + inode_data.i_ctime = current_time; + if (write_inode_to_disk(*context, inode_num, &inode_data) != 0) return -errno; + return 0; +} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..d3e57d0 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,113 @@ +#include +#include "fuse_ops.h" // init_fuse_operations和SimpleFS_Context +#include "disk_io.h" // read_block等 +#include "simplefs.h" // 结构体 +#include "utils.h" // is_block_device + +#include +#include +#include +#include // memset, strerror +#include // errno +#include // open +#include // close +#include // ceil + +static SimpleFS_Context fs_context; // 全局文件系统上下文 + +int main(int argc, char *argv[]) { + if (argc < 3) { + std::cerr << "用法: " << argv[0] << " <设备文件> <挂载点> [FUSE选项...]" << std::endl; + return 1; + } + + // 设备镜像路径是argv[1] + // 挂载点是argv[2] + // FUSE选项从argv[2]开始,如果我们移位的话,或者手动处理 + // 保持简单:FUSE选项在挂载点之后传递 + + std::string device_path = argv[1]; + fs_context.device_fd = open(device_path.c_str(), O_RDWR); + if (fs_context.device_fd < 0) { + perror("无法打开设备文件"); + return 1; + } + + // 读取超级块 + std::vector sb_buffer(SIMPLEFS_BLOCK_SIZE); + if (read_block(fs_context.device_fd, 1, sb_buffer.data()) != 0) { // 超级块在块1 + std::cerr << "无法读取超级块" << std::endl; + close(fs_context.device_fd); + return 1; + } + std::memcpy(&fs_context.sb, sb_buffer.data(), sizeof(SimpleFS_SuperBlock)); + + // 验证超级块魔数 + if (fs_context.sb.s_magic != SIMPLEFS_MAGIC) { + std::cerr << "魔数不匹配,不是有效的SimpleFS文件系统" << std::endl; + close(fs_context.device_fd); + return 1; + } + + std::cout << "SimpleFS已加载 - 块总数: " << fs_context.sb.s_blocks_count + << ", 空闲块: " << fs_context.sb.s_free_blocks_count << std::endl; + + + // 读取组描述符表(GDT) + uint32_t num_block_groups = static_cast(std::ceil(static_cast(fs_context.sb.s_blocks_count) / fs_context.sb.s_blocks_per_group)); + if (num_block_groups == 0 && fs_context.sb.s_blocks_count > 0) num_block_groups = 1; + + + uint32_t gdt_size_bytes = num_block_groups * sizeof(SimpleFS_GroupDesc); + uint32_t gdt_blocks_count = static_cast(std::ceil(static_cast(gdt_size_bytes) / SIMPLEFS_BLOCK_SIZE)); + + fs_context.gdt.resize(num_block_groups); + std::vector gdt_buffer_raw(gdt_blocks_count * SIMPLEFS_BLOCK_SIZE); + + uint32_t gdt_start_block = 1 + 1; // 超级块在块1,GDT从块2开始 + + for (uint32_t i = 0; i < gdt_blocks_count; ++i) { + if (read_block(fs_context.device_fd, gdt_start_block + i, gdt_buffer_raw.data() + (i * SIMPLEFS_BLOCK_SIZE)) != 0) { + std::cerr << "无法读取组描述符表" << std::endl; + close(fs_context.device_fd); + return 1; + } + } + std::memcpy(fs_context.gdt.data(), gdt_buffer_raw.data(), gdt_size_bytes); + + // 准备FUSE参数 + bool is_blk_dev = is_block_device(fs_context.device_fd); + bool allow_other_found = false; + for (int i = 0; i < argc; ++i) { + if (std::string(argv[i]) == "-o" && (i + 1 < argc) && std::string(argv[i+1]).find("allow_other") != std::string::npos) { + allow_other_found = true; + break; + } + if (std::string(argv[i]).find("-oallow_other") != std::string::npos) { + allow_other_found = true; + break; + } + } + + std::vector fuse_argv_vec; + fuse_argv_vec.push_back(argv[0]); // 程序名 + // 添加原始参数,除了设备路径 + for (int i = 2; i < argc; ++i) { + fuse_argv_vec.push_back(argv[i]); + } + + if (!allow_other_found) { + fuse_argv_vec.push_back(const_cast("-o")); + fuse_argv_vec.push_back(const_cast("allow_other")); + } + + struct fuse_operations simplefs_ops; + init_fuse_operations(&simplefs_ops); + + // 传递上下文给FUSE + int ret = fuse_main(fuse_argv_vec.size(), fuse_argv_vec.data(), &simplefs_ops, &fs_context); + + close(fs_context.device_fd); + + return ret; +} diff --git a/src/metadata.cpp b/src/metadata.cpp new file mode 100644 index 0000000..b6dadb7 --- /dev/null +++ b/src/metadata.cpp @@ -0,0 +1,1022 @@ +#include "metadata.h" +#include "disk_io.h" +#include "simplefs.h" +#include +#include +#include "simplefs_context.h" +#include "utils.h" +#include +#include +#include +#include +#include +#include +#include +#include + +// 分配可用的inode +uint32_t alloc_inode(SimpleFS_Context& context, mode_t mode) { + if (context.sb.s_free_inodes_count == 0) { + errno = ENOSPC; + return 0; + } + + for (uint32_t group_idx = 0; group_idx < context.gdt.size(); ++group_idx) { + SimpleFS_GroupDesc& gd = context.gdt[group_idx]; + if (gd.bg_free_inodes_count > 0) { + std::vector inode_bitmap_data(SIMPLEFS_BLOCK_SIZE); + if (read_block(context.device_fd, gd.bg_inode_bitmap, inode_bitmap_data.data()) != 0) { + continue; + } + + for (uint32_t bit_idx = 0; bit_idx < context.sb.s_inodes_per_group; ++bit_idx) { + if (!is_bitmap_bit_set(inode_bitmap_data, bit_idx)) { + uint32_t inode_num = (group_idx * context.sb.s_inodes_per_group) + bit_idx + 1; + + if (inode_num == 0 || inode_num > context.sb.s_inodes_count) { + continue; + } + + set_bitmap_bit(inode_bitmap_data, bit_idx); + if (write_block(context.device_fd, gd.bg_inode_bitmap, inode_bitmap_data.data()) != 0) { + errno = EIO; + return 0; + } + + gd.bg_free_inodes_count--; + context.sb.s_free_inodes_count--; + if (S_ISDIR(mode)) { + gd.bg_used_dirs_count++; + } + + return inode_num; + } + } + } + } + errno = ENOSPC; + return 0; +} + +// 释放inode +void free_inode(SimpleFS_Context& context, uint32_t inode_num, mode_t mode_of_freed_inode) { + if (inode_num == 0 || inode_num > context.sb.s_inodes_count) { + return; + } + if (inode_num < context.sb.s_first_ino && inode_num != 0) { + return; + } + + uint32_t group_idx = (inode_num - 1) / context.sb.s_inodes_per_group; + if (group_idx >= context.gdt.size()) { + return; + } + SimpleFS_GroupDesc& gd = context.gdt[group_idx]; + uint32_t bit_idx = (inode_num - 1) % context.sb.s_inodes_per_group; + + std::vector inode_bitmap_data(SIMPLEFS_BLOCK_SIZE); + if (read_block(context.device_fd, gd.bg_inode_bitmap, inode_bitmap_data.data()) != 0) { + return; + } + + clear_bitmap_bit(inode_bitmap_data, bit_idx); + if (write_block(context.device_fd, gd.bg_inode_bitmap, inode_bitmap_data.data()) != 0) { + return; + } + + gd.bg_free_inodes_count++; + context.sb.s_free_inodes_count++; + + if (S_ISDIR(mode_of_freed_inode)) { + if (gd.bg_used_dirs_count > 0) gd.bg_used_dirs_count--; + } +} + +#include + +// 分配数据块 +uint32_t alloc_block(SimpleFS_Context& context, uint32_t preferred_group_for_inode) { + // 简化的一致性检查 + if (context.sb.s_free_blocks_count == 0) { + errno = ENOSPC; + return 0; + } + + uint32_t target_group_idx = static_cast(-1); + uint32_t num_groups = context.gdt.size(); + + // 优先尝试首选组 + if (preferred_group_for_inode < num_groups) { + if (context.gdt[preferred_group_for_inode].bg_free_blocks_count > 0) { + target_group_idx = preferred_group_for_inode; + } + } + + // 如果首选组不可用,搜索所有组 + if (target_group_idx == static_cast(-1)) { + for (uint32_t i = 0; i < num_groups; ++i) { + if (context.gdt[i].bg_free_blocks_count > 0) { + target_group_idx = i; + break; + } + } + } + + if (target_group_idx == static_cast(-1)) { + errno = ENOSPC; + return 0; + } + + SimpleFS_GroupDesc& gd = context.gdt[target_group_idx]; + std::vector block_bitmap_data(SIMPLEFS_BLOCK_SIZE); + + if (read_block(context.device_fd, gd.bg_block_bitmap, block_bitmap_data.data()) != 0) { + errno = EIO; + return 0; + } + + for (uint32_t bit_idx = 0; bit_idx < context.sb.s_blocks_per_group; ++bit_idx) { + if (!is_bitmap_bit_set(block_bitmap_data, bit_idx)) { + uint32_t block_num = (target_group_idx * context.sb.s_blocks_per_group) + bit_idx; + + if (block_num == 0 && target_group_idx == 0 && bit_idx == 0) { + continue; + } + if (block_num >= context.sb.s_blocks_count) { + continue; + } + + set_bitmap_bit(block_bitmap_data, bit_idx); + if (write_block(context.device_fd, gd.bg_block_bitmap, block_bitmap_data.data()) != 0) { + errno = EIO; + return 0; + } + + gd.bg_free_blocks_count--; + context.sb.s_free_blocks_count--; + + return block_num; + } + } + + errno = ENOSPC; + return 0; +} + +// 释放数据块 +void free_block(SimpleFS_Context& context, uint32_t block_num) { + if (block_num == 0 || block_num >= context.sb.s_blocks_count) { + return; + } + + uint32_t group_idx = block_num / context.sb.s_blocks_per_group; + if (group_idx >= context.gdt.size()) { + return; + } + SimpleFS_GroupDesc& gd = context.gdt[group_idx]; + uint32_t bit_idx = block_num % context.sb.s_blocks_per_group; + + std::vector block_bitmap_data(SIMPLEFS_BLOCK_SIZE); + if (read_block(context.device_fd, gd.bg_block_bitmap, block_bitmap_data.data()) != 0) { + return; + } + + clear_bitmap_bit(block_bitmap_data, bit_idx); + if (write_block(context.device_fd, gd.bg_block_bitmap, block_bitmap_data.data()) != 0) { + return; + } + + gd.bg_free_blocks_count++; + context.sb.s_free_blocks_count++; +} + +// 将inode数据写入磁盘 +int write_inode_to_disk(SimpleFS_Context& context, uint32_t inode_num, const SimpleFS_Inode* inode_data) { + if (inode_num == 0 || inode_num > context.sb.s_inodes_count) { + errno = EINVAL; + return -EINVAL; + } + + uint32_t group_idx = (inode_num - 1) / context.sb.s_inodes_per_group; + if (group_idx >= context.gdt.size()) { + errno = EIO; + return -EIO; + } + const SimpleFS_GroupDesc& gd = context.gdt[group_idx]; + + uint32_t inode_offset_in_group = (inode_num - 1) % context.sb.s_inodes_per_group; + uint32_t inodes_per_block = SIMPLEFS_BLOCK_SIZE / sizeof(SimpleFS_Inode); + + uint32_t block_num_in_table = inode_offset_in_group / inodes_per_block; + uint32_t offset_within_block = (inode_offset_in_group % inodes_per_block) * sizeof(SimpleFS_Inode); + + uint32_t absolute_block_rw = gd.bg_inode_table + block_num_in_table; + + if (absolute_block_rw == 0 || absolute_block_rw >= context.sb.s_blocks_count) { + errno = EIO; + return -EIO; + } + + std::vector block_buffer(SIMPLEFS_BLOCK_SIZE); + if (read_block(context.device_fd, absolute_block_rw, block_buffer.data()) != 0) { + return -EIO; + } + + std::memcpy(block_buffer.data() + offset_within_block, inode_data, sizeof(SimpleFS_Inode)); + + if (write_block(context.device_fd, absolute_block_rw, block_buffer.data()) != 0) { + return -EIO; + } + return 0; +} + +// 从磁盘读取inode数据 +int read_inode_from_disk(SimpleFS_Context& context, uint32_t inode_num, SimpleFS_Inode* inode_struct) { + if (inode_num == 0 || inode_num > context.sb.s_inodes_count) { + errno = EINVAL; + return -EINVAL; + } + + uint32_t group_idx = (inode_num - 1) / context.sb.s_inodes_per_group; + if (group_idx >= context.gdt.size()) { + errno = EIO; + return -EIO; + } + const SimpleFS_GroupDesc& gd = context.gdt[group_idx]; + + uint32_t inode_offset_in_group = (inode_num - 1) % context.sb.s_inodes_per_group; + uint32_t inodes_per_block = SIMPLEFS_BLOCK_SIZE / sizeof(SimpleFS_Inode); + + uint32_t block_num_in_table = inode_offset_in_group / inodes_per_block; + uint32_t offset_within_block = (inode_offset_in_group % inodes_per_block) * sizeof(SimpleFS_Inode); + + uint32_t absolute_block_to_read = gd.bg_inode_table + block_num_in_table; + + if (absolute_block_to_read == 0 || absolute_block_to_read >= context.sb.s_blocks_count) { + errno = EIO; + return -EIO; + } + + std::vector block_buffer(SIMPLEFS_BLOCK_SIZE); + + if (read_block(context.device_fd, absolute_block_to_read, block_buffer.data()) != 0) { + return -EIO; + } + + std::memcpy(inode_struct, block_buffer.data() + offset_within_block, sizeof(SimpleFS_Inode)); + return 0; +} + + +// 向目录中添加文件项 +int add_dir_entry(SimpleFS_Context& context, SimpleFS_Inode* parent_inode, uint32_t parent_inode_num, + const std::string& entry_name, uint32_t child_inode_num, uint8_t file_type) { + if (entry_name.length() > SIMPLEFS_MAX_FILENAME_LEN) { + errno = ENAMETOOLONG; + return -ENAMETOOLONG; + } + + uint16_t needed_len_for_new_entry = calculate_dir_entry_len(entry_name.length()); + uint16_t min_rec_len_for_empty = calculate_dir_entry_len(0); + + std::vector dir_block_data_buffer(SIMPLEFS_BLOCK_SIZE); + uint32_t pointers_per_block = SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t); + uint32_t max_logical_blocks = SIMPLEFS_NUM_DIRECT_BLOCKS + + pointers_per_block + + pointers_per_block * pointers_per_block + + pointers_per_block * pointers_per_block * pointers_per_block; + + bool entry_placed = false; + + for (uint32_t logical_block_idx = 0; logical_block_idx < max_logical_blocks; ++logical_block_idx) { + uint32_t current_physical_block = get_or_alloc_dir_block(context, parent_inode, parent_inode_num, logical_block_idx); + if (current_physical_block == 0) { + if (errno == 0) errno = ENOSPC; + return -errno; + } + + if (read_block(context.device_fd, current_physical_block, dir_block_data_buffer.data()) != 0) { + errno = EIO; + return -EIO; + } + + uint16_t current_offset = 0; + while(current_offset < SIMPLEFS_BLOCK_SIZE) { + SimpleFS_DirEntry* dir_entry = reinterpret_cast(dir_block_data_buffer.data() + current_offset); + + if (dir_entry->rec_len == 0) { + if (current_offset == 0 && SIMPLEFS_BLOCK_SIZE >= needed_len_for_new_entry) { + dir_entry->inode = child_inode_num; + dir_entry->name_len = static_cast(entry_name.length()); + dir_entry->file_type = file_type; + std::strncpy(dir_entry->name, entry_name.c_str(), entry_name.length()); + dir_entry->rec_len = SIMPLEFS_BLOCK_SIZE; + entry_placed = true; + break; + } + goto next_block; + } + + uint16_t actual_len_of_current_entry = calculate_dir_entry_len(dir_entry->name_len); + + // 尝试使用空条目 + if (dir_entry->inode == 0 && dir_entry->rec_len >= needed_len_for_new_entry) { + uint16_t original_empty_rec_len = dir_entry->rec_len; + + dir_entry->inode = child_inode_num; + dir_entry->name_len = static_cast(entry_name.length()); + dir_entry->file_type = file_type; + std::strncpy(dir_entry->name, entry_name.c_str(), entry_name.length()); + dir_entry->rec_len = needed_len_for_new_entry; + + uint16_t space_left_after_new_entry = original_empty_rec_len - needed_len_for_new_entry; + + if (space_left_after_new_entry > 0) { + if (space_left_after_new_entry < min_rec_len_for_empty) { + dir_entry->rec_len += space_left_after_new_entry; + } else { + SimpleFS_DirEntry* remainder_entry = reinterpret_cast(dir_block_data_buffer.data() + current_offset + needed_len_for_new_entry); + remainder_entry->inode = 0; + remainder_entry->name_len = 0; + remainder_entry->file_type = 0; + remainder_entry->rec_len = space_left_after_new_entry; + } + } + entry_placed = true; + break; + } + + // 尝试使用现有活动条目的空白填充 + uint16_t original_rec_len_of_active_entry = dir_entry->rec_len; + if (dir_entry->inode != 0 && (original_rec_len_of_active_entry - actual_len_of_current_entry >= needed_len_for_new_entry)) { + uint16_t padding_available = original_rec_len_of_active_entry - actual_len_of_current_entry; + + dir_entry->rec_len = actual_len_of_current_entry; + + SimpleFS_DirEntry* new_entry_spot = reinterpret_cast(dir_block_data_buffer.data() + current_offset + actual_len_of_current_entry); + new_entry_spot->inode = child_inode_num; + new_entry_spot->name_len = static_cast(entry_name.length()); + new_entry_spot->file_type = file_type; + std::strncpy(new_entry_spot->name, entry_name.c_str(), entry_name.length()); + new_entry_spot->rec_len = needed_len_for_new_entry; + + uint16_t space_left_for_final_empty = padding_available - needed_len_for_new_entry; + + if (space_left_for_final_empty > 0) { + if (space_left_for_final_empty < min_rec_len_for_empty) { + new_entry_spot->rec_len += space_left_for_final_empty; + } else { + SimpleFS_DirEntry* final_empty_entry = reinterpret_cast( (uint8_t*)new_entry_spot + needed_len_for_new_entry ); + final_empty_entry->inode = 0; + final_empty_entry->name_len = 0; + final_empty_entry->file_type = 0; + final_empty_entry->rec_len = space_left_for_final_empty; + } + } + entry_placed = true; + break; + } + + // 如果这是块中的最后一个条目 + if (current_offset + dir_entry->rec_len >= SIMPLEFS_BLOCK_SIZE) { + if (dir_entry->inode != 0 && (current_offset + actual_len_of_current_entry + needed_len_for_new_entry <= SIMPLEFS_BLOCK_SIZE) ) { + dir_entry->rec_len = actual_len_of_current_entry; + + SimpleFS_DirEntry* new_entry_location = reinterpret_cast(dir_block_data_buffer.data() + current_offset + actual_len_of_current_entry); + new_entry_location->inode = child_inode_num; + new_entry_location->name_len = static_cast(entry_name.length()); + new_entry_location->file_type = file_type; + std::strncpy(new_entry_location->name, entry_name.c_str(), entry_name.length()); + new_entry_location->rec_len = SIMPLEFS_BLOCK_SIZE - (current_offset + actual_len_of_current_entry); + entry_placed = true; + } + break; + } + current_offset += dir_entry->rec_len; + } + + if (entry_placed) { + if (write_block(context.device_fd, current_physical_block, dir_block_data_buffer.data()) != 0) { + errno = EIO; return -EIO; + } + + // 更新父目录大小 + uint32_t size_if_this_block_is_last = (logical_block_idx + 1) * SIMPLEFS_BLOCK_SIZE; + if (parent_inode->i_size < size_if_this_block_is_last) { + parent_inode->i_size = size_if_this_block_is_last; + } + + parent_inode->i_mtime = parent_inode->i_ctime = time(nullptr); + if (write_inode_to_disk(context, parent_inode_num, parent_inode) != 0) { + return -EIO; + } + return 0; + } + next_block:; + } + + errno = ENOSPC; + return -ENOSPC; +} + +// 从目录中删除文件项 +int remove_dir_entry(SimpleFS_Context& context, SimpleFS_Inode* parent_inode, uint32_t parent_inode_num, const std::string& entry_name_to_remove) { + if (entry_name_to_remove.empty() || entry_name_to_remove == "." || entry_name_to_remove == "..") { + errno = EINVAL; + return -EINVAL; + } + + std::vector dir_block_data_buffer(SIMPLEFS_BLOCK_SIZE); + bool entry_found_and_removed = false; + + uint32_t num_data_blocks_in_dir = (parent_inode->i_size + SIMPLEFS_BLOCK_SIZE - 1) / SIMPLEFS_BLOCK_SIZE; + if (parent_inode->i_size == 0) num_data_blocks_in_dir = 0; + + for (uint32_t logical_block_idx = 0; logical_block_idx < num_data_blocks_in_dir; ++logical_block_idx) { + uint32_t current_physical_block = map_logical_to_physical_block(context, parent_inode, logical_block_idx); + + if (current_physical_block == 0) { + continue; + } + + if (read_block(context.device_fd, current_physical_block, dir_block_data_buffer.data()) != 0) { + errno = EIO; + return -EIO; + } + + uint16_t current_offset = 0; + SimpleFS_DirEntry* prev_entry = nullptr; + + // 计算此块中的有效数据范围 + uint32_t block_start_byte_offset = logical_block_idx * SIMPLEFS_BLOCK_SIZE; + uint32_t max_offset_in_block = SIMPLEFS_BLOCK_SIZE; + if (block_start_byte_offset + SIMPLEFS_BLOCK_SIZE > parent_inode->i_size) { + max_offset_in_block = parent_inode->i_size % SIMPLEFS_BLOCK_SIZE; + if (max_offset_in_block == 0 && parent_inode->i_size > 0) max_offset_in_block = SIMPLEFS_BLOCK_SIZE; + } + + while (current_offset < max_offset_in_block) { + SimpleFS_DirEntry* current_entry = reinterpret_cast(dir_block_data_buffer.data() + current_offset); + + if (current_entry->rec_len == 0) { + break; + } + uint16_t min_possible_rec_len = calculate_dir_entry_len(0); + if (current_entry->inode != 0 && current_entry->name_len > 0) { + min_possible_rec_len = calculate_dir_entry_len(current_entry->name_len); + } + + if (current_entry->rec_len < min_possible_rec_len || (current_offset + current_entry->rec_len > SIMPLEFS_BLOCK_SIZE) ) { + errno = EIO; + return -EIO; + } + + if (current_entry->inode != 0) { + if (entry_name_to_remove.length() == current_entry->name_len && + strncmp(current_entry->name, entry_name_to_remove.c_str(), current_entry->name_len) == 0) { + + // 找到要删除的条目 + if (prev_entry != nullptr) { + // 将此条目的长度合并到前一个条目 + prev_entry->rec_len += current_entry->rec_len; + } else { + // 这是块中的第一个条目,标记为未使用 + current_entry->inode = 0; + } + entry_found_and_removed = true; + break; + } + } + + prev_entry = current_entry; + current_offset += current_entry->rec_len; + } + + if (entry_found_and_removed) { + if (write_block(context.device_fd, current_physical_block, dir_block_data_buffer.data()) != 0) { + errno = EIO; + return -EIO; + } + + parent_inode->i_mtime = parent_inode->i_ctime = time(nullptr); + if (write_inode_to_disk(context, parent_inode_num, parent_inode) != 0) { + return -EIO; + } + return 0; + } + } + + errno = ENOENT; + return -ENOENT; +} + + +// 同步文件系统元数据到磁盘 +void sync_fs_metadata(SimpleFS_Context& context) { + // 写入超级块 + std::vector sb_block_buffer(SIMPLEFS_BLOCK_SIZE, 0); + std::memcpy(sb_block_buffer.data(), &(context.sb), sizeof(SimpleFS_SuperBlock)); + if (write_block(context.device_fd, 1, sb_block_buffer.data()) != 0) { + return; + } + + // 写入组描述符表(GDT) + if (context.gdt.empty()) { + return; + } + + uint32_t gdt_size_bytes = context.gdt.size() * sizeof(SimpleFS_GroupDesc); + uint32_t gdt_blocks_count = static_cast(std::ceil(static_cast(gdt_size_bytes) / SIMPLEFS_BLOCK_SIZE)); + uint32_t gdt_start_block = 1 + 1; // 超级块在块1,GDT从块2开始 + + std::vector gdt_one_block_buffer(SIMPLEFS_BLOCK_SIZE, 0); + const uint8_t* gdt_data_ptr = reinterpret_cast(context.gdt.data()); + + for (uint32_t i = 0; i < gdt_blocks_count; ++i) { + std::fill(gdt_one_block_buffer.begin(), gdt_one_block_buffer.end(), 0); + + uint32_t bytes_to_copy_this_block = SIMPLEFS_BLOCK_SIZE; + uint32_t offset_in_gdt_data = i * SIMPLEFS_BLOCK_SIZE; + + if (offset_in_gdt_data >= gdt_size_bytes) break; + + if (offset_in_gdt_data + bytes_to_copy_this_block > gdt_size_bytes) { + bytes_to_copy_this_block = gdt_size_bytes - offset_in_gdt_data; + } + + if (bytes_to_copy_this_block > 0) { + std::memcpy(gdt_one_block_buffer.data(), gdt_data_ptr + offset_in_gdt_data, bytes_to_copy_this_block); + } + + write_block(context.device_fd, gdt_start_block + i, gdt_one_block_buffer.data()); + } + + // 写入备份副本 + uint32_t num_groups = context.gdt.size(); + for (uint32_t grp = 1; grp < num_groups; ++grp) { + if (!is_backup_group(grp)) continue; + uint32_t grp_start = grp * context.sb.s_blocks_per_group; + write_block(context.device_fd, grp_start, sb_block_buffer.data()); + + for (uint32_t i = 0; i < gdt_blocks_count; ++i) { + std::fill(gdt_one_block_buffer.begin(), gdt_one_block_buffer.end(), 0); + uint32_t bytes_to_copy_this_block = SIMPLEFS_BLOCK_SIZE; + uint32_t offset_in_gdt_data = i * SIMPLEFS_BLOCK_SIZE; + if (offset_in_gdt_data >= gdt_size_bytes) break; + if (offset_in_gdt_data + bytes_to_copy_this_block > gdt_size_bytes) { + bytes_to_copy_this_block = gdt_size_bytes - offset_in_gdt_data; + } + if (bytes_to_copy_this_block > 0) { + std::memcpy(gdt_one_block_buffer.data(), gdt_data_ptr + offset_in_gdt_data, bytes_to_copy_this_block); + } + write_block(context.device_fd, grp_start + 1 + i, gdt_one_block_buffer.data()); + } + } +} + +// 检查文件访问权限 +int check_access(const struct fuse_context* caller_context, const SimpleFS_Inode* inode, int requested_perm) { + if (!caller_context || !inode) { + return -EINVAL; + } + + // root用户拥有所有权限 + if (caller_context->uid == 0) { + return 0; + } + + uint16_t mode = inode->i_mode; + uint16_t perms_to_check = 0; + + if (caller_context->uid == inode->i_uid) { // 文件所有者 + perms_to_check = (mode & S_IRWXU) >> 6; + } else { // 检查组权限 + bool in_group = false; + if (caller_context->gid == inode->i_gid) { + in_group = true; + } else { // 检查附加组 + int num_supp_groups = getgroups(0, nullptr); + if (num_supp_groups > 0) { + std::vector supp_group_list(num_supp_groups); + if (getgroups(num_supp_groups, supp_group_list.data()) >= 0) { + for (gid_t supp_gid : supp_group_list) { + if (supp_gid == inode->i_gid) { + in_group = true; + break; + } + } + } + } + } + + if (in_group) { + perms_to_check = (mode & S_IRWXG) >> 3; + } else { // 其他用户 + perms_to_check = (mode & S_IRWXO); + } + } + + if ((requested_perm & R_OK) && !(perms_to_check & 0x4)) { + errno = EACCES; + return -EACCES; + } + if ((requested_perm & W_OK) && !(perms_to_check & 0x2)) { + errno = EACCES; + return -EACCES; + } + if ((requested_perm & X_OK) && !(perms_to_check & 0x1)) { + errno = EACCES; + return -EACCES; + } + + return 0; +} + +// 递归释放块树结构 +static void free_block_tree_recursive(SimpleFS_Context& context, uint32_t block_num, int level) { + if (block_num == 0) { + return; + } + + if (level == 0) { // 数据块 + free_block(context, block_num); + return; + } + + // 间接块,需要读取并释放其子块 + std::vector indirect_block_content(SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t)); + if (read_block(context.device_fd, block_num, indirect_block_content.data()) != 0) { + return; + } + + // 递归释放子块 + for (uint32_t child_block_num : indirect_block_content) { + if (child_block_num != 0) { + free_block_tree_recursive(context, child_block_num, level - 1); + } + } + + // 释放间接块本身 + free_block(context, block_num); +} + +// 释放inode关联的所有数据块 +void free_all_inode_blocks(SimpleFS_Context& context, SimpleFS_Inode* inode) { + if (!inode) { + return; + } + + // 释放直接块 + for (int i = 0; i < SIMPLEFS_NUM_DIRECT_BLOCKS; ++i) { + if (inode->i_block[i] != 0) { + free_block(context, inode->i_block[i]); + } + } + + // 释放间接块结构 + free_block_tree_recursive(context, inode->i_block[SIMPLEFS_NUM_DIRECT_BLOCKS], 1); // 一级间接 + free_block_tree_recursive(context, inode->i_block[SIMPLEFS_NUM_DIRECT_BLOCKS + 1], 2); // 二级间接 + free_block_tree_recursive(context, inode->i_block[SIMPLEFS_NUM_DIRECT_BLOCKS + 2], 3); // 三级间接 + + // 重置inode块指针 + std::memset(inode->i_block, 0, sizeof(uint32_t) * SIMPLEFS_INODE_BLOCK_PTRS); + inode->i_blocks = 0; +} + +// 获取或分配目录数据块 +uint32_t get_or_alloc_dir_block(SimpleFS_Context& context, SimpleFS_Inode* dir_inode, uint32_t dir_inode_num, uint32_t logical_block_idx) { + if (!dir_inode) { errno = EIO; return 0; } + + uint32_t preferred_group = (dir_inode_num - 1) / context.sb.s_inodes_per_group; + uint32_t pointers_per_block = SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t); + std::vector indirect_block_content(pointers_per_block); + std::vector zero_block_buffer(SIMPLEFS_BLOCK_SIZE, 0); + + // 直接块 + if (logical_block_idx < SIMPLEFS_NUM_DIRECT_BLOCKS) { + if (dir_inode->i_block[logical_block_idx] == 0) { + uint32_t new_data_block = alloc_block(context, preferred_group); + if (new_data_block == 0) { return 0; } + if (write_block(context.device_fd, new_data_block, zero_block_buffer.data()) != 0) { + errno = EIO; + return 0; + } + dir_inode->i_block[logical_block_idx] = new_data_block; + dir_inode->i_blocks += (SIMPLEFS_BLOCK_SIZE / 512); + } + return dir_inode->i_block[logical_block_idx]; + } + + // 一级间接块 + uint32_t single_indirect_start_idx = SIMPLEFS_NUM_DIRECT_BLOCKS; + uint32_t single_indirect_end_idx = single_indirect_start_idx + pointers_per_block; + if (logical_block_idx < single_indirect_end_idx) { + uint32_t* p_single_indirect_block_num = &dir_inode->i_block[SIMPLEFS_NUM_DIRECT_BLOCKS]; + if (*p_single_indirect_block_num == 0) { + uint32_t new_l1_block = alloc_block(context, preferred_group); + if (new_l1_block == 0) { errno = ENOSPC; return 0; } + dir_inode->i_blocks += (SIMPLEFS_BLOCK_SIZE / 512); + std::fill(indirect_block_content.begin(), indirect_block_content.end(), 0); + if (write_block(context.device_fd, new_l1_block, indirect_block_content.data()) != 0) { + free_block(context, new_l1_block); + dir_inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + errno = EIO; return 0; + } + *p_single_indirect_block_num = new_l1_block; + } + if (read_block(context.device_fd, *p_single_indirect_block_num, indirect_block_content.data()) != 0) { + errno = EIO; return 0; + } + + uint32_t idx_in_indirect = logical_block_idx - single_indirect_start_idx; + if (indirect_block_content[idx_in_indirect] == 0) { + uint32_t new_data_block = alloc_block(context, preferred_group); + if (new_data_block == 0) { errno = ENOSPC; return 0; } + if (write_block(context.device_fd, new_data_block, zero_block_buffer.data()) != 0) { + free_block(context, new_data_block); + errno = EIO; return 0; + } + + indirect_block_content[idx_in_indirect] = new_data_block; + dir_inode->i_blocks += (SIMPLEFS_BLOCK_SIZE / 512); + if (write_block(context.device_fd, *p_single_indirect_block_num, indirect_block_content.data()) != 0) { + free_block(context, new_data_block); + dir_inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + indirect_block_content[idx_in_indirect] = 0; + errno = EIO; return 0; + } + } + return indirect_block_content[idx_in_indirect]; + } + + // 二级间接块 + uint32_t double_indirect_start_idx = single_indirect_end_idx; + uint32_t double_indirect_max_logical_blocks = pointers_per_block * pointers_per_block; + uint32_t double_indirect_end_idx = double_indirect_start_idx + double_indirect_max_logical_blocks; + if (logical_block_idx < double_indirect_end_idx) { + uint32_t* p_dbl_indirect_block_num = &dir_inode->i_block[SIMPLEFS_NUM_DIRECT_BLOCKS + 1]; + if (*p_dbl_indirect_block_num == 0) { + uint32_t new_l2_block = alloc_block(context, preferred_group); + if (new_l2_block == 0) { errno = ENOSPC; return 0; } + dir_inode->i_blocks += (SIMPLEFS_BLOCK_SIZE / 512); + std::fill(indirect_block_content.begin(), indirect_block_content.end(), 0); + if (write_block(context.device_fd, new_l2_block, indirect_block_content.data()) != 0) { + free_block(context, new_l2_block); + dir_inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + errno = EIO; return 0; + } + *p_dbl_indirect_block_num = new_l2_block; + } + + std::vector l2_buffer(pointers_per_block); + if (read_block(context.device_fd, *p_dbl_indirect_block_num, l2_buffer.data()) != 0) { errno = EIO; return 0; } + + uint32_t logical_offset_in_dbl_range = logical_block_idx - double_indirect_start_idx; + uint32_t idx_in_l2_block = logical_offset_in_dbl_range / pointers_per_block; + + uint32_t* p_l1_block_num_from_l2 = &l2_buffer[idx_in_l2_block]; + if (*p_l1_block_num_from_l2 == 0) { + uint32_t new_l1_block = alloc_block(context, preferred_group); + if (new_l1_block == 0) { errno = ENOSPC; return 0;} + dir_inode->i_blocks += (SIMPLEFS_BLOCK_SIZE / 512); + std::fill(indirect_block_content.begin(), indirect_block_content.end(), 0); + if (write_block(context.device_fd, new_l1_block, indirect_block_content.data()) != 0) { + free_block(context, new_l1_block); + dir_inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + errno = EIO; return 0; + } + *p_l1_block_num_from_l2 = new_l1_block; + if (write_block(context.device_fd, *p_dbl_indirect_block_num, l2_buffer.data()) != 0) { + free_block(context, new_l1_block); + dir_inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + *p_l1_block_num_from_l2 = 0; + errno = EIO; return 0; + } + } + + std::vector l1_buffer(pointers_per_block); + if (read_block(context.device_fd, *p_l1_block_num_from_l2, l1_buffer.data()) != 0) { errno = EIO; return 0;} + + uint32_t idx_in_l1_block = logical_offset_in_dbl_range % pointers_per_block; + if (l1_buffer[idx_in_l1_block] == 0) { + uint32_t new_data_block = alloc_block(context, preferred_group); + if (new_data_block == 0) { errno = ENOSPC; return 0; } + if (write_block(context.device_fd, new_data_block, zero_block_buffer.data()) != 0) { + free_block(context, new_data_block); + errno = EIO; return 0; + } + + l1_buffer[idx_in_l1_block] = new_data_block; + dir_inode->i_blocks += (SIMPLEFS_BLOCK_SIZE / 512); + if (write_block(context.device_fd, *p_l1_block_num_from_l2, l1_buffer.data()) != 0) { + free_block(context, new_data_block); + dir_inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + l1_buffer[idx_in_l1_block] = 0; + errno = EIO; return 0; + } + } + return l1_buffer[idx_in_l1_block]; + } + + // 三级间接块 + uint32_t triple_indirect_start_idx = double_indirect_end_idx; + uint64_t triple_indirect_max_logical_blocks = (uint64_t)pointers_per_block * pointers_per_block * pointers_per_block; + uint64_t triple_indirect_end_idx = triple_indirect_start_idx + triple_indirect_max_logical_blocks; + + if (logical_block_idx < triple_indirect_end_idx) { + uint32_t* p_tpl_indirect_block_num = &dir_inode->i_block[SIMPLEFS_NUM_DIRECT_BLOCKS + 2]; + if (*p_tpl_indirect_block_num == 0) { + uint32_t new_l3_block = alloc_block(context, preferred_group); + if (new_l3_block == 0) { errno = ENOSPC; return 0; } + dir_inode->i_blocks += (SIMPLEFS_BLOCK_SIZE / 512); + std::fill(indirect_block_content.begin(), indirect_block_content.end(), 0); + if (write_block(context.device_fd, new_l3_block, indirect_block_content.data()) != 0) { + free_block(context, new_l3_block); + dir_inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + errno = EIO; return 0; + } + *p_tpl_indirect_block_num = new_l3_block; + } + + std::vector l3_buffer(pointers_per_block); + if (read_block(context.device_fd, *p_tpl_indirect_block_num, l3_buffer.data()) != 0) { errno = EIO; return 0; } + + uint32_t logical_offset_in_tpl_range = logical_block_idx - triple_indirect_start_idx; + uint32_t idx_in_l3_block = logical_offset_in_tpl_range / (pointers_per_block * pointers_per_block); + + uint32_t* p_l2_block_num_from_l3 = &l3_buffer[idx_in_l3_block]; + if (*p_l2_block_num_from_l3 == 0) { + uint32_t new_l2_block = alloc_block(context, preferred_group); + if (new_l2_block == 0) { errno = ENOSPC; return 0; } + dir_inode->i_blocks += (SIMPLEFS_BLOCK_SIZE / 512); + std::fill(indirect_block_content.begin(), indirect_block_content.end(), 0); + if (write_block(context.device_fd, new_l2_block, indirect_block_content.data()) != 0) { + free_block(context, new_l2_block); + dir_inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + errno = EIO; return 0; + } + *p_l2_block_num_from_l3 = new_l2_block; + if (write_block(context.device_fd, *p_tpl_indirect_block_num, l3_buffer.data()) != 0) { + free_block(context, new_l2_block); + dir_inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + *p_l2_block_num_from_l3 = 0; + errno = EIO; return 0; + } + } + + std::vector l2_buffer(pointers_per_block); + if (read_block(context.device_fd, *p_l2_block_num_from_l3, l2_buffer.data()) != 0) { errno = EIO; return 0; } + + uint32_t logical_offset_in_l2_from_tpl = logical_offset_in_tpl_range % (pointers_per_block * pointers_per_block); + uint32_t idx_in_l2_from_tpl = logical_offset_in_l2_from_tpl / pointers_per_block; + + uint32_t* p_l1_block_num_from_l2 = &l2_buffer[idx_in_l2_from_tpl]; + if (*p_l1_block_num_from_l2 == 0) { + uint32_t new_l1_block = alloc_block(context, preferred_group); + if (new_l1_block == 0) { errno = ENOSPC; return 0;} + dir_inode->i_blocks += (SIMPLEFS_BLOCK_SIZE / 512); + std::fill(indirect_block_content.begin(), indirect_block_content.end(), 0); + if (write_block(context.device_fd, new_l1_block, indirect_block_content.data()) != 0) { + free_block(context, new_l1_block); + dir_inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + errno = EIO; return 0; + } + *p_l1_block_num_from_l2 = new_l1_block; + if (write_block(context.device_fd, *p_l2_block_num_from_l3, l2_buffer.data()) != 0) { + free_block(context, new_l1_block); + dir_inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + *p_l1_block_num_from_l2 = 0; + errno = EIO; return 0; + } + } + + std::vector l1_buffer(pointers_per_block); + if (read_block(context.device_fd, *p_l1_block_num_from_l2, l1_buffer.data()) != 0) { errno = EIO; return 0; } + + uint32_t idx_in_l1_final = logical_offset_in_l2_from_tpl % pointers_per_block; + if (l1_buffer[idx_in_l1_final] == 0) { + uint32_t new_data_block = alloc_block(context, preferred_group); + if (new_data_block == 0) { errno = ENOSPC; return 0; } + if (write_block(context.device_fd, new_data_block, zero_block_buffer.data()) != 0) { + free_block(context, new_data_block); + errno = EIO; return 0; + } + + l1_buffer[idx_in_l1_final] = new_data_block; + dir_inode->i_blocks += (SIMPLEFS_BLOCK_SIZE / 512); + if (write_block(context.device_fd, *p_l1_block_num_from_l2, l1_buffer.data()) != 0) { + free_block(context, new_data_block); + dir_inode->i_blocks -= (SIMPLEFS_BLOCK_SIZE / 512); + l1_buffer[idx_in_l1_final] = 0; + errno = EIO; return 0; + } + } + return l1_buffer[idx_in_l1_final]; + } + + errno = EFBIG; + return 0; +} + + + +// 映射逻辑块到物理块(不分配) +uint32_t map_logical_to_physical_block(SimpleFS_Context& context, const SimpleFS_Inode* inode, uint32_t logical_block_idx) { + if (!inode) { errno = EINVAL; return 0; } + + if (logical_block_idx < SIMPLEFS_NUM_DIRECT_BLOCKS) { + return inode->i_block[logical_block_idx]; + } + + uint32_t pointers_per_block = SIMPLEFS_BLOCK_SIZE / sizeof(uint32_t); + std::vector indirect_block_buffer(pointers_per_block); + + uint32_t single_indirect_start_idx = SIMPLEFS_NUM_DIRECT_BLOCKS; + uint32_t single_indirect_end_idx = single_indirect_start_idx + pointers_per_block; + if (logical_block_idx < single_indirect_end_idx) { + uint32_t single_indirect_block_num = inode->i_block[SIMPLEFS_NUM_DIRECT_BLOCKS]; + if (single_indirect_block_num == 0) {errno = 0; return 0;} + + if (read_block(context.device_fd, single_indirect_block_num, indirect_block_buffer.data()) != 0) { + errno = EIO; + return 0; + } + uint32_t idx_in_indirect = logical_block_idx - single_indirect_start_idx; + return indirect_block_buffer[idx_in_indirect]; + } + + uint32_t double_indirect_start_idx = single_indirect_end_idx; + uint32_t double_indirect_max_entries = pointers_per_block * pointers_per_block; + uint32_t double_indirect_end_idx = double_indirect_start_idx + double_indirect_max_entries; + if (logical_block_idx < double_indirect_end_idx) { + uint32_t dbl_indirect_block_num = inode->i_block[SIMPLEFS_NUM_DIRECT_BLOCKS + 1]; + if (dbl_indirect_block_num == 0) {errno=0; return 0;} + + if (read_block(context.device_fd, dbl_indirect_block_num, indirect_block_buffer.data()) != 0) { + errno = EIO; return 0; + } + uint32_t logical_offset_in_dbl = logical_block_idx - double_indirect_start_idx; + uint32_t idx_in_dbl_indirect_block = logical_offset_in_dbl / pointers_per_block; + uint32_t single_indirect_block_to_read = indirect_block_buffer[idx_in_dbl_indirect_block]; + if (single_indirect_block_to_read == 0) {errno=0; return 0;} + + if (read_block(context.device_fd, single_indirect_block_to_read, indirect_block_buffer.data()) != 0) { + errno = EIO; return 0; + } + uint32_t idx_in_single_indirect_block = logical_offset_in_dbl % pointers_per_block; + return indirect_block_buffer[idx_in_single_indirect_block]; + } + + uint32_t triple_indirect_start_idx = double_indirect_end_idx; + uint64_t triple_indirect_max_logical_blocks = (uint64_t)pointers_per_block * pointers_per_block * pointers_per_block; + uint64_t triple_indirect_end_idx = triple_indirect_start_idx + triple_indirect_max_logical_blocks; + + if (logical_block_idx < triple_indirect_end_idx) { + uint32_t tpl_indirect_block_num = inode->i_block[SIMPLEFS_NUM_DIRECT_BLOCKS + 2]; + if (tpl_indirect_block_num == 0) { errno = 0; return 0; } + + if (read_block(context.device_fd, tpl_indirect_block_num, indirect_block_buffer.data()) != 0) { + errno = EIO; return 0; + } + + uint32_t logical_offset_in_tpl = logical_block_idx - triple_indirect_start_idx; + uint32_t idx_in_tpl_indirect_block = logical_offset_in_tpl / (pointers_per_block * pointers_per_block); + uint32_t dbl_indirect_block_to_read = indirect_block_buffer[idx_in_tpl_indirect_block]; + if (dbl_indirect_block_to_read == 0) { errno = 0; return 0; } + + if (read_block(context.device_fd, dbl_indirect_block_to_read, indirect_block_buffer.data()) != 0) { + errno = EIO; return 0; + } + + uint32_t logical_offset_in_dbl_from_tpl = logical_offset_in_tpl % (pointers_per_block * pointers_per_block); + uint32_t idx_in_dbl_from_tpl = logical_offset_in_dbl_from_tpl / pointers_per_block; + uint32_t sgl_indirect_block_to_read = indirect_block_buffer[idx_in_dbl_from_tpl]; + if (sgl_indirect_block_to_read == 0) { errno = 0; return 0; } + + if (read_block(context.device_fd, sgl_indirect_block_to_read, indirect_block_buffer.data()) != 0) { + errno = EIO; return 0; + } + uint32_t idx_in_sgl_final = logical_offset_in_dbl_from_tpl % pointers_per_block; + return indirect_block_buffer[idx_in_sgl_final]; + } + + errno = EFBIG; + return 0; +} + +// 释放逻辑块范围 +void release_logical_block_range(SimpleFS_Context& context, SimpleFS_Inode* inode, uint32_t start_lbn, uint32_t end_lbn) { + if (start_lbn >= end_lbn || !inode) { + return; + } + + for (uint32_t lbn_to_free = start_lbn; lbn_to_free < end_lbn; ++lbn_to_free) { + uint32_t physical_block = map_logical_to_physical_block(context, inode, lbn_to_free); + if (physical_block != 0) { + free_block(context, physical_block); + } + } + + // 简单重新计算块计数 + inode->i_blocks = (inode->i_size + 511) / 512; +} diff --git a/src/utils.cpp b/src/utils.cpp new file mode 100644 index 0000000..62cc3bc --- /dev/null +++ b/src/utils.cpp @@ -0,0 +1,100 @@ +#include "utils.h" +#include +#include + +void set_bitmap_bit(std::vector& bitmap_data, uint32_t bit_index) { + uint32_t byte_index = bit_index / 8; + uint8_t bit_offset = bit_index % 8; + if (bit_index < bitmap_data.size() * 8) { + bitmap_data[byte_index] |= (1 << bit_offset); + } +} + +void clear_bitmap_bit(std::vector& bitmap_data, uint32_t bit_index) { + uint32_t byte_index = bit_index / 8; + uint8_t bit_offset = bit_index % 8; + if (bit_index < bitmap_data.size() * 8) { + bitmap_data[byte_index] &= ~(1 << bit_offset); + } +} + +bool is_bitmap_bit_set(const std::vector& bitmap_data, uint32_t bit_index) { + uint32_t byte_index = bit_index / 8; + uint8_t bit_offset = bit_index % 8; + if (bit_index < bitmap_data.size() * 8) { + return (bitmap_data[byte_index] & (1 << bit_offset)) != 0; + } + return true; +} + +void parse_path(const std::string& path, std::string& dirname, std::string& basename) { + if (path.empty()) { + dirname = "."; + basename = ""; + return; + } + + // 规范化路径 + std::string p_normalized; + p_normalized.reserve(path.length()); + if (path[0] == '/') { + p_normalized += '/'; + } + for (size_t i = 0; i < path.length(); ++i) { + if (path[i] == '/') { + if (!p_normalized.empty() && p_normalized.back() != '/') { + p_normalized += '/'; + } + } else { + p_normalized += path[i]; + } + } + + // 移除尾部斜杠,除非是根路径 + if (p_normalized.length() > 1 && p_normalized.back() == '/') { + p_normalized.pop_back(); + } + + if (p_normalized.empty() && path[0] == '/') { + p_normalized = "/"; + } + + if (p_normalized == "/") { + dirname = "/"; + basename = "/"; + return; + } + + size_t last_slash = p_normalized.find_last_of('/'); + if (last_slash == std::string::npos) { + dirname = "."; + basename = p_normalized; + } else { + basename = p_normalized.substr(last_slash + 1); + if (last_slash == 0) { + dirname = "/"; + } else { + dirname = p_normalized.substr(0, last_slash); + } + } +} + +#include + +bool is_block_device(int fd) { + struct stat st; + if (fstat(fd, &st) == -1) { + return false; + } + return S_ISBLK(st.st_mode); +} + +bool is_backup_group(uint32_t group_index) { + if (group_index == 0 || group_index == 1) return true; + uint32_t n = group_index; + while (n % 3 == 0) n /= 3; + while (n % 5 == 0) n /= 5; + while (n % 7 == 0) n /= 7; + return n == 1; +} + diff --git a/stress_test.py b/stress_test.py new file mode 100644 index 0000000..e4d43a3 --- /dev/null +++ b/stress_test.py @@ -0,0 +1,598 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import os +import subprocess +import time +import hashlib +import pwd +import grp +import threading +import random +import string +import shutil +import sys +from collections import defaultdict + +# --- 配置部分 --- + +# 项目根目录 (假设此脚本位于项目根目录下) +PROJECT_DIR = os.path.dirname(os.path.abspath(__file__)) +# 构建目录 +BUILD_DIR = os.path.join(PROJECT_DIR, "build") +# SimpleFS 可执行文件路径 +SIMPLEFS_EXEC = os.path.join(BUILD_DIR, "simplefs") +# mkfs.simplefs 可执行文件路径 +MKFS_EXEC = os.path.join(BUILD_DIR, "mkfs.simplefs") + +# 测试环境配置 +TEST_DIR = os.path.join(PROJECT_DIR, "simplefs_test_environment") # 测试环境的主目录 +MOUNT_POINT = os.path.join(TEST_DIR, "mountpoint") # 文件系统挂载点 +DISK_IMAGE = os.path.join(TEST_DIR, "simplefs.img") # 磁盘镜像文件 +DISK_SIZE_MB = 256 # 磁盘镜像大小 (MB) + +# 大文件测试配置 +LARGE_FILE_SIZE_MB = 64 # 大文件大小 (MB) +LARGE_FILE_PATH = os.path.join(MOUNT_POINT, "large_file.dat") + +# 大量文件测试配置 +MANY_FILES_COUNT = 1024 # 创建的文件数量 +MANY_FILES_DIR = os.path.join(MOUNT_POINT, "many_files_test") + +# 权限测试配置 +TEST_USER_NAME = "testuser" +TEST_GROUP_NAME = "testgroup" + +# --- 日志和颜色 --- + +class Colors: + HEADER = '\033[95m' + OKBLUE = '\033[94m' + OKCYAN = '\033[96m' + OKGREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + +def log_info(message): + print(f"{Colors.OKBLUE}[INFO] {message}{Colors.ENDC}") + +def log_success(message): + print(f"{Colors.OKGREEN}[SUCCESS] {message}{Colors.ENDC}") + +def log_warning(message): + print(f"{Colors.WARNING}[WARNING] {message}{Colors.ENDC}") + +def log_error(message): + print(f"{Colors.FAIL}[ERROR] {message}{Colors.ENDC}") + sys.exit(1) # 发生错误时直接退出 + +def log_header(message): + print(f"\n{Colors.HEADER}{Colors.BOLD}===== {message} ====={Colors.ENDC}") + +# --- 辅助函数 --- + +def run_command(command, cwd=None, check=True, as_user=None): + """执行一个 shell 命令""" + log_info(f"执行命令: {' '.join(command)}") + if as_user: + command = ['sudo', '-u', as_user] + command + try: + process = subprocess.run( + command, + cwd=cwd, + check=check, + capture_output=True, + text=True, + timeout=600 # 10分钟超时 + ) + if process.stdout: + print(process.stdout) + if process.stderr: + print(process.stderr) + return process + except subprocess.CalledProcessError as e: + log_error(f"命令执行失败,返回码: {e.returncode}") + log_error(f"Stdout: {e.stdout}") + log_error(f"Stderr: {e.stderr}") + raise + except subprocess.TimeoutExpired as e: + log_error(f"命令执行超时: {' '.join(command)}") + raise + +def get_file_hash(filepath): + """计算文件的 SHA256 哈希值""" + sha256 = hashlib.sha256() + with open(filepath, 'rb') as f: + for chunk in iter(lambda: f.read(4096), b''): + sha256.update(chunk) + return sha256.hexdigest() + +def create_random_file(filepath, size_bytes): + """创建一个指定大小的随机内容文件""" + log_info(f"正在创建大小为 {size_bytes / 1024 / 1024:.2f} MB 的随机文件: {filepath}") + with open(filepath, 'wb') as f: + f.write(os.urandom(size_bytes)) + log_success(f"文件创建成功: {filepath}") + +# --- 环境准备和清理 --- + +def setup_environment(): + """准备测试环境""" + log_header("准备测试环境") + if os.geteuid() != 0: + log_error("此脚本需要 root 权限来执行挂载和用户切换操作。请使用 sudo 运行。") + + # 清理旧环境 + if os.path.exists(MOUNT_POINT): + run_command(['fusermount', '-u', MOUNT_POINT], check=False) + shutil.rmtree(TEST_DIR, ignore_errors=True) + + # 创建新目录 + os.makedirs(MOUNT_POINT, exist_ok=True) + log_success(f"测试目录 '{TEST_DIR}' 和挂载点 '{MOUNT_POINT}' 已创建。") + +def compile_project(): + """编译 SimpleFS 项目""" + log_header("编译项目") + if not os.path.exists(BUILD_DIR): + os.makedirs(BUILD_DIR) + + # 检查CMakeLists.txt是否存在 + if not os.path.exists(os.path.join(PROJECT_DIR, "CMakeLists.txt")): + log_error("项目根目录下未找到 CMakeLists.txt,请确认脚本位置是否正确。") + + run_command(['cmake', '..'], cwd=BUILD_DIR) + run_command(['make', '-j'], cwd=BUILD_DIR) # 使用多核编译 + + if not os.path.exists(SIMPLEFS_EXEC) or not os.path.exists(MKFS_EXEC): + log_error("编译失败,未找到可执行文件。") + log_success("项目编译成功。") + +def create_and_format_disk(): + """创建并格式化磁盘镜像""" + log_header("创建和格式化磁盘镜像") + # 创建一个稀疏文件作为磁盘镜像 + run_command(['truncate', '-s', f'{DISK_SIZE_MB}M', DISK_IMAGE]) + log_success(f"创建了 {DISK_SIZE_MB}MB 的磁盘镜像: {DISK_IMAGE}") + + # 格式化磁盘 + run_command([MKFS_EXEC, DISK_IMAGE]) + log_success("磁盘镜像格式化成功。") + +def mount_fs(): + """挂载文件系统""" + log_header("挂载文件系统") + # 使用 -f 在前台运行,便于调试,但这里我们需要后台运行 + command = [SIMPLEFS_EXEC, DISK_IMAGE, MOUNT_POINT, '-o', 'allow_other'] + # 在后台启动 simplefs 进程 + fs_process = subprocess.Popen(command) + time.sleep(2) # 等待 FUSE 挂载完成 + + # 检查挂载是否成功 + if not os.path.ismount(MOUNT_POINT): + fs_process.kill() + log_error("文件系统挂载失败!") + + log_success(f"文件系统已成功挂载到 {MOUNT_POINT}") + return fs_process + +def unmount_fs(fs_process): + """卸载文件系统并终止进程""" + log_header("卸载文件系统") + run_command(['fusermount', '-u', MOUNT_POINT]) + + # 尝试正常终止进程 + fs_process.terminate() + try: + fs_process.wait(timeout=5) + log_success("SimpleFS 进程已正常终止。") + except subprocess.TimeoutExpired: + log_warning("SimpleFS 进程无法正常终止,强制杀死。") + fs_process.kill() + + if os.path.ismount(MOUNT_POINT): + log_warning("卸载失败,挂载点仍然存在。") + else: + log_success("文件系统已成功卸载。") + + +def cleanup_environment(): + """清理测试环境""" + log_header("清理测试环境") + shutil.rmtree(TEST_DIR, ignore_errors=True) + cleanup_test_user() + log_success("测试环境已清理。") + +def setup_test_user(): + """创建用于权限测试的用户和组""" + log_header("设置测试用户和组") + try: + grp.getgrnam(TEST_GROUP_NAME) + log_info(f"组 '{TEST_GROUP_NAME}' 已存在。") + except KeyError: + run_command(['groupadd', TEST_GROUP_NAME]) + log_success(f"组 '{TEST_GROUP_NAME}' 已创建。") + + try: + pwd.getpwnam(TEST_USER_NAME) + log_info(f"用户 '{TEST_USER_NAME}' 已存在。") + except KeyError: + run_command(['useradd', '-m', '-g', TEST_GROUP_NAME, '-s', '/bin/bash', TEST_USER_NAME]) + log_success(f"用户 '{TEST_USER_NAME}' 已创建。") + +def cleanup_test_user(): + """删除测试用户和组""" + log_info("清理测试用户和组...") + run_command(['userdel', '-r', TEST_USER_NAME], check=False) + run_command(['groupdel', TEST_GROUP_NAME], check=False) + log_success("测试用户和组已清理。") + +# --- 测试用例 --- + +def test_large_file_io(): + """ + 测试大文件的读写和完整性。 + 1. 在本地创建一个大文件。 + 2. 计算本地文件的哈希值。 + 3. 使用 dd 命令将文件复制到挂载点。 + 4. 从挂载点将文件复制回来。 + 5. 比较复制回来的文件和原始文件的哈希值。 + 6. 直接读取挂载点上的文件并验证其哈希值。 + 7. 删除文件。 + """ + log_header("开始大文件读写和完整性测试") + local_source_file = os.path.join(TEST_DIR, "large_file_source.dat") + local_dest_file = os.path.join(TEST_DIR, "large_file_dest.dat") + file_size_bytes = LARGE_FILE_SIZE_MB * 1024 * 1024 + + # 1. 创建本地源文件 + create_random_file(local_source_file, file_size_bytes) + + # 2. 计算源文件哈希 + source_hash = get_file_hash(local_source_file) + log_info(f"源文件哈希: {source_hash}") + + # 3. 写入文件到 simplefs + log_info("使用 dd 命令将大文件写入 simplefs...") + run_command([ + 'dd', f'if={local_source_file}', f'of={LARGE_FILE_PATH}', 'bs=4M', 'oflag=direct' + ]) + log_success("大文件写入成功。") + time.sleep(1) # 等待数据落盘 + + # 4. 检查文件大小 + stat_info = os.stat(LARGE_FILE_PATH) + if stat_info.st_size != file_size_bytes: + log_error(f"文件大小不匹配!期望: {file_size_bytes}, 实际: {stat_info.st_size}") + log_success("文件大小验证成功。") + + # 5. 直接验证挂载点上文件的哈希 + log_info("直接验证挂载点上文件的哈希...") + fs_file_hash = get_file_hash(LARGE_FILE_PATH) + log_info(f"SimpleFS 中的文件哈希: {fs_file_hash}") + if fs_file_hash != source_hash: + log_error("文件内容完整性检查失败!哈希值不匹配。") + log_success("文件内容完整性(直接读取)验证成功!") + + # 6. 从 simplefs 读回文件 + log_info("使用 dd 命令从 simplefs 读回大文件...") + run_command([ + 'dd', f'if={LARGE_FILE_PATH}', f'of={local_dest_file}', 'bs=4M', 'iflag=direct' + ]) + + # 7. 验证读回文件的哈希 + dest_hash = get_file_hash(local_dest_file) + log_info(f"读回文件哈希: {dest_hash}") + if dest_hash != source_hash: + log_error("文件内容完整性检查失败!读回的文件与源文件不匹配。") + log_success("文件内容完整性(读回)验证成功!") + + # 8. 删除文件 + os.remove(LARGE_FILE_PATH) + if os.path.exists(LARGE_FILE_PATH): + log_error("删除大文件失败!") + log_success("大文件删除成功。") + + # 清理本地临时文件 + os.remove(local_source_file) + os.remove(local_dest_file) + + +def test_many_files_io(): + """ + 测试大量小文件的创建、读写和删除。 + 1. 创建一个目录。 + 2. 在目录中创建大量小文件,并写入少量随机数据。 + 3. 记录每个文件的路径和其内容的哈希。 + 4. 随机抽查一些文件,验证其内容是否正确。 + 5. 验证目录列表是否能正确显示所有文件。 + 6. 依次删除所有文件。 + 7. 删除目录。 + """ + log_header("开始大量小文件读写测试") + os.makedirs(MANY_FILES_DIR, exist_ok=True) + + file_hashes = {} + + # 1. 创建大量文件 + log_info(f"正在创建 {MANY_FILES_COUNT} 个小文件...") + for i in range(MANY_FILES_COUNT): + filename = f"small_file_{i}.txt" + filepath = os.path.join(MANY_FILES_DIR, filename) + content = ''.join(random.choices(string.ascii_letters + string.digits, k=128)).encode('utf-8') + + with open(filepath, 'wb') as f: + f.write(content) + + file_hashes[filepath] = hashlib.sha256(content).hexdigest() + log_success(f"{MANY_FILES_COUNT} 个小文件创建完成。") + + # 2. 验证文件数量 + listed_files = os.listdir(MANY_FILES_DIR) + if len(listed_files) != MANY_FILES_COUNT: + log_error(f"文件数量不匹配!期望: {MANY_FILES_COUNT}, 实际: {len(listed_files)}") + log_success("文件数量验证成功。") + + # 3. 随机抽样验证 + log_info("随机抽样 50 个文件进行内容验证...") + sample_paths = random.sample(list(file_hashes.keys()), 50) + for path in sample_paths: + with open(path, 'rb') as f: + content = f.read() + read_hash = hashlib.sha256(content).hexdigest() + if read_hash != file_hashes[path]: + log_error(f"文件 {path} 内容验证失败!") + log_success("随机抽样文件内容验证成功。") + + # 4. 删除所有文件 + log_info(f"正在删除 {MANY_FILES_COUNT} 个小文件...") + for filepath in file_hashes.keys(): + os.remove(filepath) + log_success("所有小文件删除成功。") + + # 5. 验证目录是否为空 + if len(os.listdir(MANY_FILES_DIR)) != 0: + log_error("删除文件后,目录不为空!") + log_success("目录已清空验证成功。") + + # 6. 删除目录 + os.rmdir(MANY_FILES_DIR) + if os.path.exists(MANY_FILES_DIR): + log_error("删除目录失败!") + log_success("测试目录删除成功。") + + +def test_permission_system(): + """ + 测试文件系统的权限控制。 + 1. 创建一个测试文件,所有者为 root。 + 2. 切换到 testuser,尝试读取该文件(应该失败)。 + 3. 切换到 testuser,尝试写入该文件(应该失败)。 + 4. 使用 root 修改文件权限为 0644,允许其他人读取。 + 5. 切换到 testuser,尝试读取该文件(应该成功)。 + 6. 切换到 testuser,尝试写入该文件(应该失败)。 + 7. 使用 root 修改文件权限为 0666,允许其他人写入。 + 8. 切换到 testuser,尝试写入该文件(应该成功)。 + 9. 使用 chown 修改文件所有者为 testuser。 + 10. 切换到 testuser,修改文件权限为 0600。 + 11. 切换回 root,尝试读取文件(应该成功,因为 root 有超级权限)。 + """ + log_header("开始权限系统测试") + setup_test_user() + test_file = os.path.join(MOUNT_POINT, "permission_test.txt") + test_content = "permission test content" + + # 1. root 创建文件 + with open(test_file, 'w') as f: + f.write(test_content) + run_command(['chown', f'root:root', test_file]) + run_command(['chmod', '0600', test_file]) + log_success("root 创建了文件 permission_test.txt (权限 0600)") + + # 2. testuser 尝试读取 (失败) + log_info("测试: testuser 尝试读取 root 的 0600 文件 (应失败)") + try: + run_command(['cat', test_file], as_user=TEST_USER_NAME, check=True) + log_error("权限测试失败:testuser 不应能读取此文件!") + except subprocess.CalledProcessError: + log_success("测试通过:testuser 无法读取文件。") + + # 3. testuser 尝试写入 (失败) + log_info("测试: testuser 尝试写入 root 的 0600 文件 (应失败)") + try: + run_command(['sh', '-c', f'echo "more" >> {test_file}'], as_user=TEST_USER_NAME, check=True) + log_error("权限测试失败:testuser 不应能写入此文件!") + except subprocess.CalledProcessError: + log_success("测试通过:testuser 无法写入文件。") + + # 4. root 修改权限为 0644 + log_info("root 修改权限为 0644 (允许 others 读取)") + run_command(['chmod', '0644', test_file]) + + # 5. testuser 尝试读取 (成功) + log_info("测试: testuser 尝试读取 root 的 0644 文件 (应成功)") + run_command(['cat', test_file], as_user=TEST_USER_NAME) + log_success("测试通过:testuser 可以读取文件。") + + # 6. testuser 尝试写入 (失败) + log_info("测试: testuser 尝试写入 root 的 0644 文件 (应失败)") + try: + run_command(['sh', '-c', f'echo "more" >> {test_file}'], as_user=TEST_USER_NAME, check=True) + log_error("权限测试失败:testuser 不应能写入此文件!") + except subprocess.CalledProcessError: + log_success("测试通过:testuser 无法写入文件。") + + # 7. root 修改所有者为 testuser + log_info("root 使用 chown 将文件所有者改为 testuser") + run_command(['chown', f'{TEST_USER_NAME}:{TEST_GROUP_NAME}', test_file]) + + # 8. testuser 尝试写入 (成功) + log_info("测试: testuser 作为所有者尝试写入文件 (应成功)") + run_command(['sh', '-c', f'echo " more content" >> {test_file}'], as_user=TEST_USER_NAME) + log_success("测试通过:testuser 作为所有者可以写入文件。") + + # 9. testuser 修改权限为 0600 + log_info("testuser 修改权限为 0600") + run_command(['chmod', '0600', test_file], as_user=TEST_USER_NAME) + + # 10. root 尝试读取 (成功) + log_info("测试: root 尝试读取 testuser 的 0600 文件 (应成功)") + run_command(['cat', test_file]) # root 默认有权限 + log_success("测试通过:root 可以读取任何文件。") + + # 清理 + os.remove(test_file) + log_success("权限测试文件已清理。") + +def test_links(): + """ + 测试硬链接和符号链接。 + 1. 创建一个源文件。 + 2. 创建一个硬链接到该文件。 + 3. 验证硬链接和源文件有相同的 inode。 + 4. 验证修改源文件后,硬链接内容也改变。 + 5. 删除源文件,验证硬链接依然可以访问。 + 6. 删除硬链接。 + 7. 创建一个新的源文件。 + 8. 创建一个符号链接到该文件。 + 9. 验证读取符号链接会返回源文件的内容。 + 10. 删除源文件,验证访问符号链接会失败(悬空链接)。 + 11. 重新创建源文件,验证符号链接恢复正常。 + 12. 删除符号链接和源文件。 + """ + log_header("开始链接功能测试") + + # --- 硬链接测试 --- + log_info("--- 硬链接测试 ---") + source_file = os.path.join(MOUNT_POINT, "hardlink_source.txt") + hard_link = os.path.join(MOUNT_POINT, "hardlink_link.txt") + + # 1. 创建源文件 + with open(source_file, "w") as f: + f.write("initial content") + log_success(f"创建源文件: {source_file}") + + # 2. 创建硬链接 + os.link(source_file, hard_link) + log_success(f"创建硬链接: {hard_link}") + + # 3. 验证 inode + source_stat = os.stat(source_file) + link_stat = os.stat(hard_link) + if source_stat.st_ino != link_stat.st_ino: + log_error(f"硬链接 Inode 不匹配! 源: {source_stat.st_ino}, 链接: {link_stat.st_ino}") + log_success("Inode 验证成功。") + if source_stat.st_nlink != 2: + log_error(f"链接数不为 2,实际为: {source_stat.st_nlink}") + log_success("链接数验证成功 (nlink=2)。") + + # 4. 验证内容同步 + with open(source_file, "a") as f: + f.write(" appended") + with open(hard_link, "r") as f: + content = f.read() + if content != "initial content appended": + log_error("硬链接内容未同步!") + log_success("内容同步验证成功。") + + # 5. 删除源文件后访问硬链接 + os.remove(source_file) + log_info("源文件已删除。") + with open(hard_link, "r") as f: + content = f.read() + if content != "initial content appended": + log_error("删除源文件后,无法通过硬链接访问正确内容!") + link_stat_after_rm = os.stat(hard_link) + if link_stat_after_rm.st_nlink != 1: + log_error(f"删除源文件后,链接数不为 1,实际为: {link_stat_after_rm.st_nlink}") + log_success("删除源文件后,硬链接依然可用,且 nlink=1。") + + # 6. 删除硬链接 + os.remove(hard_link) + log_success("硬链接已删除。") + + # --- 符号链接测试 --- + log_info("--- 符号链接测试 ---") + source_file_sym = os.path.join(MOUNT_POINT, "symlink_source.txt") + sym_link = os.path.join(MOUNT_POINT, "symlink_link.txt") + + # 7. 创建源文件 + with open(source_file_sym, "w") as f: + f.write("symlink test") + log_success(f"创建源文件: {source_file_sym}") + + # 8. 创建符号链接 + os.symlink(source_file_sym, sym_link) + log_success(f"创建符号链接: {sym_link}") + if not os.path.islink(sym_link): + log_error("创建的不是符号链接!") + log_success("符号链接类型验证成功。") + + # 9. 验证内容 + with open(sym_link, "r") as f: + content = f.read() + if content != "symlink test": + log_error("通过符号链接读取的内容不正确!") + log_success("通过符号链接读取内容验证成功。") + + # 10. 删除源文件后访问 (悬空链接) + os.remove(source_file_sym) + log_info("源文件已删除。") + try: + with open(sym_link, "r") as f: + f.read() + log_error("访问悬空链接时没有报错!") + except FileNotFoundError: + log_success("访问悬空链接时正确地抛出 FileNotFoundError。") + + # 11. 重新创建源文件 + with open(source_file_sym, "w") as f: + f.write("symlink reborn") + log_info("源文件已重新创建。") + with open(sym_link, "r") as f: + content = f.read() + if content != "symlink reborn": + log_error("重新创建源文件后,符号链接内容不正确!") + log_success("重新创建源文件后,符号链接恢复正常。") + + # 12. 清理 + os.remove(sym_link) + os.remove(source_file_sym) + log_success("符号链接测试清理完毕。") + +# --- 主函数 --- + +def main(): + """主执行函数""" + fs_process = None + try: + setup_environment() + compile_project() + create_and_format_disk() + fs_process = mount_fs() + + # --- 按顺序执行所有测试 --- + test_large_file_io() + test_many_files_io() + test_permission_system() + test_links() + + log_header("所有测试已成功完成!") + + except Exception as e: + log_error(f"测试过程中发生未捕获的异常: {e}") + import traceback + traceback.print_exc() + + finally: + if fs_process: + unmount_fs(fs_process) + cleanup_environment() + log_info("脚本执行结束。") + +if __name__ == '__main__': + main() + diff --git a/tools/fsck.cpp b/tools/fsck.cpp new file mode 100644 index 0000000..a76c8d4 --- /dev/null +++ b/tools/fsck.cpp @@ -0,0 +1,77 @@ +#include "simplefs.h" +#include "disk_io.h" +#include "utils.h" +#include +#include +#include +#include +#include +#include + +int main(int argc, char* argv[]) { + if (argc < 2) { + std::cerr << "用法: " << argv[0] << " <设备文件>" << std::endl; + return 1; + } + const char* path = argv[1]; + int fd = open(path, O_RDONLY); + if (fd < 0) { + perror("打开设备文件失败"); + return 1; + } + + std::vector buf(SIMPLEFS_BLOCK_SIZE); + if (read_block(fd, 1, buf.data()) != 0) { + std::cerr << "读取超级块失败" << std::endl; + close(fd); + return 1; + } + SimpleFS_SuperBlock sb; + std::memcpy(&sb, buf.data(), sizeof(sb)); + if (sb.s_magic != SIMPLEFS_MAGIC) { + std::cerr << "魔数不匹配,不是SimpleFS镜像" << std::endl; + close(fd); + return 1; + } + + uint32_t num_groups = static_cast(std::ceil((double)sb.s_blocks_count / sb.s_blocks_per_group)); + uint32_t gdt_size = num_groups * sizeof(SimpleFS_GroupDesc); + uint32_t gdt_blocks = static_cast(std::ceil((double)gdt_size / SIMPLEFS_BLOCK_SIZE)); + std::vector gdt_raw(gdt_blocks * SIMPLEFS_BLOCK_SIZE); + for (uint32_t i=0;i gdt(num_groups); + std::memcpy(gdt.data(), gdt_raw.data(), gdt_size); + + uint64_t calc_free_blocks=0, calc_free_inodes=0; + for(uint32_t grp=0; grp bb(SIMPLEFS_BLOCK_SIZE), ib(SIMPLEFS_BLOCK_SIZE); + read_block(fd, gd.bg_block_bitmap, bb.data()); + read_block(fd, gd.bg_inode_bitmap, ib.data()); + uint32_t freeb=0, freei=0; + for(uint32_t b=0;b +#include +#include +#include +#include // 字符串操作 +#include // stat, fstat +#include // open +#include // close, ftruncate +#include // ceil +#include // std::fill +#include // std::fill + +#include // ioctl +#include // BLKGETSIZE64 + +// 默认参数(可通过选项覆盖) +const uint32_t DEFAULT_BLOCKS_PER_GROUP = SIMPLEFS_BLOCK_SIZE * 8; // 位图中每位对应一个块 +const uint32_t DEFAULT_INODES_PER_GROUP = 1024; // 选定的默认值 + +// 静态位图辅助函数已移至metadata.cpp + +void print_usage(const char* prog_name) { + std::cerr << "用法: " << prog_name << " <设备文件> [块数量]" << std::endl; + std::cerr << " <设备文件>: 磁盘镜像文件或块设备路径" << std::endl; + std::cerr << " [块数量]: 可选,新镜像文件的总块数" << std::endl; +} + +// 获取文件大小的函数 +off_t get_file_size(int fd) { + struct stat st; + if (fstat(fd, &st) == -1) { + perror("获取文件大小失败"); + return -1; + } + return st.st_size; +} + + +int main(int argc, char* argv[]) { + if (argc < 2 || argc > 3) { + print_usage(argv[0]); + return 1; + } + + std::string device_path = argv[1]; + uint64_t total_blocks_on_device = 0; + uint64_t device_size_bytes = 0; + bool create_new_image = false; + + DeviceFd fd = open(device_path.c_str(), O_RDWR); + + if (fd == -1) { + if (errno == ENOENT && argc == 3) { // 文件不存在,且提供了大小 + std::cout << "正在创建新镜像文件: " << device_path << std::endl; + fd = open(device_path.c_str(), O_RDWR | O_CREAT | O_EXCL, 0666); + if (fd == -1) { + perror("创建镜像文件失败"); + return 1; + } + create_new_image = true; + try { + total_blocks_on_device = std::stoull(argv[2]); + if (total_blocks_on_device == 0) { + std::cerr << "块数量必须为正数" << std::endl; + close(fd); + unlink(device_path.c_str()); // 清理已创建的文件 + return 1; + } + device_size_bytes = total_blocks_on_device * SIMPLEFS_BLOCK_SIZE; + if (ftruncate(fd, device_size_bytes) == -1) { + perror("设置镜像大小失败"); + close(fd); + unlink(device_path.c_str()); // 清理 + return 1; + } + std::cout << "已创建新镜像文件 " << device_path << " (大小: " + << total_blocks_on_device << " 块, " << device_size_bytes << " 字节)" << std::endl; + } catch (const std::exception& e) { + std::cerr << "块数量参数无效: " << e.what() << std::endl; + close(fd); + unlink(device_path.c_str()); // 清理 + return 1; + } + } else if (errno == ENOENT) { + std::cerr << "错误: 镜像文件 '" << device_path << "' 未找到,请提供块数量来创建" << std::endl; + perror("打开设备/镜像失败"); + return 1; + } + else { + perror("打开设备/镜像失败"); + return 1; + } + } else { + bool is_blk_dev = is_block_device(fd); + + if (is_blk_dev) { + std::cout << "检测到块设备" << std::endl; + uint64_t size_from_ioctl = 0; + if (ioctl(fd, BLKGETSIZE64, &size_from_ioctl) == 0) { + std::cout << "通过ioctl获取块设备大小: " << size_from_ioctl << " 字节" << std::endl; + if (size_from_ioctl % SIMPLEFS_BLOCK_SIZE != 0) { + std::cerr << "警告: 块设备大小不是文件系统块大小的整数倍" << std::endl; + } + device_size_bytes = size_from_ioctl; + total_blocks_on_device = device_size_bytes / SIMPLEFS_BLOCK_SIZE; + if (argc == 3) { + std::cout << "注意: 忽略[num_blocks]参数,已自动检测设备大小" << std::endl; + } + } else { + perror("ioctl获取设备大小失败"); + std::cerr << "无法自动检测块设备大小" << std::endl; + if (argc != 3) { + std::cerr << "错误: 请手动提供[num_blocks]参数" << std::endl; + close(fd); + return 1; + } + try { + total_blocks_on_device = std::stoull(argv[2]); + if (total_blocks_on_device == 0) { + std::cerr << "块数量必须为正数" << std::endl; + close(fd); + return 1; + } + device_size_bytes = total_blocks_on_device * SIMPLEFS_BLOCK_SIZE; + } catch (const std::exception& e) { + std::cerr << "块数量参数无效: " << e.what() << std::endl; + close(fd); + return 1; + } + } + std::cout << "格式化块设备 " << device_path << ",块数: " << total_blocks_on_device + << " (" << device_size_bytes << " 字节)" << std::endl; + + } else { + // 这是常规文件,获取其大小 + off_t existing_size = get_file_size(fd); + if (existing_size == -1) { + close(fd); + return 1; + } + if (existing_size == 0) { + if (argc == 3) { // 这是空文件但用户要用指定大小格式化 + std::cout << "现有文件为空,按新镜像创建处理" << std::endl; + create_new_image = true; + try { + total_blocks_on_device = std::stoull(argv[2]); + if (total_blocks_on_device == 0) { + std::cerr << "块数量必须为正数" << std::endl; + close(fd); + return 1; + } + device_size_bytes = total_blocks_on_device * SIMPLEFS_BLOCK_SIZE; + if (ftruncate(fd, device_size_bytes) == -1) { + perror("设置镜像大小失败"); + close(fd); + return 1; + } + std::cout << "设置镜像 " << device_path << " 大小为 " << total_blocks_on_device + << " 块 (" << device_size_bytes << " 字节)" << std::endl; + } catch (const std::exception& e) { + std::cerr << "块数量参数无效: " << e.what() << std::endl; + close(fd); + return 1; + } + } else { + std::cerr << "错误: 镜像文件为空" << std::endl; + std::cerr << "如需格式化,请提供num_blocks参数" << std::endl; + close(fd); + return 1; + } + } else { + if (existing_size % SIMPLEFS_BLOCK_SIZE != 0) { + std::cerr << "警告: 设备/镜像大小 (" << existing_size + << " 字节) 不是块大小 (" << SIMPLEFS_BLOCK_SIZE << " 字节) 的整数倍" << std::endl; + } + device_size_bytes = existing_size; + total_blocks_on_device = device_size_bytes / SIMPLEFS_BLOCK_SIZE; + std::cout << "Opened existing image " << device_path << ". Total blocks: " << total_blocks_on_device + << " (" << device_size_bytes << " bytes)." << std::endl; + if (argc == 3 && !create_new_image) { + std::cout << "Note: [num_blocks] argument is ignored when using an existing, non-empty image file." << std::endl; + } + } + } + } + + if (total_blocks_on_device < 64) { + std::cerr << "错误: 设备/镜像太小,至少需要64个块" << std::endl; + close(fd); + if (create_new_image) unlink(device_path.c_str()); + return 1; + } + + std::cout << "正在格式化 " << device_path << " 为 SimpleFS..." << std::endl; + + uint32_t inodes_per_block = SIMPLEFS_BLOCK_SIZE / SIMPLEFS_INODE_SIZE; + uint32_t sb_blocks_per_group = DEFAULT_BLOCKS_PER_GROUP; + uint32_t sb_inodes_per_group = DEFAULT_INODES_PER_GROUP; + if (sb_inodes_per_group > SIMPLEFS_BLOCK_SIZE * 8) { + sb_inodes_per_group = SIMPLEFS_BLOCK_SIZE * 8; + std::cout << "警告: 请求的每组inode数超过inode位图最大容量,调整为 " + << sb_inodes_per_group << std::endl; + } + + uint32_t num_block_groups = static_cast(std::ceil(static_cast(total_blocks_on_device) / sb_blocks_per_group)); + if (num_block_groups == 0) num_block_groups = 1; + + uint64_t total_inodes_fs = static_cast(num_block_groups) * sb_inodes_per_group; + if (total_inodes_fs > UINT32_MAX) { + total_inodes_fs = UINT32_MAX; + } + + std::cout << "文件系统布局:" << std::endl; + std::cout << " 总块数: " << total_blocks_on_device << std::endl; + std::cout << " 每组inode数: " << sb_inodes_per_group << std::endl; + std::cout << " 块组数: " << num_block_groups << std::endl; + std::cout << " 总inode数: " << total_inodes_fs << std::endl; + + SimpleFS_SuperBlock sb; + std::memset(&sb, 0, sizeof(SimpleFS_SuperBlock)); + sb.s_magic = SIMPLEFS_MAGIC; + sb.s_blocks_count = total_blocks_on_device; + sb.s_inodes_count = static_cast(total_inodes_fs); + sb.s_log_block_size = static_cast(std::log2(SIMPLEFS_BLOCK_SIZE)) - 10; + sb.s_blocks_per_group = sb_blocks_per_group; + sb.s_inodes_per_group = sb_inodes_per_group; + sb.s_inode_size = SIMPLEFS_INODE_SIZE; + sb.s_root_inode = SIMPLEFS_ROOT_INODE_NUM; + sb.s_first_ino = 11; + sb.s_state = 1; + sb.s_errors = 1; + sb.s_max_mnt_count = 20; + sb.s_mnt_count = 0; + sb.s_wtime = time(nullptr); + sb.s_block_group_nr = 0; + + uint32_t gdt_size_bytes = num_block_groups * sizeof(SimpleFS_GroupDesc); + uint32_t gdt_blocks = static_cast(std::ceil(static_cast(gdt_size_bytes) / SIMPLEFS_BLOCK_SIZE)); + std::cout << " GDT size: " << gdt_size_bytes << " bytes, requiring " << gdt_blocks << " blocks." << std::endl; + + uint32_t superblock_location_block = 1; + uint32_t gdt_start_block = superblock_location_block + 1; + + std::vector gdt(num_block_groups); + std::memset(gdt.data(), 0, gdt_size_bytes); + + uint32_t running_total_free_blocks = total_blocks_on_device; + uint32_t running_total_free_inodes = sb.s_inodes_count; + + if (superblock_location_block < total_blocks_on_device) running_total_free_blocks--; else { std::cerr << "No space for SB!" << std::endl; return 1; } + for(uint32_t i = 0; i < gdt_blocks; ++i) { + if ((gdt_start_block + i) < total_blocks_on_device) running_total_free_blocks--; else { std::cerr << "No space for GDT!" << std::endl; return 1; } + } + + uint32_t current_group_meta_start_block = gdt_start_block + gdt_blocks; + + for (uint32_t i = 0; i < num_block_groups; ++i) { + SimpleFS_GroupDesc& current_gd = gdt[i]; + uint32_t group_abs_start_block_for_data = i * sb.s_blocks_per_group; + uint32_t inode_table_size_blocks = static_cast(std::ceil(static_cast(sb.s_inodes_per_group) * SIMPLEFS_INODE_SIZE / SIMPLEFS_BLOCK_SIZE)); + + bool backup_here = is_backup_group(i); + + if (i == 0) { + current_gd.bg_block_bitmap = current_group_meta_start_block; + current_gd.bg_inode_bitmap = current_gd.bg_block_bitmap + 1; + current_gd.bg_inode_table = current_gd.bg_inode_bitmap + 1; + sb.s_first_data_block = current_gd.bg_inode_table + inode_table_size_blocks; + } else if (backup_here) { + current_gd.bg_block_bitmap = group_abs_start_block_for_data + 1 + gdt_blocks; + current_gd.bg_inode_bitmap = current_gd.bg_block_bitmap + 1; + current_gd.bg_inode_table = current_gd.bg_inode_bitmap + 1; + } else { + current_gd.bg_block_bitmap = group_abs_start_block_for_data; + current_gd.bg_inode_bitmap = current_gd.bg_block_bitmap + 1; + current_gd.bg_inode_table = current_gd.bg_inode_bitmap + 1; + } + + uint32_t last_meta_block_for_group = current_gd.bg_inode_table + inode_table_size_blocks -1; + if (last_meta_block_for_group >= total_blocks_on_device || current_gd.bg_block_bitmap >= total_blocks_on_device) { + std::cerr << "错误: 组 " << i << " 的元数据超出设备限制" << std::endl; close(fd); if(create_new_image) unlink(device_path.c_str()); return 1; + } + + running_total_free_blocks--; // 块位图 + running_total_free_blocks--; // inode位图 + running_total_free_blocks -= inode_table_size_blocks; // inode表 + // 注意:主组(组0)的超级块和GDT已在前面减去,这里不重复减去 + if (backup_here && i != 0) { // 只有备份组且不是组0才减去 + running_total_free_blocks--; // 备份超级块 + running_total_free_blocks -= gdt_blocks; // 备份GDT + } + + uint32_t blocks_in_this_group_range = (i == num_block_groups - 1) ? + (total_blocks_on_device - group_abs_start_block_for_data) : + sb.s_blocks_per_group; + + current_gd.bg_free_blocks_count = blocks_in_this_group_range; + current_gd.bg_free_blocks_count -= 1; // 块位图 + current_gd.bg_free_blocks_count -= 1; // inode位图 + current_gd.bg_free_blocks_count -= inode_table_size_blocks; // inode表 + if (i == 0) { + current_gd.bg_free_blocks_count--; // 超级块 + current_gd.bg_free_blocks_count -= gdt_blocks; // GDT + } else if (backup_here) { + current_gd.bg_free_blocks_count--; // 备份超级块 + current_gd.bg_free_blocks_count -= gdt_blocks; // 备份GDT + } + + // 主要SB/GDT的额外空闲块调整已在前面完成 + current_gd.bg_free_inodes_count = sb.s_inodes_per_group; + current_gd.bg_used_dirs_count = 0; + } + + sb.s_free_blocks_count = running_total_free_blocks; + sb.s_free_inodes_count = running_total_free_inodes; + + if (gdt_start_block + gdt_blocks > gdt[0].bg_block_bitmap) { + std::cerr << "严重错误: GDT与组0块位图重叠,设备太小或计算错误" << std::endl; + close(fd); if(create_new_image) unlink(device_path.c_str()); return 1; + } + + std::cout << "超级块(根目录前的最终估计值):" << std::endl; + std::cout << " 空闲块数: " << sb.s_free_blocks_count << std::endl; + std::cout << " 空闲inode数: " << sb.s_free_inodes_count << std::endl; + std::cout << " 首个数据块(全局): " << sb.s_first_data_block << std::endl; + + std::vector fs_block_buffer(SIMPLEFS_BLOCK_SIZE, 0); + std::memcpy(fs_block_buffer.data(), &sb, sizeof(sb)); + if (write_block(fd, superblock_location_block, fs_block_buffer.data()) != 0) { + std::cerr << "超级块写入失败" << std::endl; close(fd); if (create_new_image) unlink(device_path.c_str()); return 1; + } + std::cout << "超级块已写入块 " << superblock_location_block << std::endl; + + uint8_t* gdt_write_ptr = reinterpret_cast(gdt.data()); + for (uint32_t i = 0; i < gdt_blocks; ++i) { + std::fill(fs_block_buffer.begin(), fs_block_buffer.end(), 0); + uint32_t bytes_to_copy_this_block = (gdt_size_bytes - (i * SIMPLEFS_BLOCK_SIZE) < SIMPLEFS_BLOCK_SIZE) ? + (gdt_size_bytes % SIMPLEFS_BLOCK_SIZE == 0 && gdt_size_bytes > 0 ? SIMPLEFS_BLOCK_SIZE : gdt_size_bytes % SIMPLEFS_BLOCK_SIZE) + : SIMPLEFS_BLOCK_SIZE; + if (gdt_size_bytes == 0 && i==0) bytes_to_copy_this_block = 0; + + std::memcpy(fs_block_buffer.data(), gdt_write_ptr + (i * SIMPLEFS_BLOCK_SIZE), bytes_to_copy_this_block); + if (write_block(fd, gdt_start_block + i, fs_block_buffer.data()) != 0) { + std::cerr << "GDT块 " << (gdt_start_block + i) << " 写入失败" << std::endl; close(fd); if (create_new_image) unlink(device_path.c_str()); return 1; + } + } + std::cout << "GDT已写入块 " << gdt_start_block << " 到 " << (gdt_start_block + gdt_blocks - 1) << std::endl; + + std::vector group_block_bitmap_buffer(SIMPLEFS_BLOCK_SIZE, 0); + std::vector group_inode_bitmap_buffer(SIMPLEFS_BLOCK_SIZE, 0); + + for (uint32_t i = 0; i < num_block_groups; ++i) { + SimpleFS_GroupDesc& current_gd_ref = gdt[i]; + uint32_t group_abs_data_start_block = i * sb.s_blocks_per_group; // 这是该组位图中位0的块号 + uint32_t inode_table_size_blocks = static_cast(std::ceil(static_cast(sb.s_inodes_per_group) * SIMPLEFS_INODE_SIZE / SIMPLEFS_BLOCK_SIZE)); + + std::cout << "Processing Group " << i << ":" << std::endl; + std::cout << " BB@" << current_gd_ref.bg_block_bitmap << ", IB@" << current_gd_ref.bg_inode_bitmap << ", IT@" << current_gd_ref.bg_inode_table << " (" << inode_table_size_blocks << " blocks)" << std::endl; + + std::fill(group_block_bitmap_buffer.begin(), group_block_bitmap_buffer.end(), 0); + std::fill(group_inode_bitmap_buffer.begin(), group_inode_bitmap_buffer.end(), 0); + + // 在其块位图中将组自己的元数据块标记为已使用 + // 组位图中的位索引相对于该组管理的块起始位置 + set_bitmap_bit(group_block_bitmap_buffer, current_gd_ref.bg_block_bitmap - group_abs_data_start_block); + set_bitmap_bit(group_block_bitmap_buffer, current_gd_ref.bg_inode_bitmap - group_abs_data_start_block); + for (uint32_t j = 0; j < inode_table_size_blocks; ++j) { + set_bitmap_bit(group_block_bitmap_buffer, (current_gd_ref.bg_inode_table + j) - group_abs_data_start_block); + } + + bool backup_here = is_backup_group(i); + if (backup_here) { + uint32_t sb_blk = (i == 0) ? superblock_location_block : group_abs_data_start_block; + set_bitmap_bit(group_block_bitmap_buffer, sb_blk - group_abs_data_start_block); + for (uint32_t gdt_idx = 0; gdt_idx < gdt_blocks; ++gdt_idx) { + uint32_t abs_gdt_block = (i == 0) ? (gdt_start_block + gdt_idx) + : (group_abs_data_start_block + 1 + gdt_idx); + set_bitmap_bit(group_block_bitmap_buffer, abs_gdt_block - group_abs_data_start_block); + } + + + } + if (i == 0) { + if (!is_bitmap_bit_set(group_block_bitmap_buffer, 0)) { + set_bitmap_bit(group_block_bitmap_buffer, 0); + bool block0_was_sb = (superblock_location_block == 0); + bool block0_was_gdt = false; + for(uint32_t gdt_idx=0; gdt_idx < gdt_blocks; ++gdt_idx) if((gdt_start_block + gdt_idx) == 0) block0_was_gdt = true; + bool block0_was_group0_bb = (current_gd_ref.bg_block_bitmap == 0); + bool block0_was_group0_ib = (current_gd_ref.bg_inode_bitmap == 0); + bool block0_was_group0_it = (current_gd_ref.bg_inode_table == 0); + if (!block0_was_sb && !block0_was_gdt && !block0_was_group0_bb && !block0_was_group0_ib && !block0_was_group0_it) { + if (current_gd_ref.bg_free_blocks_count > 0) current_gd_ref.bg_free_blocks_count--; + if (sb.s_free_blocks_count > 0) sb.s_free_blocks_count--; + } + } + set_bitmap_bit(group_inode_bitmap_buffer, 0); + set_bitmap_bit(group_inode_bitmap_buffer, 1); + if (current_gd_ref.bg_free_inodes_count >= 2) current_gd_ref.bg_free_inodes_count -= 2; else current_gd_ref.bg_free_inodes_count = 0; + if (sb.s_free_inodes_count >= 2) sb.s_free_inodes_count -= 2; else sb.s_free_inodes_count = 0; + } + + if (write_block(fd, current_gd_ref.bg_block_bitmap, group_block_bitmap_buffer.data()) != 0) { /* error */ return 1; } + std::cout << " Written Block Bitmap. Group free blocks: " << current_gd_ref.bg_free_blocks_count << std::endl; + + if (write_block(fd, current_gd_ref.bg_inode_bitmap, group_inode_bitmap_buffer.data()) != 0) { /* error */ return 1; } + std::cout << " Written Inode Bitmap. Group free inodes: " << current_gd_ref.bg_free_inodes_count << std::endl; + + if (write_zero_blocks(fd, current_gd_ref.bg_inode_table, inode_table_size_blocks) != 0) { /* error */ return 1; } + std::cout << " Zeroed Inode Table." << std::endl; + } + + std::cout << "Re-writing Superblock and GDT (final pre-root dir)..." << std::endl; + std::memcpy(fs_block_buffer.data(), &sb, sizeof(sb)); + if (write_block(fd, superblock_location_block, fs_block_buffer.data()) != 0) { /* error */ return 1;} + + gdt_write_ptr = reinterpret_cast(gdt.data()); + for (uint32_t i = 0; i < gdt_blocks; ++i) { + std::fill(fs_block_buffer.begin(), fs_block_buffer.end(), 0); + uint32_t bytes_to_copy_this_block = (gdt_size_bytes - (i * SIMPLEFS_BLOCK_SIZE) < SIMPLEFS_BLOCK_SIZE) ? + (gdt_size_bytes % SIMPLEFS_BLOCK_SIZE == 0 && gdt_size_bytes > 0 ? SIMPLEFS_BLOCK_SIZE : gdt_size_bytes % SIMPLEFS_BLOCK_SIZE) + : SIMPLEFS_BLOCK_SIZE; + if (gdt_size_bytes == 0 && i==0) bytes_to_copy_this_block = 0; + std::memcpy(fs_block_buffer.data(), gdt_write_ptr + (i * SIMPLEFS_BLOCK_SIZE), bytes_to_copy_this_block); + if (write_block(fd, gdt_start_block + i, fs_block_buffer.data()) != 0) { /* error */ return 1; } + } + + // 将超级块和GDT的备份副本写入指定组 + for (uint32_t grp = 1; grp < num_block_groups; ++grp) { + if (!is_backup_group(grp)) continue; + uint32_t grp_start = grp * sb.s_blocks_per_group; + std::memcpy(fs_block_buffer.data(), &sb, sizeof(sb)); + if (write_block(fd, grp_start, fs_block_buffer.data()) != 0) { /* error */ return 1; } + for (uint32_t i = 0; i < gdt_blocks; ++i) { + std::fill(fs_block_buffer.begin(), fs_block_buffer.end(), 0); + uint32_t bytes_to_copy_this_block = (gdt_size_bytes - (i * SIMPLEFS_BLOCK_SIZE) < SIMPLEFS_BLOCK_SIZE) ? + (gdt_size_bytes % SIMPLEFS_BLOCK_SIZE == 0 && gdt_size_bytes > 0 ? SIMPLEFS_BLOCK_SIZE : gdt_size_bytes % SIMPLEFS_BLOCK_SIZE) + : SIMPLEFS_BLOCK_SIZE; + if (gdt_size_bytes == 0 && i==0) bytes_to_copy_this_block = 0; + std::memcpy(fs_block_buffer.data(), gdt_write_ptr + (i * SIMPLEFS_BLOCK_SIZE), bytes_to_copy_this_block); + if (write_block(fd, grp_start + 1 + i, fs_block_buffer.data()) != 0) { /* error */ return 1; } + } + } + + std::cout << "Creating root directory..." << std::endl; + + SimpleFS_GroupDesc& group0_gd = gdt[0]; + // 根inode(SIMPLEFS_ROOT_INODE_NUM,通常为2)和inode 1(位0) + // 已在inode位图中标记,以及超级块/组描述符 + // 在组0的初始设置循环中已减少了空闲inode计数 + // 因此,此处不需要再次调用set_bitmap_bit或减少计数 + // 只需为组0增加used_dirs_count + group0_gd.bg_used_dirs_count++; + + std::cout << " Root inode " << SIMPLEFS_ROOT_INODE_NUM << " allocation accounted for (marked in bitmap and counts updated earlier)." << std::endl; + std::cout << " Incremented used_dirs_count for group 0." << std::endl; + + // 如果后续决策依赖于最新状态,重新读取inode位图是好习惯 + // 但此处不对根inode号本身做分配决策,只分配其数据块,故继续进行 + // 如有疑问,可重新读取: + // if (read_block(fd, group0_gd.bg_inode_bitmap, group_inode_bitmap_buffer.data()) != 0) { + // std::cerr << "根目录数据分配前重新读取组0 inode位图失败" << std::endl; return 1; + // } + + uint32_t root_dir_data_block_num = 0; + if (read_block(fd, group0_gd.bg_block_bitmap, group_block_bitmap_buffer.data()) != 0) { + std::cerr << "组0块位图读取失败,无法分配根目录数据块" << std::endl; return 1; + } + + uint32_t group0_abs_start_block = 0 * sb.s_blocks_per_group; + uint32_t search_start_offset_in_group0 = 0; + if (sb.s_first_data_block >= group0_abs_start_block && sb.s_first_data_block < (group0_abs_start_block + sb.s_blocks_per_group) ) { + search_start_offset_in_group0 = sb.s_first_data_block - group0_abs_start_block; + } else if (sb.s_first_data_block < group0_abs_start_block) { + search_start_offset_in_group0 = (gdt[0].bg_inode_table + static_cast(std::ceil(static_cast(sb.s_inodes_per_group) * SIMPLEFS_INODE_SIZE / SIMPLEFS_BLOCK_SIZE))) - group0_abs_start_block; + } + + for (uint32_t block_offset_in_group = search_start_offset_in_group0; + block_offset_in_group < sb.s_blocks_per_group; ++block_offset_in_group) { + if (!is_bitmap_bit_set(group_block_bitmap_buffer, block_offset_in_group)) { + root_dir_data_block_num = group0_abs_start_block + block_offset_in_group; + set_bitmap_bit(group_block_bitmap_buffer, block_offset_in_group); + group0_gd.bg_free_blocks_count--; + sb.s_free_blocks_count--; + break; + } + } + + if (root_dir_data_block_num == 0) { + std::cerr << "错误: 组0中找不到根目录的空闲数据块" << std::endl; return 1; + } + if (write_block(fd, group0_gd.bg_block_bitmap, group_block_bitmap_buffer.data()) != 0) { + std::cerr << "组0块位图更新失败" << std::endl; return 1; + } + std::cout << " 已为根目录分配数据块 " << root_dir_data_block_num << std::endl; + + std::vector root_dir_data_buffer(SIMPLEFS_BLOCK_SIZE, 0); + uint16_t current_offset = 0; + + SimpleFS_DirEntry dot_entry; + dot_entry.inode = SIMPLEFS_ROOT_INODE_NUM; + dot_entry.name_len = 1; + dot_entry.file_type = S_IFDIR >> 12; + std::strncpy(dot_entry.name, ".", 1); + dot_entry.rec_len = calculate_dir_entry_len(dot_entry.name_len); + std::memcpy(root_dir_data_buffer.data() + current_offset, &dot_entry, (size_t)8 + dot_entry.name_len); + current_offset += dot_entry.rec_len; + + SimpleFS_DirEntry dotdot_entry; + dotdot_entry.inode = SIMPLEFS_ROOT_INODE_NUM; + dotdot_entry.name_len = 2; + dotdot_entry.file_type = S_IFDIR >> 12; + std::strncpy(dotdot_entry.name, "..", 2); + dotdot_entry.rec_len = SIMPLEFS_BLOCK_SIZE - current_offset; + std::memcpy(root_dir_data_buffer.data() + current_offset, &dotdot_entry, (size_t)8 + dotdot_entry.name_len); + + if (write_block(fd, root_dir_data_block_num, root_dir_data_buffer.data()) != 0) { + std::cerr << "根目录数据块写入失败" << std::endl; return 1; + } + std::cout << " 已向根目录数据块写入'.'和'..'项" << std::endl; + + SimpleFS_Inode root_inode; + std::memset(&root_inode, 0, sizeof(SimpleFS_Inode)); + root_inode.i_mode = S_IFDIR | 0777; // 从0755改为0777便于测试 + root_inode.i_uid = 0; + root_inode.i_gid = 0; + root_inode.i_size = SIMPLEFS_BLOCK_SIZE; + root_inode.i_links_count = 2; + root_inode.i_blocks = SIMPLEFS_BLOCK_SIZE / 512; + root_inode.i_atime = root_inode.i_ctime = root_inode.i_mtime = time(nullptr); + root_inode.i_block[0] = root_dir_data_block_num; + + // 基于1的inode编号的修正计算 + uint32_t root_inode_idx_in_group = SIMPLEFS_ROOT_INODE_NUM - 1; + uint32_t root_inode_block_in_table = group0_gd.bg_inode_table + (root_inode_idx_in_group / inodes_per_block); + uint32_t root_inode_offset_in_block = (root_inode_idx_in_group % inodes_per_block) * SIMPLEFS_INODE_SIZE; + + std::vector inode_table_block_buffer(SIMPLEFS_BLOCK_SIZE); + if (read_block(fd, root_inode_block_in_table, inode_table_block_buffer.data()) != 0) { + std::cerr << "根inode的inode表块读取失败" << std::endl; return 1; + } + std::memcpy(inode_table_block_buffer.data() + root_inode_offset_in_block, &root_inode, sizeof(SimpleFS_Inode)); + if (write_block(fd, root_inode_block_in_table, inode_table_block_buffer.data()) != 0) { + std::cerr << "根inode写入inode表失败" << std::endl; return 1; + } + std::cout << " Initialized and written root inode (inode " << SIMPLEFS_ROOT_INODE_NUM << ")." << std::endl; + + std::cout << "Finalizing Superblock and GDT..." << std::endl; + std::memcpy(fs_block_buffer.data(), &sb, sizeof(sb)); + if (write_block(fd, superblock_location_block, fs_block_buffer.data()) != 0) { /* error */ return 1;} + + gdt_write_ptr = reinterpret_cast(gdt.data()); + for (uint32_t i = 0; i < gdt_blocks; ++i) { + std::fill(fs_block_buffer.begin(), fs_block_buffer.end(), 0); + uint32_t bytes_to_copy_this_block = (gdt_size_bytes - (i * SIMPLEFS_BLOCK_SIZE) < SIMPLEFS_BLOCK_SIZE) ? + (gdt_size_bytes % SIMPLEFS_BLOCK_SIZE == 0 && gdt_size_bytes > 0 ? SIMPLEFS_BLOCK_SIZE : gdt_size_bytes % SIMPLEFS_BLOCK_SIZE) + : SIMPLEFS_BLOCK_SIZE; + if (gdt_size_bytes == 0 && i==0) bytes_to_copy_this_block = 0; + std::memcpy(fs_block_buffer.data(), gdt_write_ptr + (i * SIMPLEFS_BLOCK_SIZE), bytes_to_copy_this_block); + if (write_block(fd, gdt_start_block + i, fs_block_buffer.data()) != 0) { /* error */ return 1; } + } + std::cout << "超级块和GDT已完成" << std::endl; + + std::cout << "文件系统格式化成功" << std::endl; + + if (close(fd) == -1) { + perror("关闭设备/镜像失败"); + } + + std::cout << "SimpleFS格式化工具完成" << std::endl; + return 0; +} diff --git a/课程设计报告.docx b/课程设计报告.docx new file mode 100644 index 0000000..4da7ebc Binary files /dev/null and b/课程设计报告.docx differ