14.7.4 文件系统支持
文件系统是操作系统中负责管理持久数据的核心子系统,提供了数据的组织、存储、检索和访问控制等功能。32位微处理器通过提供内存管理、I/O操作和保护机制等功能,为操作系统实现复杂的文件系统提供了必要的硬件支持。
c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <stdint.h>
// 文件类型定义
typedef enum {
FT_REGULAR, // 普通文件
FT_DIRECTORY, // 目录
FT_SYMLINK, // 符号链接
FT_DEVICE, // 设备文件
FT_PIPE, // 命名管道
FT_SOCKET // 套接字
} FileType;
// 文件访问权限
#define PERM_READ 0x4
#define PERM_WRITE 0x2
#define PERM_EXEC 0x1
// 文件属性结构体
typedef struct {
uint32_t inode; // inode号
FileType type; // 文件类型
uint32_t size; // 文件大小(字节)
uint32_t blockCount; // 占用块数量
uint16_t permissions; // 权限 (rwx)
uint32_t owner; // 所有者ID
uint32_t group; // 所属组ID
time_t creationTime; // 创建时间
time_t modificationTime;// 修改时间
time_t accessTime; // 访问时间
} FileAttributes;
// 文件系统统计信息
typedef struct {
char name[32]; // 文件系统名称
uint32_t totalBlocks; // 总块数
uint32_t freeBlocks; // 空闲块数
uint32_t blockSize; // 块大小(字节)
uint32_t totalInodes; // 总inode数
uint32_t freeInodes; // 空闲inode数
} FilesystemStats;
// 文件系统块结构(简化版)
#define BLOCK_SIZE 4096
typedef struct {
uint8_t data[BLOCK_SIZE];
} Disk_Block;
// 目录项结构
typedef struct DirEntry {
uint32_t inode; // inode号
char name[256]; // 文件名
FileType type; // 文件类型
struct DirEntry* next; // 链表下一个项
} DirEntry;
// inode结构
#define DIRECT_BLOCKS 12
#define INDIRECT_BLOCKS 1
#define DOUBLE_INDIRECT_BLOCKS 1
typedef struct {
uint32_t id; // inode编号
FileAttributes attributes; // 文件属性
uint32_t directBlocks[DIRECT_BLOCKS]; // 直接块指针
uint32_t indirectBlock; // 一级间接块指针
uint32_t doubleIndirectBlock; // 二级间接块指针
bool allocated; // 是否已分配
} Inode;
// 文件描述符
typedef struct {
uint32_t inode; // 关联的inode
uint32_t position; // 当前文件位置
uint16_t flags; // 打开标志
bool inUse; // 是否在使用
} FileDescriptor;
// 文件系统超级块
typedef struct {
char name[32]; // 文件系统名称
uint32_t blockSize; // 块大小
uint32_t totalBlocks; // 总块数
uint32_t freeBlocks; // 空闲块数
uint32_t totalInodes; // 总inode数
uint32_t freeInodes; // 空闲inode数
uint32_t inodeBitmapBlock; // inode位图块号
uint32_t blockBitmapBlock; // 数据块位图块号
uint32_t inodeTableBlock; // inode表起始块号
uint32_t dataBlocksStart; // 数据块起始块号
uint32_t rootInode; // 根目录inode号
} SuperBlock;
// 文件系统结构
typedef struct {
SuperBlock superBlock; // 超级块
Disk_Block* blocks; // 模拟的磁盘块
Inode* inodeTable; // inode表
uint8_t* inodeBitmap; // inode位图
uint8_t* blockBitmap; // 数据块位图
char mountPoint[256]; // 挂载点
bool mounted; // 是否已挂载
} FileSystem;
// 操作系统文件表
#define MAX_OPEN_FILES 64
FileDescriptor openFiles[MAX_OPEN_FILES];
// 当前工作目录
char currentDirectory[256] = "/";
uint32_t currentDirectoryInode = 0;
// 全局文件系统
FileSystem* activeFS = NULL;
// 辅助函数:将权限转换为字符串表示
void formatPermissions(uint16_t perm, char* buffer) {
buffer[0] = (perm & 0x400) ? 'r' : '-';
buffer[1] = (perm & 0x200) ? 'w' : '-';
buffer[2] = (perm & 0x100) ? 'x' : '-';
buffer[3] = (perm & 0x40) ? 'r' : '-';
buffer[4] = (perm & 0x20) ? 'w' : '-';
buffer[5] = (perm & 0x10) ? 'x' : '-';
buffer[6] = (perm & 0x4) ? 'r' : '-';
buffer[7] = (perm & 0x2) ? 'w' : '-';
buffer[8] = (perm & 0x1) ? 'x' : '-';
buffer[9] = '';
}
// 辅助函数:获取文件类型字符表示
char getFileTypeChar(FileType type) {
switch (type) {
case FT_REGULAR: return '-';
case FT_DIRECTORY: return 'd';
case FT_SYMLINK: return 'l';
case FT_DEVICE: return 'c';
case FT_PIPE: return 'p';
case FT_SOCKET: return 's';
default: return '?';
}
}
// 辅助函数:格式化时间
void formatTime(time_t t, char* buffer) {
strftime(buffer, 20, "%Y-%m-%d %H:%M", localtime(&t));
}
// 文件系统初始化
FileSystem* initFileSystem(const char* name, uint32_t sizeInMB) {
printf("初始化文件系统: %s (%u MB)
", name, sizeInMB);
FileSystem* fs = (FileSystem*)malloc(sizeof(FileSystem));
if (!fs) {
printf("错误: 内存分配失败
");
return NULL;
}
// 计算块数和inode数
uint32_t totalBlocks = (sizeInMB * 1024 * 1024) / BLOCK_SIZE;
uint32_t totalInodes = totalBlocks / 4; // 每4个块分配1个inode
// 确保有足够的空间
if (totalBlocks < 100 || totalInodes < 100) {
printf("错误: 文件系统太小
");
free(fs);
return NULL;
}
// 初始化超级块
strncpy(fs->superBlock.name, name, sizeof(fs->superBlock.name) - 1);
fs->superBlock.blockSize = BLOCK_SIZE;
fs->superBlock.totalBlocks = totalBlocks;
fs->superBlock.totalInodes = totalInodes;
// 分配位图和表的位置
fs->superBlock.inodeBitmapBlock = 1; // 超级块后面
fs->superBlock.blockBitmapBlock = 2;
fs->superBlock.inodeTableBlock = 3;
// 计算inode表大小(块数)
uint32_t inodeTableBlocks = (totalInodes * sizeof(Inode) + BLOCK_SIZE - 1) / BLOCK_SIZE;
fs->superBlock.dataBlocksStart = fs->superBlock.inodeTableBlock + inodeTableBlocks;
// 调整总块数和空闲块数
fs->superBlock.totalBlocks = totalBlocks;
fs->superBlock.freeBlocks = totalBlocks - fs->superBlock.dataBlocksStart;
fs->superBlock.freeInodes = totalInodes - 1; // 减去根目录inode
// 设置根目录inode
fs->superBlock.rootInode = 0;
// 分配磁盘块
fs->blocks = (Disk_Block*)calloc(totalBlocks, sizeof(Disk_Block));
if (!fs->blocks) {
printf("错误: 内存分配失败
");
free(fs);
return NULL;
}
// 分配inode表
fs->inodeTable = (Inode*)calloc(totalInodes, sizeof(Inode));
if (!fs->inodeTable) {
printf("错误: 内存分配失败
");
free(fs->blocks);
free(fs);
return NULL;
}
// 分配位图
uint32_t inodeBitmapSize = (totalInodes + 7) / 8;
uint32_t blockBitmapSize = (totalBlocks + 7) / 8;
fs->inodeBitmap = (uint8_t*)calloc(inodeBitmapSize, 1);
fs->blockBitmap = (uint8_t*)calloc(blockBitmapSize, 1);
if (!fs->inodeBitmap || !fs->blockBitmap) {
printf("错误: 内存分配失败
");
if (fs->inodeBitmap) free(fs->inodeBitmap);
if (fs->blockBitmap) free(fs->blockBitmap);
free(fs->inodeTable);
free(fs->blocks);
free(fs);
return NULL;
}
// 标记已使用的块
for (uint32_t i = 0; i < fs->superBlock.dataBlocksStart; i++) {
fs->blockBitmap[i / 8] |= (1 << (i % 8));
}
// 初始化根目录
Inode* rootInode = &fs->inodeTable[fs->superBlock.rootInode];
rootInode->id = fs->superBlock.rootInode;
rootInode->attributes.type = FT_DIRECTORY;
rootInode->attributes.size = 0;
rootInode->attributes.permissions = 0755; // rwxr-xr-x
rootInode->attributes.creationTime = time(NULL);
rootInode->attributes.modificationTime = rootInode->attributes.creationTime;
rootInode->attributes.accessTime = rootInode->attributes.creationTime;
rootInode->allocated = true;
// 分配根目录的第一个块
uint32_t rootDirBlock = fs->superBlock.dataBlocksStart;
rootInode->directBlocks[0] = rootDirBlock;
rootInode->attributes.blockCount = 1;
// 标记根目录inode和块为已使用
fs->inodeBitmap[0] |= 1;
fs->blockBitmap[rootDirBlock / 8] |= (1 << (rootDirBlock % 8));
fs->superBlock.freeBlocks--;
// 创建根目录的"."和".."条目
// 在实际文件系统中,这些是单独的目录项
// 为了简化,我们将它们组合成一个字符串
char* rootDirData = (char*)fs->blocks[rootDirBlock].data;
sprintf(rootDirData, "0 . d
0 .. d
");
rootInode->attributes.size = strlen(rootDirData);
// 设置挂载信息
strcpy(fs->mountPoint, "/");
fs->mounted = false;
printf("文件系统初始化完成:
");
printf(" 总块数: %u
", fs->superBlock.totalBlocks);
printf(" 可用块数: %u
", fs->superBlock.freeBlocks);
printf(" 总inode数: %u
", fs->superBlock.totalInodes);
printf(" 可用inode数: %u
", fs->superBlock.freeInodes);
printf(" 数据区起始块: %u
", fs->superBlock.dataBlocksStart);
return fs;
}
// 挂载文件系统
bool mountFileSystem(FileSystem* fs, const char* mountPoint) {
if (!fs) {
printf("错误: 无效的文件系统
");
return false;
}
if (fs->mounted) {
printf("错误: 文件系统已经挂载
");
return false;
}
printf("挂载文件系统 '%s' 到 '%s'
", fs->superBlock.name, mountPoint);
strncpy(fs->mountPoint, mountPoint, sizeof(fs->mountPoint) - 1);
fs->mounted = true;
// 设置为活动文件系统
activeFS = fs;
currentDirectoryInode = fs->superBlock.rootInode;
strcpy(currentDirectory, "/");
printf("文件系统挂载成功
");
return true;
}
// 卸载文件系统
bool unmountFileSystem(FileSystem* fs) {
if (!fs || !fs->mounted) {
printf("错误: 文件系统未挂载
");
return false;
}
printf("卸载文件系统 '%s' 从 '%s'
", fs->superBlock.name, fs->mountPoint);
// 关闭所有打开的文件
for (int i = 0; i < MAX_OPEN_FILES; i++) {
if (openFiles[i].inUse) {
printf("警告: 文件描述符 %d 仍在使用中
", i);
openFiles[i].inUse = false;
}
}
fs->mounted = false;
if (activeFS == fs) {
activeFS = NULL;
}
printf("文件系统卸载成功
");
return true;
}
// 分配新的inode
uint32_t allocateInode(FileSystem* fs) {
if (!fs) return 0;
// 如果没有空闲inode,返回0
if (fs->superBlock.freeInodes == 0) {
printf("错误: 没有空闲inode
");
return 0;
}
// 查找第一个空闲inode
for (uint32_t i = 0; i < fs->superBlock.totalInodes; i++) {
uint8_t byte = fs->inodeBitmap[i / 8];
uint8_t bit = 1 << (i % 8);
if ((byte & bit) == 0) {
// 找到空闲inode,标记为已使用
fs->inodeBitmap[i / 8] |= bit;
fs->superBlock.freeInodes--;
// 初始化inode
Inode* inode = &fs->inodeTable[i];
memset(inode, 0, sizeof(Inode));
inode->id = i;
inode->allocated = true;
inode->attributes.creationTime = time(NULL);
inode->attributes.modificationTime = inode->attributes.creationTime;
inode->attributes.accessTime = inode->attributes.creationTime;
return i;
}
}
return 0; // 未找到空闲inode
}
// 释放inode
void freeInode(FileSystem* fs, uint32_t inodeNum) {
if (!fs || inodeNum >= fs->superBlock.totalInodes) return;
// 检查inode是否已分配
uint8_t byte = fs->inodeBitmap[inodeNum / 8];
uint8_t bit = 1 << (inodeNum % 8);
if ((byte & bit) == 0) {
printf("警告: 尝试释放未分配的inode %u
", inodeNum);
return;
}
// 释放inode关联的所有数据块
Inode* inode = &fs->inodeTable[inodeNum];
// 直接块
for (int i = 0; i < DIRECT_BLOCKS; i++) {
if (inode->directBlocks[i] != 0) {
// 释放数据块
fs->blockBitmap[inode->directBlocks[i] / 8] &= ~(1 << (inode->directBlocks[i] % 8));
fs->superBlock.freeBlocks++;
inode->directBlocks[i] = 0;
}
}
// 一级间接块
if (inode->indirectBlock != 0) {
uint32_t* indirectTable = (uint32_t*)fs->blocks[inode->indirectBlock].data;
for (uint32_t i = 0; i < BLOCK_SIZE / sizeof(uint32_t); i++) {
if (indirectTable[i] != 0) {
fs->blockBitmap[indirectTable[i] / 8] &= ~(1 << (indirectTable[i] % 8));
fs->superBlock.freeBlocks++;
}
}
// 释放间接块本身
fs->blockBitmap[inode->indirectBlock / 8] &= ~(1 << (inode->indirectBlock % 8));
fs->superBlock.freeBlocks++;
inode->indirectBlock = 0;
}
// 二级间接块 (简化处理)
if (inode->doubleIndirectBlock != 0) {
uint32_t* doubleIndirectTable = (uint32_t*)fs->blocks[inode->doubleIndirectBlock].data;
// 遍历所有一级间接块
for (uint32_t i = 0; i < BLOCK_SIZE / sizeof(uint32_t); i++) {
if (doubleIndirectTable[i] != 0) {
uint32_t* indirectTable = (uint32_t*)fs->blocks[doubleIndirectTable[i]].data;
// 释放二级指向的数据块
for (uint32_t j = 0; j < BLOCK_SIZE / sizeof(uint32_t); j++) {
if (indirectTable[j] != 0) {
fs->blockBitmap[indirectTable[j] / 8] &= ~(1 << (indirectTable[j] % 8));
fs->superBlock.freeBlocks++;
}
}
// 释放一级间接块
fs->blockBitmap[doubleIndirectTable[i] / 8] &= ~(1 << (doubleIndirectTable[i] % 8));
fs->superBlock.freeBlocks++;
}
}
// 释放二级间接块本身
fs->blockBitmap[inode->doubleIndirectBlock / 8] &= ~(1 << (inode->doubleIndirectBlock % 8));
fs->superBlock.freeBlocks++;
inode->doubleIndirectBlock = 0;
}
// 标记inode为空闲
fs->inodeBitmap[inodeNum / 8] &= ~bit;
fs->superBlock.freeInodes++;
// 清除inode数据
memset(inode, 0, sizeof(Inode));
}
// 分配数据块
uint32_t allocateBlock(FileSystem* fs) {
if (!fs) return 0;
// 如果没有空闲块,返回0
if (fs->superBlock.freeBlocks == 0) {
printf("错误: 没有空闲数据块
");
return 0;
}
// 从数据块区域开始查找第一个空闲块
for (uint32_t i = fs->superBlock.dataBlocksStart; i < fs->superBlock.totalBlocks; i++) {
uint8_t byte = fs->blockBitmap[i / 8];
uint8_t bit = 1 << (i % 8);
if ((byte & bit) == 0) {
// 找到空闲块,标记为已使用
fs->blockBitmap[i / 8] |= bit;
fs->superBlock.freeBlocks--;
// 清零块数据
memset(fs->blocks[i].data, 0, BLOCK_SIZE);
return i;
}
}
return 0; // 未找到空闲块
}
// 释放数据块
void freeBlock(FileSystem* fs, uint32_t blockNum) {
if (!fs || blockNum < fs->superBlock.dataBlocksStart || blockNum >= fs->superBlock.totalBlocks) {
printf("错误: 无效的块号 %u
", blockNum);
return;
}
// 检查块是否已分配
uint8_t byte = fs->blockBitmap[blockNum / 8];
uint8_t bit = 1 << (blockNum % 8);
if ((byte & bit) == 0) {
printf("警告: 尝试释放未分配的块 %u
", blockNum);
return;
}
// 标记为空闲
fs->blockBitmap[blockNum / 8] &= ~bit;
fs->superBlock.freeBlocks++;
// 清零块数据
memset(fs->blocks[blockNum].data, 0, BLOCK_SIZE);
}
// 查找inode对应逻辑块号的物理块
uint32_t findBlock(FileSystem* fs, Inode* inode, uint32_t logicalBlock) {
if (!fs || !inode || !inode->allocated) return 0;
// 直接块
if (logicalBlock < DIRECT_BLOCKS) {
return inode->directBlocks[logicalBlock];
}
// 一级间接块
logicalBlock -= DIRECT_BLOCKS;
uint32_t indirectEntries = BLOCK_SIZE / sizeof(uint32_t);
if (logicalBlock < indirectEntries) {
if (inode->indirectBlock == 0) return 0;
uint32_t* indirectTable = (uint32_t*)fs->blocks[inode->indirectBlock].data;
return indirectTable[logicalBlock];
}
// 二级间接块
logicalBlock -= indirectEntries;
uint32_t doubleIndirectEntries = indirectEntries * indirectEntries;
if (logicalBlock < doubleIndirectEntries) {
if (inode->doubleIndirectBlock == 0) return 0;
uint32_t doubleIndirectIndex = logicalBlock / indirectEntries;
uint32_t indirectIndex = logicalBlock % indirectEntries;
uint32_t* doubleIndirectTable = (uint32_t*)fs->blocks[inode->doubleIndirectBlock].data;
if (doubleIndirectTable[doubleIndirectIndex] == 0) return 0;
uint32_t* indirectTable = (uint32_t*)fs->blocks[doubleIndirectTable[doubleIndirectIndex]].data;
return indirectTable[indirectIndex];
}
// 超出文件系统支持的最大文件大小
return 0;
}
// 分配逻辑块对应的物理块
uint32_t allocateFileBlock(FileSystem* fs, Inode* inode, uint32_t logicalBlock) {
if (!fs || !inode || !inode->allocated) return 0;
// 直接块
if (logicalBlock < DIRECT_BLOCKS) {
if (inode->directBlocks[logicalBlock] == 0) {
inode->directBlocks[logicalBlock] = allocateBlock(fs);
if (inode->directBlocks[logicalBlock] != 0) {
inode->attributes.blockCount++;
}
}
return inode->directBlocks[logicalBlock];
}
// 一级间接块
logicalBlock -= DIRECT_BLOCKS;
uint32_t indirectEntries = BLOCK_SIZE / sizeof(uint32_t);
if (logicalBlock < indirectEntries) {
// 分配间接块(如果需要)
if (inode->indirectBlock == 0) {
inode->indirectBlock = allocateBlock(fs);
if (inode->indirectBlock == 0) return 0;
inode->attributes.blockCount++;
// 初始化间接块表
memset(fs->blocks[inode->indirectBlock].data, 0, BLOCK_SIZE);
}
// 获取间接块表
uint32_t* indirectTable = (uint32_t*)fs->blocks[inode->indirectBlock].data;
// 分配数据块(如果需要)
if (indirectTable[logicalBlock] == 0) {
indirectTable[logicalBlock] = allocateBlock(fs);
if (indirectTable[logicalBlock] != 0) {
inode->attributes.blockCount++;
}
}
return indirectTable[logicalBlock];
}
// 二级间接块
logicalBlock -= indirectEntries;
uint32_t doubleIndirectEntries = indirectEntries * indirectEntries;
if (logicalBlock < doubleIndirectEntries) {
// 分配二级间接块(如果需要)
if (inode->doubleIndirectBlock == 0) {
inode->doubleIndirectBlock = allocateBlock(fs);
if (inode->doubleIndirectBlock == 0) return 0;
inode->attributes.blockCount++;
// 初始化二级间接块表
memset(fs->blocks[inode->doubleIndirectBlock].data, 0, BLOCK_SIZE);
}
uint32_t doubleIndirectIndex = logicalBlock / indirectEntries;
uint32_t indirectIndex = logicalBlock % indirectEntries;
// 获取二级间接块表
uint32_t* doubleIndirectTable = (uint32_t*)fs->blocks[inode->doubleIndirectBlock].data;
// 分配一级间接块(如果需要)
if (doubleIndirectTable[doubleIndirectIndex] == 0) {
doubleIndirectTable[doubleIndirectIndex] = allocateBlock(fs);
if (doubleIndirectTable[doubleIndirectIndex] == 0) return 0;
inode->attributes.blockCount++;
// 初始化一级间接块表
memset(fs->blocks[doubleIndirectTable[doubleIndirectIndex]].data, 0, BLOCK_SIZE);
}
// 获取一级间接块表
uint32_t* indirectTable = (uint32_t*)fs->blocks[doubleIndirectTable[doubleIndirectIndex]].data;
// 分配数据块(如果需要)
if (indirectTable[indirectIndex] == 0) {
indirectTable[indirectIndex] = allocateBlock(fs);
if (indirectTable[indirectIndex] != 0) {
inode->attributes.blockCount++;
}
}
return indirectTable[indirectIndex];
}
// 超出文件系统支持的最大文件大小
return 0;
}
// 解析目录内容
DirEntry* readDirectoryEntries(FileSystem* fs, uint32_t inodeNum) {
if (!fs || inodeNum >= fs->superBlock.totalInodes) return NULL;
Inode* inode = &fs->inodeTable[inodeNum];
if (!inode->allocated || inode->attributes.type != FT_DIRECTORY) {
return NULL;
}
// 读取目录内容
char* dirContent = (char*)malloc(inode->attributes.size + 1);
if (!dirContent) return NULL;
uint32_t bytesRead = 0;
uint32_t blockIndex = 0;
while (bytesRead < inode->attributes.size) {
uint32_t blockNum = findBlock(fs, inode, blockIndex);
if (blockNum == 0) break;
uint32_t bytesToRead = BLOCK_SIZE;
if (bytesRead + bytesToRead > inode->attributes.size) {
bytesToRead = inode->attributes.size - bytesRead;
}
memcpy(dirContent + bytesRead, fs->blocks[blockNum].data, bytesToRead);
bytesRead += bytesToRead;
blockIndex++;
}
dirContent[bytesRead] = '';
// 解析目录内容
DirEntry* head = NULL;
DirEntry* tail = NULL;
char* line = strtok(dirContent, "
");
while (line != NULL) {
uint32_t entryInode;
char entryName[256];
char typeChar;
// 解析格式: "inode名称 类型"
if (sscanf(line, "%u %255s %c", &entryInode, entryName, &typeChar) == 3) {
DirEntry* entry = (DirEntry*)malloc(sizeof(DirEntry));
if (entry) {
entry->inode = entryInode;
strncpy(entry->name, entryName, sizeof(entry->name) - 1);
entry->name[sizeof(entry->name) - 1] = '';
switch (typeChar) {
case 'd': entry->type = FT_DIRECTORY; break;
case 'l': entry->type = FT_SYMLINK; break;
case 'c': entry->type = FT_DEVICE; break;
case 'p': entry->type = FT_PIPE; break;
case 's': entry->type = FT_SOCKET; break;
default: entry->type = FT_REGULAR; break;
}
entry->next = NULL;
if (head == NULL) {
head = entry;
} else {
tail->next = entry;
}
tail = entry;
}
}
line = strtok(NULL, "
");
}
free(dirContent);
return head;
}
// 添加目录项
bool addDirectoryEntry(FileSystem* fs, uint32_t dirInode, uint32_t entryInode, const char* name, FileType type) {
if (!fs || dirInode >= fs->superBlock.totalInodes || entryInode >= fs->superBlock.totalInodes) {
return false;
}
Inode* inode = &fs->inodeTable[dirInode];
if (!inode->allocated || inode->attributes.type != FT_DIRECTORY) {
return false;
}
// 检查名称是否已存在
DirEntry* entries = readDirectoryEntries(fs, dirInode);
DirEntry* current = entries;
while (current) {
if (strcmp(current->name, name) == 0) {
// 释放内存
while (entries) {
DirEntry* next = entries->next;
free(entries);
entries = next;
}
return false;
}
current = current->next;
}
// 释放内存
while (entries) {
DirEntry* next = entries->next;
free(entries);
entries = next;
}
// 读取当前目录内容
char* dirContent = (char*)malloc(inode->attributes.size + 1);
if (!dirContent) return false;
uint32_t bytesRead = 0;
uint32_t blockIndex = 0;
while (bytesRead < inode->attributes.size
while (bytesRead < inode->attributes.size) {
uint32_t blockNum = findBlock(fs, inode, blockIndex);
if (blockNum == 0) break;
uint32_t bytesToRead = BLOCK_SIZE;
if (bytesRead + bytesToRead > inode->attributes.size) {
bytesToRead = inode->attributes.size - bytesRead;
}
memcpy(dirContent + bytesRead, fs->blocks[blockNum].data, bytesToRead);
bytesRead += bytesToRead;
blockIndex++;
}
dirContent[bytesRead] = '';
// 获取类型字符
char typeChar;
switch (type) {
case FT_DIRECTORY: typeChar = 'd'; break;
case FT_SYMLINK: typeChar = 'l'; break;
case FT_DEVICE: typeChar = 'c'; break;
case FT_PIPE: typeChar = 'p'; break;
case FT_SOCKET: typeChar = 's'; break;
default: typeChar = '-'; break;
}
// 构建新的目录内容
char* newContent = (char*)malloc(inode->attributes.size + 256);
if (!newContent) {
free(dirContent);
return false;
}
// 复制现有内容并添加新项
strcpy(newContent, dirContent);
free(dirContent);
// 添加新条目
sprintf(newContent + inode->attributes.size, "%u %s %c
", entryInode, name, typeChar);
uint32_t newSize = strlen(newContent);
// 写回目录内容
uint32_t bytesWritten = 0;
blockIndex = 0;
while (bytesWritten < newSize) {
uint32_t blockNum = findBlock(fs, inode, blockIndex);
if (blockNum == 0) {
blockNum = allocateFileBlock(fs, inode, blockIndex);
if (blockNum == 0) {
free(newContent);
return false;
}
}
uint32_t bytesToWrite = BLOCK_SIZE;
if (bytesWritten + bytesToWrite > newSize) {
bytesToWrite = newSize - bytesWritten;
}
memcpy(fs->blocks[blockNum].data, newContent + bytesWritten, bytesToWrite);
bytesWritten += bytesToWrite;
blockIndex++;
}
// 更新目录inode
inode->attributes.size = newSize;
inode->attributes.modificationTime = time(NULL);
free(newContent);
return true;
}
// 删除目录项
bool removeDirectoryEntry(FileSystem* fs, uint32_t dirInode, const char* name) {
if (!fs || dirInode >= fs->superBlock.totalInodes) {
return false;
}
Inode* inode = &fs->inodeTable[dirInode];
if (!inode->allocated || inode->attributes.type != FT_DIRECTORY) {
return false;
}
// 检查名称是否存在
bool found = false;
DirEntry* entries = readDirectoryEntries(fs, dirInode);
DirEntry* current = entries;
while (current) {
if (strcmp(current->name, name) == 0) {
found = true;
break;
}
current = current->next;
}
if (!found) {
// 释放内存
while (entries) {
DirEntry* next = entries->next;
free(entries);
entries = next;
}
return false;
}
// 读取当前目录内容
char* dirContent = (char*)malloc(inode->attributes.size + 1);
if (!dirContent) {
// 释放内存
while (entries) {
DirEntry* next = entries->next;
free(entries);
entries = next;
}
return false;
}
uint32_t bytesRead = 0;
uint32_t blockIndex = 0;
while (bytesRead < inode->attributes.size) {
uint32_t blockNum = findBlock(fs, inode, blockIndex);
if (blockNum == 0) break;
uint32_t bytesToRead = BLOCK_SIZE;
if (bytesRead + bytesToRead > inode->attributes.size) {
bytesToRead = inode->attributes.size - bytesRead;
}
memcpy(dirContent + bytesRead, fs->blocks[blockNum].data, bytesToRead);
bytesRead += bytesToRead;
blockIndex++;
}
dirContent[bytesRead] = '';
// 构建不包含要删除条目的新内容
char* newContent = (char*)malloc(inode->attributes.size + 1);
if (!newContent) {
free(dirContent);
// 释放内存
while (entries) {
DirEntry* next = entries->next;
free(entries);
entries = next;
}
return false;
}
newContent[0] = '';
char* line = strtok(dirContent, "
");
while (line != NULL) {
uint32_t entryInode;
char entryName[256];
char typeChar;
// 解析格式: "inode名称 类型"
if (sscanf(line, "%u %255s %c", &entryInode, entryName, &typeChar) == 3) {
if (strcmp(entryName, name) != 0) {
// 如果不是要删除的条目,保留它
strcat(newContent, line);
strcat(newContent, "
");
}
}
line = strtok(NULL, "
");
}
free(dirContent);
// 写回目录内容
uint32_t newSize = strlen(newContent);
uint32_t bytesWritten = 0;
blockIndex = 0;
while (bytesWritten < newSize) {
uint32_t blockNum = findBlock(fs, inode, blockIndex);
if (blockNum == 0) break;
uint32_t bytesToWrite = BLOCK_SIZE;
if (bytesWritten + bytesToWrite > newSize) {
bytesToWrite = newSize - bytesWritten;
}
memcpy(fs->blocks[blockNum].data, newContent + bytesWritten, bytesToWrite);
bytesWritten += bytesToWrite;
blockIndex++;
}
// 如果新内容比旧内容短,清零剩余块
while (true) {
uint32_t blockNum = findBlock(fs, inode, blockIndex);
if (blockNum == 0) break;
memset(fs->blocks[blockNum].data, 0, BLOCK_SIZE);
blockIndex++;
}
// 更新目录inode
inode->attributes.size = newSize;
inode->attributes.modificationTime = time(NULL);
free(newContent);
// 释放内存
while (entries) {
DirEntry* next = entries->next;
free(entries);
entries = next;
}
return true;
}
// 查找文件/目录
uint32_t findFileInode(FileSystem* fs, uint32_t dirInode, const char* name) {
if (!fs || dirInode >= fs->superBlock.totalInodes) {
return 0;
}
DirEntry* entries = readDirectoryEntries(fs, dirInode);
DirEntry* current = entries;
uint32_t foundInode = 0;
while (current) {
if (strcmp(current->name, name) == 0) {
foundInode = current->inode;
break;
}
current = current->next;
}
// 释放内存
while (entries) {
DirEntry* next = entries->next;
free(entries);
entries = next;
}
return foundInode;
}
// 解析路径
uint32_t resolvePath(FileSystem* fs, const char* path, uint32_t startInode) {
if (!fs || !path) return 0;
// 复制路径以便修改
char* pathCopy = strdup(path);
if (!pathCopy) return 0;
uint32_t currentInode = startInode;
// 如果路径以'/'开头,从根目录开始
if (pathCopy[0] == '/') {
currentInode = fs->superBlock.rootInode;
}
char* token = strtok(pathCopy, "/");
while (token) {
// 跳过当前目录"."
if (strcmp(token, ".") == 0) {
token = strtok(NULL, "/");
continue;
}
// 父目录".."
if (strcmp(token, "..") == 0) {
// 读取当前目录的".."条目
DirEntry* entries = readDirectoryEntries(fs, currentInode);
DirEntry* current = entries;
while (current) {
if (strcmp(current->name, "..") == 0) {
currentInode = current->inode;
break;
}
current = current->next;
}
// 释放内存
while (entries) {
DirEntry* next = entries->next;
free(entries);
entries = next;
}
token = strtok(NULL, "/");
continue;
}
// 查找子目录/文件
uint32_t nextInode = findFileInode(fs, currentInode, token);
if (nextInode == 0) {
free(pathCopy);
return 0; // 路径不存在
}
currentInode = nextInode;
token = strtok(NULL, "/");
}
free(pathCopy);
return currentInode;
}
// 创建文件
uint32_t createFile(FileSystem* fs, uint32_t dirInode, const char* name, uint16_t permissions) {
if (!fs || dirInode >= fs->superBlock.totalInodes) {
return 0;
}
// 检查目录是否存在
Inode* dirInodePtr = &fs->inodeTable[dirInode];
if (!dirInodePtr->allocated || dirInodePtr->attributes.type != FT_DIRECTORY) {
return 0;
}
// 检查文件名是否已存在
if (findFileInode(fs, dirInode, name) != 0) {
return 0;
}
// 分配新的inode
uint32_t newInode = allocateInode(fs);
if (newInode == 0) {
return 0;
}
// 初始化inode
Inode* inode = &fs->inodeTable[newInode];
inode->attributes.type = FT_REGULAR;
inode->attributes.size = 0;
inode->attributes.blockCount = 0;
inode->attributes.permissions = permissions;
// 添加到目录
if (!addDirectoryEntry(fs, dirInode, newInode, name, FT_REGULAR)) {
freeInode(fs, newInode);
return 0;
}
return newInode;
}
// 创建目录
uint32_t createDirectory(FileSystem* fs, uint32_t parentInode, const char* name, uint16_t permissions) {
if (!fs || parentInode >= fs->superBlock.totalInodes) {
return 0;
}
// 检查父目录是否存在
Inode* parentInodePtr = &fs->inodeTable[parentInode];
if (!parentInodePtr->allocated || parentInodePtr->attributes.type != FT_DIRECTORY) {
return 0;
}
// 检查目录名是否已存在
if (findFileInode(fs, parentInode, name) != 0) {
return 0;
}
// 分配新的inode
uint32_t newInode = allocateInode(fs);
if (newInode == 0) {
return 0;
}
// 初始化inode
Inode* inode = &fs->inodeTable[newInode];
inode->attributes.type = FT_DIRECTORY;
inode->attributes.permissions = permissions;
// 分配第一个数据块
uint32_t blockNum = allocateFileBlock(fs, inode, 0);
if (blockNum == 0) {
freeInode(fs, newInode);
return 0;
}
// 创建"."和".."条目
char initialContent[256];
sprintf(initialContent, "%u . d
%u .. d
", newInode, parentInode);
// 写入目录内容
uint32_t contentSize = strlen(initialContent);
memcpy(fs->blocks[blockNum].data, initialContent, contentSize);
// 更新目录inode
inode->attributes.size = contentSize;
// 添加到父目录
if (!addDirectoryEntry(fs, parentInode, newInode, name, FT_DIRECTORY)) {
freeInode(fs, newInode);
return 0;
}
return newInode;
}
// 删除文件
bool deleteFile(FileSystem* fs, uint32_t dirInode, const char* name) {
if (!fs || dirInode >= fs->superBlock.totalInodes) {
return false;
}
// 查找文件inode
uint32_t fileInode = findFileInode(fs, dirInode, name);
if (fileInode == 0) {
return false;
}
// 检查是否是普通文件
Inode* inode = &fs->inodeTable[fileInode];
if (inode->attributes.type != FT_REGULAR) {
return false;
}
// 从目录中移除
if (!removeDirectoryEntry(fs, dirInode, name)) {
return false;
}
// 释放inode和相关块
freeInode(fs, fileInode);
return true;
}
// 删除目录 (必须为空)
bool deleteDirectory(FileSystem* fs, uint32_t parentInode, const char* name) {
if (!fs || parentInode >= fs->superBlock.totalInodes) {
return false;
}
// 查找目录inode
uint32_t dirInode = findFileInode(fs, parentInode, name);
if (dirInode == 0) {
return false;
}
// 检查是否是目录
Inode* inode = &fs->inodeTable[dirInode];
if (inode->attributes.type != FT_DIRECTORY) {
return false;
}
// 检查目录是否为空
DirEntry* entries = readDirectoryEntries(fs, dirInode);
DirEntry* current = entries;
int entryCount = 0;
while (current) {
// 忽略"."和".."
if (strcmp(current->name, ".") != 0 && strcmp(current->name, "..") != 0) {
entryCount++;
}
current = current->next;
}
// 释放内存
while (entries) {
DirEntry* next = entries->next;
free(entries);
entries = next;
}
if (entryCount > 0) {
printf("错误: 目录不为空
");
return false;
}
// 从父目录中移除
if (!removeDirectoryEntry(fs, parentInode, name)) {
return false;
}
// 释放inode和相关块
freeInode(fs, dirInode);
return true;
}
// 打开文件
int openFile(FileSystem* fs, const char* path, uint16_t flags) {
if (!fs) return -1;
// 解析路径
uint32_t inode = resolvePath(fs, path, currentDirectoryInode);
if (inode == 0) {
printf("错误: 文件 %s 不存在
", path);
return -1;
}
// 检查是否是普通文件
if (fs->inodeTable[inode].attributes.type != FT_REGULAR) {
printf("错误: %s 不是普通文件
", path);
return -1;
}
// 找到空闲文件描述符
for (int i = 0; i < MAX_OPEN_FILES; i++) {
if (!openFiles[i].inUse) {
openFiles[i].inUse = true;
openFiles[i].inode = inode;
openFiles[i].position = 0;
openFiles[i].flags = flags;
// 更新访问时间
fs->inodeTable[inode].attributes.accessTime = time(NULL);
return i;
}
}
printf("错误: 文件描述符已用完
");
return -1;
}
// 关闭文件
bool closeFile(int fd) {
if (fd < 0 || fd >= MAX_OPEN_FILES || !openFiles[fd].inUse) {
return false;
}
openFiles[fd].inUse = false;
return true;
}
// 读取文件内容
int readFile(FileSystem* fs, int fd, void* buffer, uint32_t size) {
if (!fs || fd < 0 || fd >= MAX_OPEN_FILES || !openFiles[fd].inUse || buffer == NULL) {
return -1;
}
FileDescriptor* fileDesc = &openFiles[fd];
Inode* inode = &fs->inodeTable[fileDesc->inode];
// 检查是否超出文件范围
if (fileDesc->position >= inode->attributes.size) {
return 0; // 文件结束
}
// 计算实际可读取的字节数
uint32_t bytesToRead = size;
if (fileDesc->position + bytesToRead > inode->attributes.size) {
bytesToRead = inode->attributes.size - fileDesc->position;
}
uint32_t bytesRead = 0;
uint8_t* buf = (uint8_t*)buffer;
while (bytesRead < bytesToRead) {
// 计算逻辑块号和块内偏移
uint32_t logicalBlock = fileDesc->position / BLOCK_SIZE;
uint32_t offset = fileDesc->position % BLOCK_SIZE;
// 获取物理块号
uint32_t blockNum = findBlock(fs, inode, logicalBlock);
if (blockNum == 0) {
break;
}
// 计算本次读取字节数
uint32_t blockBytesToRead = BLOCK_SIZE - offset;
if (blockBytesToRead > bytesToRead - bytesRead) {
blockBytesToRead = bytesToRead - bytesRead;
}
// 读取数据
memcpy(buf + bytesRead, fs->blocks[blockNum].data + offset, blockBytesToRead);
bytesRead += blockBytesToRead;
fileDesc->position += blockBytesToRead;
}
// 更新访问时间
inode->attributes.accessTime = time(NULL);
return bytesRead;
}
// 写入文件内容
int writeFile(FileSystem* fs, int fd, const void* buffer, uint32_t size) {
if (!fs || fd < 0 || fd >= MAX_OPEN_FILES || !openFiles[fd].inUse || buffer == NULL) {
return -1;
}
FileDescriptor* fileDesc = &openFiles[fd];
Inode* inode = &fs->inodeTable[fileDesc->inode];
// 检查写入权限
if ((fileDesc->flags & 0x2) == 0) {
printf("错误: 文件未以写入模式打开
");
return -1;
}
uint32_t bytesWritten = 0;
const uint8_t* buf = (const uint8_t*)buffer;
while (bytesWritten < size) {
// 计算逻辑块号和块内偏移
uint32_t logicalBlock = fileDesc->position / BLOCK_SIZE;
uint32_t offset = fileDesc->position % BLOCK_SIZE;
// 获取或分配物理块号
uint32_t blockNum = findBlock(fs, inode, logicalBlock);
if (blockNum == 0) {
blockNum = allocateFileBlock(fs, inode, logicalBlock);
if (blockNum == 0) {
break; // 无法分配更多块
}
}
// 计算本次写入字节数
uint32_t blockBytesToWrite = BLOCK_SIZE - offset;
if (blockBytesToWrite > size - bytesWritten) {
blockBytesToWrite = size - bytesWritten;
}
// 写入数据
memcpy(fs->blocks[blockNum].data + offset, buf + bytesWritten, blockBytesToWrite);
bytesWritten += blockBytesToWrite;
fileDesc->position += blockBytesToWrite;
}
// 更新文件大小
if (fileDesc->position > inode->attributes.size) {
inode->attributes.size = fileDesc->position;
}
// 更新修改时间
inode->attributes.modificationTime = time(NULL);
return bytesWritten;
}
// 重定位文件指针
bool seekFile(int fd, int32_t offset, int whence) {
if (fd < 0 || fd >= MAX_OPEN_FILES || !openFiles[fd].inUse) {
return false;
}
FileDescriptor* fileDesc = &openFiles[fd];
Inode* inode = &activeFS->inodeTable[fileDesc->inode];
uint32_t newPosition;
switch (whence) {
case 0: // 从文件开头
if (offset < 0) return false;
newPosition = offset;
break;
case 1: // 从当前位置
if (offset < 0 && (uint32_t)(-offset) > fileDesc->position) return false;
newPosition = fileDesc->position + offset;
break;
case 2: // 从文件末尾
if (offset < 0 && (uint32_t)(-offset) > inode->attributes.size) return false;
newPosition = inode->attributes.size + offset;
break;
default:
return false;
}
// 更新文件位置
fileDesc->position = newPosition;
return true;
}
// 获取文件状态
bool statFile(FileSystem* fs, const char* path, FileAttributes* attr) {
if (!fs || !path || !attr) {
return false;
}
uint32_t inode = resolvePath(fs, path, currentDirectoryInode);
if (inode == 0) {
return false;
}
// 复制文件属性
memcpy(attr, &fs->inodeTable[inode].attributes, sizeof(FileAttributes));
attr->inode = inode;
return true;
}
// 更改工作目录
bool changeDirectory(FileSystem* fs, const char* path) {
if (!fs || !path) {
return false;
}
uint32_t inode = resolvePath(fs, path, currentDirectoryInode);
if (inode == 0) {
printf("错误: 目录 '%s' 不存在
", path);
return false;
}
// 确保是目录
if (fs->inodeTable[inode].attributes.type != FT_DIRECTORY) {
printf("错误: '%s' 不是目录
", path);
return false;
}
// 更新当前工作目录
currentDirectoryInode = inode;
// 更新目录路径
if (path[0] == '/') {
// 绝对路径
strncpy(currentDirectory, path, sizeof(currentDirectory) - 1);
} else {
// 相对路径
char tempPath[256];
if (strcmp(path, "..") == 0) {
// 上一级目录
char* lastSlash = strrchr(currentDirectory, '/');
if (lastSlash == currentDirectory) {
strcpy(currentDirectory, "/");
} else if (lastSlash) {
*lastSlash = '';
}
} else if (strcmp(path, ".") == 0) {
// 当前目录,不变
} else {
// 子目录
if (currentDirectory[strlen(currentDirectory) - 1] != '/') {
strcat(currentDirectory, "/");
}
strcat(currentDirectory, path);
}
}
// 确保路径以"/"开头
if (currentDirectory[0] != '/') {
memmove(currentDirectory + 1, currentDirectory, strlen(currentDirectory) + 1);
currentDirectory[0] = '/';
}
// 去掉尾部的"/"(除了根目录)
size_t len = strlen(currentDirectory);
if (len > 1 && currentDirectory[len - 1] == '/') {
currentDirectory[len - 1] = '';
}
return true;
}
// 列出目录内容
void listDirectory(FileSystem* fs, const char* path) {
if (!fs) {
return;
}
uint32_t dirInode;
if (path == NULL || strlen(path) == 0) {
dirInode = currentDirectoryInode;
} else {
dirInode = resolvePath(fs, path, currentDirectoryInode);
if (dirInode == 0) {
printf("错误: 目录 '%s' 不存在
", path ? path : "");
return;
}
}
// 确保是目录
if (fs->inodeTable[dirInode].attributes.type != FT_DIRECTORY) {
printf("错误: '%s' 不是目录
", path ? path : currentDirectory);
return;
}
// 读取目录内容
DirEntry* entries = readDirectoryEntries(fs, dirInode);
if (!entries) {
printf("目录为空或无法读取
");
return;
}
// 打印目录标头
printf("
目录列表: %s
", path ? path : currentDirectory);
printf("%-6s %-10s %-12s %-6s %-8s %s
",
"Inode", "权限", "大小", "块数", "类型", "名称");
printf("-----------------------------------------------
");
// 遍历目录项
DirEntry* current = entries;
while (current) {
Inode* fileInode = &fs->inodeTable[current->inode];
// 格式化权限
char perms[10];
formatPermissions(fileInode->attributes.permissions, perms);
// 获取文件类型字符
char typeStr[20];
switch (current->type) {
case FT_DIRECTORY: strcpy(typeStr, "目录"); break;
case FT_REGULAR: strcpy(typeStr, "文件"); break;
case FT_SYMLINK: strcpy(typeStr, "链接"); break;
case FT_DEVICE: strcpy(typeStr, "设备"); break;
case FT_PIPE: strcpy(typeStr, "管道"); break;
case FT_SOCKET: strcpy(typeStr, "套接字"); break;
default: strcpy(typeStr, "未知"); break;
}
printf("%-6u %-10s %-12u %-6u %-8s %s
",
current->inode,
perms,
fileInode->attributes.size,
fileInode->attributes.blockCount,
typeStr,
current->name);
current = current->next;
}
// 释放内存
while (entries) {
DirEntry* next = entries->next;
free(entries);
entries = next;
}
}
// 获取文件系统统计信息
void getFilesystemStats(FileSystem* fs, FilesystemStats* stats) {
if (!fs || !stats) return;
strncpy(stats->name, fs->superBlock.name, sizeof(stats->name) - 1);
stats->totalBlocks = fs->superBlock.totalBlocks;
stats->freeBlocks = fs->superBlock.freeBlocks;
stats->blockSize = fs->superBlock.blockSize;
stats->totalInodes = fs->superBlock.totalInodes;
stats->freeInodes = fs->superBlock.freeInodes;
}
// 创建符号链接
uint32_t createSymlink(FileSystem* fs, uint32_t dirInode, const char* name, const char* target) {
if (!fs || dirInode >= fs->superBlock.totalInodes || !name || !target) {
return 0;
}
// 检查链接名是否已存在
if (findFileInode(fs, dirInode, name) != 0) {
return 0;
}
// 分配新的inode
uint32_t newInode = allocateInode(fs);
if (newInode == 0) {
return 0;
}
// 初始化inode
Inode* inode = &fs->inodeTable[newInode];
inode->attributes.type = FT_SYMLINK;
inode->attributes.permissions = 0777; // 符号链接通常有最大权限
// 分配第一个数据块
uint32_t blockNum = allocateFileBlock(fs, inode, 0);
if (blockNum == 0) {
freeInode(fs, newInode);
return 0;
}
// 保存目标路径
uint32_t targetLen = strlen(target);
if (targetLen > BLOCK_SIZE - 1) {
targetLen = BLOCK_SIZE - 1;
}
memcpy(fs->blocks[blockNum].data, target, targetLen);
fs->blocks[blockNum].data[targetLen] = '';
// 更新符号链接inode
inode->attributes.size = targetLen;
// 添加到目录
if (!addDirectoryEntry(fs, dirInode, newInode, name, FT_SYMLINK)) {
freeInode(fs, newInode);
return 0;
}
return newInode;
}
// 读取符号链接目标
char* readSymlink(FileSystem* fs, uint32_t inodeNum, char* buffer, uint32_t bufSize) {
if (!fs || inodeNum >= fs->superBlock.totalInodes || !buffer || bufSize == 0) {
return NULL;
}
Inode* inode = &fs->inodeTable[inodeNum];
if (!inode->allocated || inode->attributes.type != FT_SYMLINK) {
return NULL;
}
// 获取链接目标块
uint32_t blockNum = findBlock(fs, inode, 0);
if (blockNum == 0) {
return NULL;
}
// 复制目标路径
uint32_t targetLen = inode->attributes.size;
if (targetLen >= bufSize) {
targetLen = bufSize - 1;
}
memcpy(buffer, fs->blocks[blockNum].data, targetLen);
buffer[targetLen] = '';
return buffer;
}
// 改变文件权限
bool changeFilePermissions(FileSystem* fs, const char* path, uint16_t permissions) {
if (!fs || !path) {
return false;
}
uint32_t inodeNum = resolvePath(fs, path, currentDirectoryInode);
if (inodeNum == 0) {
return false;
}
// 更新权限
Inode* inode = &fs->inodeTable[inodeNum];
inode->attributes.permissions = permissions;
inode->attributes.modificationTime = time(NULL);
return true;
}
// 清理文件系统资源
void cleanupFileSystem(FileSystem* fs) {
if (!fs) return;
// 如果已挂载,先卸载
if (fs->mounted) {
unmountFileSystem(fs);
}
// 释放各种资源
free(fs->blocks);
free(fs->inodeTable);
free(fs->inodeBitmap);
free(fs->blockBitmap);
free(fs);
}
// 文件系统摘要
void printFilesystemSummary(FileSystem* fs) {
if (!fs) return;
printf("
文件系统摘要: %s
", fs->superBlock.name);
printf("--------------------------
");
printf("块大小: %u 字节
", fs->superBlock.blockSize);
printf("总块数: %u (%u MB)
",
fs->superBlock.totalBlocks,
(fs->superBlock.totalBlocks * fs->superBlock.blockSize) / (1024*1024));
printf("可用块数: %u (%u MB, %.1f%%)
",
fs->superBlock.freeBlocks,
(fs->superBlock.freeBlocks * fs->superBlock.blockSize) / (1024*1024),
(float)fs->superBlock.freeBlocks / fs->superBlock.totalBlocks * 100);
printf("总inode数: %u
", fs->superBlock.totalInodes);
printf("可用inode数: %u (%.1f%%)
",
fs->superBlock.freeInodes,
(float)fs->superBlock.freeInodes / fs->superBlock.totalInodes * 100);
printf("系统区域使用块数: %u
", fs->superBlock.dataBlocksStart);
printf("根目录inode: %u
", fs->superBlock.rootInode);
printf("已挂载: %s
", fs->mounted ? "是" : "否");
if (fs->mounted) {
printf("挂载点: %s
", fs->mountPoint);
}
}
// 检查文件系统健康状况
void checkFilesystem(FileSystem* fs) {
if (!fs) return;
printf("
检查文件系统: %s
", fs->superBlock.name);
printf("--------------------------
");
bool hasErrors = false;
uint32_t inodeErrors = 0;
uint32_t blockErrors = 0;
uint32_t directoryErrors = 0;
// 1. 检查超级块
if (fs->superBlock.totalBlocks == 0 || fs->superBlock.totalInodes == 0) {
printf("错误: 超级块损坏
");
hasErrors = true;
}
// 2. 检查位图一致性
uint32_t bitmapInodeCount = 0;
for (uint32_t i = 0; i < fs->superBlock.totalInodes; i++) {
if ((fs->inodeBitmap[i / 8] & (1 << (i % 8))) != 0) {
bitmapInodeCount++;
}
}
if (bitmapInodeCount != (fs->superBlock.totalInodes - fs->superBlock.freeInodes)) {
printf("错误: inode位图计数不一致
");
printf(" 位图中标记使用: %u
", bitmapInodeCount);
printf(" 超级块中已使用: %u
", fs->superBlock.totalInodes - fs->superBlock.freeInodes);
hasErrors = true;
inodeErrors++;
}
uint32_t bitmapBlockCount = 0;
for (uint32_t i = 0; i < fs->superBlock.totalBlocks; i++) {
if ((fs->blockBitmap[i / 8] & (1 << (i % 8))) != 0) {
bitmapBlockCount++;
}
}
if (bitmapBlockCount != (fs->superBlock.totalBlocks - fs->superBlock.freeBlocks)) {
printf("错误: 块位图计数不一致
");
printf(" 位图中标记使用: %u
", bitmapBlockCount);
printf(" 超级块中已使用: %u
", fs->superBlock.totalBlocks - fs->superBlock.freeBlocks);
hasErrors = true;
blockErrors++;
}
// 3. 检查根目录是否有效
if (fs->superBlock.rootInode >= fs->superBlock.totalInodes ||
!fs->inodeTable[fs->superBlock.rootInode].allocated ||
fs->inodeTable[fs->superBlock.rootInode].attributes.type != FT_DIRECTORY) {
printf("严重错误: 根目录无效
");
hasErrors = true;
directoryErrors++;
}
// 4. 简单的目录一致性检查
for (uint32_t i = 0; i < fs->superBlock.totalInodes; i++) {
if (!fs->inodeTable[i].allocated) continue;
Inode* inode = &fs->inodeTable[i];
if (inode->attributes.type != FT_DIRECTORY) continue;
// 检查"."和".."条目
DirEntry* entries = readDirectoryEntries(fs, i);
bool hasDot = false;
bool hasDotDot = false;
DirEntry* current = entries;
while (current) {
if (strcmp(current->name, ".") == 0) hasDot = true;
if (strcmp(current->name, "..") == 0) hasDotDot = true;
current = current->next;
}
if (!hasDot || !hasDotDot) {
printf("错误: 目录inode %u 缺少 . 或 .. 条目
", i);
hasErrors = true;
directoryErrors++;
}
// 释放内存
while (entries) {
DirEntry* next = entries->next;
free(entries);
entries = next;
}
}
if (hasErrors) {
printf("
文件系统检查结果: 发现错误
");
printf(" inode错误: %u
", inodeErrors);
printf(" 块错误: %u
", blockErrors);
printf(" 目录错误: %u
", directoryErrors);
printf("建议进行修复
");
} else {
printf("
文件系统检查结果: 无错误
");
printf("文件系统看起来状态良好
");
}
}
// 将文件系统保存到磁盘
bool saveFilesystem(FileSystem* fs, const char* filename) {
if (!fs || !filename) {
return false;
}
FILE* file = fopen(filename, "wb");
if (!file) {
printf("错误: 无法创建文件 %s
", filename);
return false;
}
// 写入超级块
if (fwrite(&fs->superBlock, sizeof(SuperBlock), 1, file) != 1) {
printf("错误: 写入超级块失败
");
fclose(file);
return false;
}
// 计算位图大小
uint32_t inodeBitmapSize = (fs->superBlock.totalInodes + 7) / 8;
uint32_t blockBitmapSize = (fs->superBlock.totalBlocks + 7) / 8;
// 写入位图
if (fwrite(fs->inodeBitmap, 1, inodeBitmapSize, file) != inodeBitmapSize ||
fwrite(fs->blockBitmap, 1, blockBitmapSize, file) != blockBitmapSize) {
printf("错误: 写入位图失败
");
fclose(file);
return false;
}
// 写入inode表
if (fwrite(fs->inodeTable, sizeof(Inode), fs->superBlock.totalInodes, file) != fs->superBlock.totalInodes) {
printf("错误: 写入inode表失败
");
fclose(file);
return false;
}
// 写入块数据
if (fwrite(fs->blocks, sizeof(Disk_Block), fs->superBlock.totalBlocks, file) != fs->superBlock.totalBlocks) {
printf("错误: 写入块数据失败
");
fclose(file);
return false;
}
fclose(file);
printf("文件系统已保存到 %s
", filename);
return true;
}
// 从磁盘加载文件系统
FileSystem* loadFilesystem(const char* filename) {
if (!filename) {
return NULL;
}
FILE* file = fopen(filename, "rb");
if (!file) {
printf("错误: 无法打开文件 %s
", filename);
return NULL;
}
// 创建文件系统结构
FileSystem* fs = (FileSystem*)malloc(sizeof(FileSystem));
if (!fs) {
printf("错误: 内存分配失败
");
fclose(file);
return NULL;
}
// 读取超级块
if (fread(&fs->superBlock, sizeof(SuperBlock), 1, file) != 1) {
printf("错误: 读取超级块失败
");
free(fs);
fclose(file);
return NULL;
}
// 分配内存
fs->blocks = (Disk_Block*)malloc(fs->superBlock.totalBlocks * sizeof(Disk_Block));
fs->inodeTable = (Inode*)malloc(fs->superBlock.totalInodes * sizeof(Inode));
uint32_t inodeBitmapSize = (fs->superBlock.totalInodes + 7) / 8;
uint32_t blockBitmapSize = (fs->superBlock.totalBlocks + 7) / 8;
fs->inodeBitmap = (uint8_t*)malloc(inodeBitmapSize);
fs->blockBitmap = (uint8_t*)malloc(blockBitmapSize);
if (!fs->blocks || !fs->inodeTable || !fs->inodeBitmap || !fs->blockBitmap) {
printf("错误: 内存分配失败
");
if (fs->blocks) free(fs->blocks);
if (fs->inodeTable) free(fs->inodeTable);
if (fs->inodeBitmap) free(fs->inodeBitmap);
if (fs->blockBitmap) free(fs->blockBitmap);
free(fs);
fclose(file);
return NULL;
}
// 读取位图
if (fread(fs->inodeBitmap, 1, inodeBitmapSize, file) != inodeBitmapSize ||
fread(fs->blockBitmap, 1, blockBitmapSize, file) != blockBitmapSize) {
printf("错误: 读取位图失败
");
cleanupFileSystem(fs);
fclose(file);
return NULL;
}
// 读取inode表
if (fread(fs->inodeTable, sizeof(Inode), fs->superBlock.totalInodes, file) != fs->superBlock.totalInodes) {
printf("错误: 读取inode表失败
");
cleanupFileSystem(fs);
fclose(file);
return NULL;
}
// 读取块数据
if (fread(fs->blocks, sizeof(Disk_Block), fs->superBlock.totalBlocks, file) != fs->superBlock.totalBlocks) {
printf("错误: 读取块数据失败
");
cleanupFileSystem(fs);
fclose(file);
return NULL;
}
fclose(file);
// 设置未挂载状态
fs->mounted = false;
strcpy(fs->mountPoint, "");
printf("文件系统已从 %s 加载
", filename);
return fs;
}
// 实现简单的备份功能
bool backupFileSystem(FileSystem* fs, const char* backupFilename) {
if (!fs || !backupFilename) {
return false;
}
printf("备份文件系统到 %s
", backupFilename);
// 保存文件系统即可实现备份
return saveFilesystem(fs, backupFilename);
}
// 恢复备份
FileSystem* restoreFileSystem(const char* backupFilename) {
if (!backupFilename) {
return NULL;
}
printf("从 %s 恢复文件系统
", backupFilename);
// 加载文件系统即可恢复备份
return loadFilesystem(backupFilename);
}
// 实用函数:获取文件类型名称
const char* getFileTypeName(FileType type) {
switch(type) {
case FT_REGULAR: return "普通文件";
case FT_DIRECTORY: return "目录";
case FT_SYMLINK: return "符号链接";
case FT_DEVICE: return "设备文件";
case FT_PIPE: return "命名管道";
case FT_SOCKET: return "套接字";
default: return "未知类型";
}
}
// 打印inode详细信息
void printInodeDetails(FileSystem* fs, uint32_t inodeNum) {
if (!fs || inodeNum >= fs->superBlock.totalInodes) {
printf("错误: 无效的inode编号
");
return;
}
Inode* inode = &fs->inodeTable[inodeNum];
if (!inode->allocated) {
printf("Inode %u 未分配
", inodeNum);
return;
}
printf("
Inode %u 详细信息:
", inodeNum);
printf("--------------------------
");
printf("类型: %s
", getFileTypeName(inode->attributes.type));
// 格式化权限
char perms[10];
formatPermissions(inode->attributes.permissions, perms);
printf("权限: %s (0%o)
", perms, inode->attributes.permissions);
printf("大小: %u 字节
", inode->attributes.size);
printf("块数: %u
", inode->attributes.blockCount);
// 格式化时间
char timeBuffer[20];
formatTime(inode->attributes.creationTime, timeBuffer);
printf("创建时间: %s
", timeBuffer);
formatTime(inode->attributes.modificationTime, timeBuffer);
printf("修改时间: %s
", timeBuffer);
formatTime(inode->attributes.accessTime, timeBuffer);
printf("访问时间: %s
", timeBuffer);
// 列出块映射
printf("
块映射:
");
// 直接块
printf("直接块:
");
for (int i = 0; i < DIRECT_BLOCKS; i++) {
if (inode->directBlocks[i] != 0) {
printf(" [%2d]: %u
", i, inode->directBlocks[i]);
}
}
// 一级间接块
if (inode->indirectBlock != 0) {
printf("
一级间接块: %u
", inode->indirectBlock);
uint32_t* indirectTable = (uint32_t*)fs->blocks[inode->indirectBlock].data;
for (uint32_t i = 0; i < BLOCK_SIZE / sizeof(uint32_t); i++) {
if (indirectTable[i] != 0) {
printf(" [%3u]: %u
", i, indirectTable[i]);
}
}
}
// 二级间接块
if (inode->doubleIndirectBlock != 0) {
printf("
二级间接块: %u
", inode->doubleIndirectBlock);
uint32_t* doubleIndirectTable = (uint32_t*)fs->blocks[inode->doubleIndirectBlock].data;
for (uint32_t i = 0; i < BLOCK_SIZE / sizeof(uint32_t); i++) {
if (doubleIndirectTable[i] != 0) {
printf(" [%3u]: 一级间接块 %u
", i, doubleIndirectTable[i]);
// 可以选择性地显示二级指向的块
/*
uint32_t* indirectTable = (uint32_t*)fs->blocks[doubleIndirectTable[i]].data;
for (uint32_t j = 0; j < BLOCK_SIZE / sizeof(uint32_t); j++) {
if (indirectTable[j] != 0) {
printf(" [%3u,%3u]: %u
", i, j, indirectTable[j]);
}
}
*/
}
}
}
}
// 查找占用空间最大的文件
void findLargestFiles(FileSystem* fs, uint32_t startDir, int count) {
if (!fs || startDir >= fs->superBlock.totalInodes || count <= 0) {
return;
}
// 创建大文件数组
typedef struct {
uint32_t inode;
uint32_t size;
char path[256];
} LargeFile;
LargeFile* largeFiles = (LargeFile*)calloc(count, sizeof(LargeFile));
if (!largeFiles) {
printf("错误: 内存分配失败
");
return;
}
// 递归函数来遍历目录树
void traverseDir(uint32_t dirInode, const char* currentPath) {
DirEntry* entries = readDirectoryEntries(fs, dirInode);
DirEntry* current = entries;
while (current) {
// 跳过"."和".."
if (strcmp(current->name, ".") != 0 && strcmp(current->name, "..") != 0) {
Inode* inode = &fs->inodeTable[current->inode];
// 构建当前项的路径
char path[256];
if (strcmp(currentPath, "/") == 0) {
sprintf(path, "/%s", current->name);
} else {
sprintf(path, "%s/%s", currentPath, current->name);
}
// 如果是普通文件,检查其大小
if (current->type == FT_REGULAR) {
// 查找该文件是否应该在大文件列表中
for (int i = 0; i < count; i++) {
if (inode->attributes.size > largeFiles[i].size) {
// 向下移动列表中的项
for (int j = count - 1; j > i; j--) {
largeFiles[j] = largeFiles[j-1];
}
// 插入新文件
largeFiles[i].inode = current->inode;
largeFiles[i].size = inode->attributes.size;
strncpy(largeFiles[i].path, path, sizeof(largeFiles[i].path) - 1);
break;
}
}
}
// 如果是目录,递归遍历
if (current->type == FT_DIRECTORY) {
traverseDir(current->inode, path);
}
}
current = current->next;
}
// 释放内存
while (entries) {
DirEntry* next = entries->next;
free(entries);
entries = next;
}
}
// 开始遍历
traverseDir(startDir, "/");
// 显示结果
printf("
最大的 %d 个文件:
", count);
printf("%-10s %-12s %s
", "大小(KB)", "Inode", "路径");
printf("---------------------------------------
");
for (int i = 0; i < count; i++) {
if (largeFiles[i].size > 0) {
printf("%-10u %-12u %s
",
largeFiles[i].size / 1024,
largeFiles[i].inode,
largeFiles[i].path);
}
}
free(largeFiles);
}
// 查找最近修改的文件
void findRecentlyModifiedFiles(FileSystem* fs, uint32_t startDir, int count) {
if (!fs || startDir >= fs->superBlock.totalInodes || count <= 0) {
return;
}
// 创建最近修改文件数组
typedef struct {
uint32_t inode;
time_t modTime;
char path[256];
} RecentFile;
RecentFile* recentFiles = (RecentFile*)calloc(count, sizeof(RecentFile));
if (!recentFiles) {
printf("错误: 内存分配失败
");
return;
}
// 递归函数来遍历目录树
void traverseDir(uint32_t dirInode, const char* currentPath) {
DirEntry* entries = readDirectoryEntries(fs, dirInode);
DirEntry* current = entries;
while (current) {
// 跳过"."和".."
if (strcmp(current->name, ".") != 0 && strcmp(current->name, "..") != 0) {
Inode* inode = &fs->inodeTable[current->inode];
// 构建当前项的路径
char path[256];
if (strcmp(currentPath, "/") == 0) {
sprintf(path, "/%s", current->name);
} else {
sprintf(path, "%s/%s", currentPath, current->name);
}
// 如果是普通文件,检查修改时间
if (current->type == FT_REGULAR) {
// 查找该文件是否应该在最近修改列表中
for (int i = 0; i < count; i++) {
if (inode->attributes.modificationTime > recentFiles[i].modTime) {
// 向下移动列表中的项
for (int j = count - 1; j > i; j--) {
recentFiles[j] = recentFiles[j-1];
}
// 插入新文件
recentFiles[i].inode = current->inode;
recentFiles[i].modTime = inode->attributes.modificationTime;
strncpy(recentFiles[i].path, path, sizeof(recentFiles[i].path) - 1);
break;
}
}
}
// 如果是目录,递归遍历
if (current->type == FT_DIRECTORY) {
traverseDir(current->inode, path);
}
}
current = current->next;
}
// 释放内存
while (entries) {
DirEntry* next = entries->next;
free(entries);
entries = next;
}
}
// 开始遍历
traverseDir(startDir, "/");
// 显示结果
printf("
最近修改的 %d 个文件:
", count);
printf("%-20s %-12s %s
", "修改时间", "Inode", "路径");
printf("-----------------------------------------------
");
for (int i = 0; i < count; i++) {
if (recentFiles[i].modTime > 0) {
char timeBuffer[20];
formatTime(recentFiles[i].modTime, timeBuffer);
printf("%-20s %-12u %s
",
timeBuffer,
recentFiles[i].inode,
recentFiles[i].path);
}
}
free(recentFiles);
}
// 复制文件
bool copyFile(FileSystem* fs, const char* sourcePath, const char* destPath) {
if (!fs || !sourcePath || !destPath) {
return false;
}
// 解析源文件路径
uint32_t sourceInode = resolvePath(fs, sourcePath, currentDirectoryInode);
if (sourceInode == 0) {
printf("错误: 源文件 '%s' 不存在
", sourcePath);
return false;
}
// 确保源文件是普通文件
if (fs->inodeTable[sourceInode].attributes.type != FT_REGULAR) {
printf("错误: '%s' 不是普通文件
", sourcePath);
return false;
}
// 解析目标路径的目录部分和文件名
char destDir[256];
char destName[256];
char* lastSlash = strrchr(destPath, '/');
if (lastSlash) {
// 复制目录部分
size_t dirLen = lastSlash - destPath;
strncpy(destDir, destPath, dirLen);
destDir[dirLen] = '';
// 文件名
strcpy(destName, lastSlash + 1);
// 处理特殊情况
if (destDir[0] == '') {
strcpy(destDir, "/");
}
} else {
// 目标在当前目录
strcpy(destDir, ".");
strcpy(destName, destPath);
}
// 解析目标目录
uint32_t destDirInode = resolvePath(fs, destDir, currentDirectoryInode);
if (destDirInode == 0) {
printf("错误: 目标目录 '%s' 不存在
", destDir);
return false;
}
// 确保目标目录是目录
if (fs->inodeTable[destDirInode].attributes.type != FT_DIRECTORY) {
printf("错误: '%s' 不是目录
", destDir);
return false;
}
// 检查目标文件是否已存在
uint32_t existingInode = findFileInode(fs, destDirInode, destName);
if (existingInode != 0) {
printf("错误: 目标文件 '%s' 已存在
", destName);
return false;
}
// 创建新文件
uint32_t newFileInode = createFile(fs, destDirInode, destName,
fs->inodeTable[sourceInode].attributes.permissions);
if (newFileInode == 0) {
printf("错误: 无法创建目标文件
");
return false;
}
// 打开源文件和目标文件
int sourceFd = openFile(fs, sourcePath, 1); // 读模式
if (sourceFd < 0) {
printf("错误: 无法打开源文件
");
return false;
}
int destFd = openFile(fs, destPath, 2); // 写模式
if (destFd < 0) {
closeFile(sourceFd);
printf("错误: 无法打开目标文件
");
return false;
}
// 复制文件内容
const uint32_t bufferSize = 4096;
char buffer[bufferSize];
int bytesRead;
bool success = true;
while ((bytesRead = readFile(fs, sourceFd, buffer, bufferSize)) > 0) {
if (writeFile(fs, destFd, buffer, bytesRead) != bytesRead) {
printf("错误: 写入文件失败
");
success = false;
break;
}
}
// 关闭文件
closeFile(sourceFd);
closeFile(destFd);
if (!success) {
// 删除失败的目标文件
deleteFile(fs, destDirInode, destName);
return false;
}
return true;
}
// 移动文件
bool moveFile(FileSystem* fs, const char* sourcePath, const char* destPath) {
if (!fs || !sourcePath || !destPath) {
return false;
}
// 解析源文件路径
uint32_t sourceInode = resolvePath(fs, sourcePath, currentDirectoryInode);
if (sourceInode == 0) {
printf("错误: 源文件 '%s' 不存在
", sourcePath);
return false;
}
// 解析源文件的目录部分和文件名
char sourceDir[256];
char sourceName[256];
char* lastSlash = strrchr(sourcePath, '/');
if (lastSlash) {
// 复制目录部分
size_t dirLen = lastSlash - sourcePath;
strncpy(sourceDir, sourcePath, dirLen);
sourceDir[dirLen] = '';
// 文件名
strcpy(sourceName, lastSlash + 1);
// 处理特殊情况
if (sourceDir[0] == '') {
strcpy(sourceDir, "/");
}
} else {
// 源在当前目录
strcpy(sourceDir, ".");
strcpy(sourceName, sourcePath);
}
// 解析源目录
uint32_t sourceDirInode = resolvePath(fs, sourceDir, currentDirectoryInode);
if (sourceDirInode == 0) {
printf("错误: 源目录 '%s' 不存在
", sourceDir);
return false;
}
// 解析目标路径的目录部分和文件名
char destDir[256];
char destName[256];
lastSlash = strrchr(destPath, '/');
if (lastSlash) {
// 复制目录部分
size_t dirLen = lastSlash - destPath;
strncpy(destDir, destPath, dirLen);
destDir[dirLen] = '';
// 文件名
strcpy(destName, lastSlash + 1);
// 处理特殊情况
if (destDir[0] == '') {
strcpy(destDir, "/");
}
} else {
// 目标在当前目录
strcpy(destDir, ".");
strcpy(destName, destPath);
}
// 解析目标目录
uint32_t destDirInode = resolvePath(fs, destDir, currentDirectoryInode);
if (destDirInode == 0) {
printf("错误: 目标目录 '%s' 不存在
", destDir);
return false;
}
// 确保目标目录是目录
if (fs->inodeTable[destDirInode].attributes.type != FT_DIRECTORY) {
printf("错误: '%s' 不是目录
", destDir);
return false;
}
// 检查目标文件是否已存在
uint32_t existingInode = findFileInode(fs, destDirInode, destName);
if (existingInode != 0) {
printf("错误: 目标文件 '%s' 已存在
", destName);
return false;
}
// 添加到目标目录
FileType fileType = fs->inodeTable[sourceInode].attributes.type;
if (!addDirectoryEntry(fs, destDirInode, sourceInode, destName, fileType)) {
printf("错误: 无法将文件添加到目标目录
");
return false;
}
// 从源目录删除
if (!removeDirectoryEntry(fs, sourceDirInode, sourceName)) {
// 回滚,从目标目录移除
removeDirectoryEntry(fs, destDirInode, destName);
printf("错误: 无法从源目录移除文件
");
return false;
}
return true;
}
// 查找文件
void findFiles(FileSystem* fs, uint32_t startDir, const char* pattern) {
if (!fs || startDir >= fs->superBlock.totalInodes || !pattern) {
return;
}
printf("
查找文件: 匹配 '%s'
", pattern);
printf("%-12s %-10s %-10s %s
", "Inode", "大小", "类型", "路径");
printf("------------------------------------------
");
// 递归函数来遍历目录树
void traverseDir(uint32_t dirInode, const char* currentPath) {
DirEntry* entries = readDirectoryEntries(fs, dirInode);
DirEntry* current = entries;
while (current) {
// 跳过"."和".."
if (strcmp(current->name, ".") != 0 && strcmp(current->name, "..") != 0) {
Inode* inode = &fs->inodeTable[current->inode];
// 构建当前项的路径
char path[256];
if (strcmp(currentPath, "/") == 0) {
sprintf(path, "/%s", current->name);
} else {
sprintf(path, "%s/%s", currentPath, current->name);
}
// 检查文件名是否匹配模式
// 这里使用简单的字符串匹配,实际系统应使用正则表达式
if (strstr(current->name, pattern)) {
printf("%-12u %-10u %-10s %s
",
current->inode,
inode->attributes.size,
getFileTypeName(current->type),
path);
}
// 如果是目录,递归遍历
if (current->type == FT_DIRECTORY) {
traverseDir(current->inode, path);
}
}
current = current->next;
}
// 释放内存
while (entries) {
DirEntry* next = entries->next;
free(entries);
entries = next;
}
}
// 开始遍历
traverseDir(startDir, "/");
}
// 模拟实用功能部分
// 显示帮助信息
void showHelp() {
printf("
文件系统模拟器帮助
");
printf("===================
");
printf("基本命令:
");
printf(" help - 显示此帮助信息
");
printf(" init <name> <size> - 初始化新文件系统 (大小单位为MB)
");
printf(" mount - 挂载文件系统
");
printf(" umount - 卸载文件系统
");
printf(" save <filename> - 保存文件系统到磁盘
");
printf(" load <filename> - 从磁盘加载文件系统
");
printf(" exit - 退出模拟器
");
printf("
文件操作命令:
");
printf(" ls [path] - 列出目录内容
");
printf(" cd <path> - 改变当前目录
");
printf(" pwd - 显示当前目录
");
printf(" mkdir <name> - 创建新目录
");
printf(" rmdir <name> - 删除目录
");
printf(" touch <name> - 创建新文件
");
printf(" rm <name> - 删除文件
");
printf(" cp <src> <dest> - 复制文件
");
printf(" mv <src> <dest> - 移动文件
");
printf(" cat <file> - 显示文件内容
");
printf(" write <file> <text> - 写入文本到文件
");
printf(" ln -s <target> <link>- 创建符号链接
");
printf(" chmod <mode> <file> - 改变文件权限
");
printf("
信息和诊断命令:
");
printf(" stat <file> - 显示文件属性
");
printf(" df - 显示文件系统使用情况
");
printf(" fsck - 检查文件系统一致性
");
printf(" inode <number> - 显示inode详细信息
");
printf(" find <pattern> - 查找匹配文件
");
printf(" du - 显示最大文件
");
printf(" recent - 显示最近修改的文件
");
printf("
示例:
");
printf(" init myfs 10 - 创建10MB文件系统
");
printf(" mkdir documents - 创建documents目录
");
printf(" cd documents - 进入documents目录
");
printf(" touch report.txt - 创建新文件
");
printf(" write report.txt 这是一个测试文件 - 写入文本
");
printf(" cat report.txt - 查看文件内容
");
}
// 模拟shell
void simulateShell(FileSystem* fs) {
char command[1024];
char *args[64];
int running = 1;
if (!fs) {
printf("错误: 未初始化的文件系统
");
return;
}
// 挂载文件系统
mountFileSystem(fs, "/");
while (running) {
printf("
%s> ", currentDirectory);
if (fgets(command, sizeof(command), stdin) == NULL) break;
// 去除换行符
size_t len = strlen(command);
if (len > 0 && command[len-1] == '
') {
command[len-1] = '';
}
// 解析命令
int argc = 0;
char *token = strtok(command, " ");
while (token && argc < 64) {
args[argc++] = token;
token = strtok(NULL, " ");
}
if (argc == 0) continue;
// 执行命令
if (strcmp(args[0], "exit") == 0) {
running = 0;
}
else if (strcmp(args[0], "help") == 0) {
showHelp();
}
else if (strcmp(args[0], "mount") == 0) {
if (!fs->mounted) {
mountFileSystem(fs, "/");
} else {
printf("文件系统已经挂载
");
}
}
else if (strcmp(args[0], "umount") == 0) {
if (fs->mounted) {
unmountFileSystem(fs);
} else {
printf("文件系统未挂载
");
}
}
else if (strcmp(args[0], "ls") == 0) {
if (argc > 1) {
listDirectory(fs, args[1]);
} else {
listDirectory(fs, NULL);
}
}
else if (strcmp(args[0], "pwd") == 0) {
printf("%s
", currentDirectory);
}
else if (strcmp(args[0], "cd") == 0) {
if (argc < 2) {
printf("用法: cd <path>
");
} else {
changeDirectory(fs, args[1]);
}
}
else if (strcmp(args[0], "mkdir") == 0) {
if (argc < 2) {
printf("用法: mkdir <name>
");
} else {
if (createDirectory(fs, currentDirectoryInode, args[1], 0755)) {
printf("目录已创建
");
} else {
printf("创建目录失败
");
}
}
}
else if (strcmp(args[0], "rmdir") == 0) {
if (argc < 2) {
printf("用法: rmdir <name>
");
} else {
if (deleteDirectory(fs, currentDirectoryInode, args[1])) {
printf("目录已删除
");
} else {
printf("删除目录失败
");
}
}
}
else if (strcmp(args[0], "touch") == 0) {
if (argc < 2) {
printf("用法: touch <name>
");
} else {
if (createFile(fs, currentDirectoryInode, args[1], 0644)) {
printf("文件已创建
");
} else {
printf("创建文件失败
");
}
}
}
else if (strcmp(args[0], "rm") == 0) {
if (argc < 2) {
printf("用法: rm <name>
");
} else {
if (deleteFile(fs, currentDirectoryInode, args[1])) {
printf("文件已删除
");
} else {
printf("删除文件失败
");
}
}
}
else if (strcmp(args[0], "cat") == 0) {
if (argc < 2) {
printf("用法: cat <file>
");
} else {
int fd = openFile(fs, args[1], 1); // 只读模式
if (fd >= 0) {
char buffer[1024];
int bytesRead;
printf("
");
while ((bytesRead = readFile(fs, fd, buffer, sizeof(buffer) - 1)) > 0) {
buffer[bytesRead] = '';
printf("%s", buffer);
}
printf("
");
closeFile(fd);
} else {
printf("无法打开文件
");
}
}
}
else if (strcmp(args[0], "write") == 0) {
if (argc < 3) {
printf("用法: write <file> <text>
");
} else {
int fd = openFile(fs, args[1], 2); // 只写模式
if (fd >= 0) {
// 组合所有剩余参数为文本
char text[1024] = "";
for (int i = 2; i < argc; i++) {
if (i > 2) strcat(text, " ");
strcat(text, args[i]);
}
if (writeFile(fs, fd, text, strlen(text)) > 0) {
printf("文件已写入
");
} else {
printf("写入文件失败
");
}
closeFile(fd);
} else {
printf("无法打开文件
");
}
}
}
else if (strcmp(args[0], "cp") == 0) {
if (argc < 3) {
printf("用法: cp <source> <destination>
");
} else {
if (copyFile(fs, args[1], args[2])) {
printf("文件已复制
");
} else {
printf("复制文件失败
");
}
}
}
else if (strcmp(args[0], "mv") == 0) {
if (argc < 3) {
printf("用法: mv <source> <destination>
");
} else {
if (moveFile(fs, args[1], args[2])) {
printf("文件已移动
");
} else {
printf("移动文件失败
");
}
}
}
else if (strcmp(args[0], "ln") == 0) {
if (argc < 4 || strcmp(args[1], "-s") != 0) {
printf("用法: ln -s <target> <link>
");
} else {
if (createSymlink(fs, currentDirectoryInode, args[3], args[2])) {
printf("符号链接已创建
");
} else {
printf("创建符号链接失败
");
}
}
}
else if (strcmp(args[0], "chmod") == 0) {
if (argc < 3) {
printf("用法: chmod <mode> <file>
");
} else {
uint16_t mode = 0;
if (sscanf(args[1], "%ho", &mode) == 1) {
if (changeFilePermissions(fs, args[2], mode)) {
printf("文件权限已修改
");
} else {
printf("修改文件权限失败
");
}
} else {
printf("无效的权限模式
");
}
}
}
else if (strcmp(args[0], "stat") == 0) {
if (argc < 2) {
printf("用法: stat <file>
");
} else {
FileAttributes attr;
if (statFile(fs, args[1], &attr)) {
printf("
文件信息: %s
", args[1]);
printf("--------------------------
");
printf("Inode: %u
", attr.inode);
printf("类型: %s
", getFileTypeName(attr.type));
char perms[10];
formatPermissions(attr.permissions, perms);
printf("权限: %s (0%o)
", perms, attr.permissions);
printf("大小: %u 字节
", attr.size);
printf("块数: %u
", attr.blockCount);
char timeBuffer[20];
formatTime(attr.creationTime, timeBuffer);
printf("创建时间: %s
", timeBuffer);
formatTime(attr.modificationTime, timeBuffer);
printf("修改时间: %s
", timeBuffer);
formatTime(attr.accessTime, timeBuffer);
printf("访问时间: %s
", timeBuffer);
} else {
printf("获取文件信息失败
");
}
}
}
else if (strcmp(args[0], "df") == 0) {
FilesystemStats stats;
getFilesystemStats(fs, &stats);
printf("
文件系统使用情况: %s
", stats.name);
printf("--------------------------
");
printf("总大小: %u MB
", (stats.totalBlocks * stats.blockSize) / (1024*1024));
printf("已用空间: %u MB (%.1f%%)
",
((stats.totalBlocks - stats.freeBlocks) * stats.blockSize) / (1024*1024),
(float)(stats.totalBlocks - stats.freeBlocks) / stats.totalBlocks * 100);
printf("可用空间: %u MB (%.1f%%)
",
(stats.freeBlocks * stats.blockSize) / (1024*1024),
(float)stats.freeBlocks / stats.totalBlocks * 100);
printf("总inode数: %u
", stats.totalInodes);
printf("已用inode数: %u (%.1f%%)
",
stats.totalInodes - stats.freeInodes,
(float)(stats.totalInodes - stats.freeInodes) / stats.totalInodes * 100);
printf("可用inode数: %u (%.1f%%)
",
stats.freeInodes,
(float)stats.freeInodes / stats.totalInodes * 100);
}
else if (strcmp(args[0], "fsck") == 0) {
checkFilesystem(fs);
}
else if (strcmp(args[0], "inode") == 0) {
if (argc < 2) {
printf("用法: inode <number>
");
} else {
uint32_t inodeNum = 0;
if (sscanf(args[1], "%u", &inodeNum) == 1) {
printInodeDetails(fs, inodeNum);
} else {
printf("无效的inode编号
");
}
}
}
else if (strcmp(args[0], "find") == 0) {
if (argc < 2) {
printf("用法: find <pattern>
");
} else {
findFiles(fs, fs->superBlock.rootInode, args[1]);
}
}
else if (strcmp(args[0], "du") == 0) {
findLargestFiles(fs, fs->superBlock.rootInode, 10);
}
else if (strcmp(args[0], "recent") == 0) {
findRecentlyModifiedFiles(fs, fs->superBlock.rootInode, 10);
}
else if (strcmp(args[0], "save") == 0) {
if (argc < 2) {
printf("用法: save <filename>
");
} else {
if (saveFilesystem(fs, args[1])) {
printf("文件系统已保存到 %s
", args[1]);
} else {
printf("保存文件系统失败
");
}
}
}
else if (strcmp(args[0], "load") == 0) {
if (argc < 2) {
printf("用法: load <filename>
");
} else {
FileSystem* loadedFs = loadFilesystem(args[1]);
if (loadedFs) {
// 卸载当前文件系统
if (fs->mounted) {
unmountFileSystem(fs);
}
cleanupFileSystem(fs);
// 替换为加载的文件系统
fs = loadedFs;
activeFS = fs;
// 挂载加载的文件系统
mountFileSystem(fs, "/");
printf("文件系统已从 %s 加载
", args[1]);
} else {
printf("加载文件系统失败
");
}
}
}
else if (strcmp(args[0], "init") == 0) {
if (argc < 3) {
printf("用法: init <name> <size>
");
} else {
uint32_t size = 0;
if (sscanf(args[2], "%u", &size) == 1 && size > 0) {
// 卸载当前文件系统
if (fs->mounted) {
unmountFileSystem(fs);
}
cleanupFileSystem(fs);
// 创建新的文件系统
fs = initFileSystem(args[1], size);
activeFS = fs;
// 挂载新的文件系统
mountFileSystem(fs, "/");
} else {
printf("无效的大小参数
");
}
}
}
else {
printf("未知命令: %s
", args[0]);
}
}
}
// 演示函数:文件系统基础演示
void demonstrateFileSystemBasics() {
printf("
===== 文件系统基础演示 =====
");
// 创建文件系统
FileSystem* fs = initFileSystem("DemoFS", 10); // 10MB
// 挂载文件系统
mountFileSystem(fs, "/");
// 创建几个目录
printf("
创建目录结构:
");
createDirectory(fs, currentDirectoryInode, "documents", 0755);
createDirectory(fs, currentDirectoryInode, "pictures", 0755);
createDirectory(fs, currentDirectoryInode, "downloads", 0755);
// 切换到documents目录
changeDirectory(fs, "/documents");
// 创建几个文件
printf("
创建文件:
");
uint32_t fileInode1 = createFile(fs, currentDirectoryInode, "report.txt", 0644);
uint32_t fileInode2 = createFile(fs, currentDirectoryInode, "notes.txt", 0644);
// 打开并写入文件
int fd1 = openFile(fs, "report.txt", 2); // 只写模式
const char* content1 = "这是一份报告文件,内容很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长。
"
"第二行内容也很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长。";
writeFile(fs, fd1, content1, strlen(content1));
closeFile(fd1);
int fd2 = openFile(fs, "notes.txt", 2); // 只写模式
const char* content2 = "这是一个简单的笔记文件。";
writeFile(fs, fd2, content2, strlen(content2));
closeFile(fd2);
// 列出目录内容
printf("
当前目录内容:
");
listDirectory(fs, NULL);
// 返回根目录
changeDirectory(fs, "/");
// 创建一个符号链接
createSymlink(fs, currentDirectoryInode, "doc_link", "/documents");
// 查看文件状态
FileAttributes attr;
statFile(fs, "/documents/report.txt", &attr);
printf("
文件状态:
");
printf("文件: /documents/report.txt
");
printf("大小: %u 字节
", attr.size);
printf("块数: %u
", attr.blockCount);
// 打开并读取文件
fd1 = openFile(fs, "/documents/report.txt", 1); // 只读模式
char buffer[256];
int bytesRead = readFile(fs, fd1, buffer, 255);
buffer[bytesRead] = '';
printf("
文件内容 (前255字节):
%s
", buffer);
closeFile(fd1);
// 移动文件
moveFile(fs, "/documents/notes.txt", "/notes.txt");
printf("
移动文件后的根目录内容:
");
listDirectory(fs, "/");
// 复制文件
copyFile(fs, "/documents/report.txt", "/report_copy.txt");
// 查看根目录
printf("
复制文件后的根目录内容:
");
listDirectory(fs, "/");
// 查看文件系统统计信息
FilesystemStats stats;
getFilesystemStats(fs, &stats);
printf("
文件系统统计信息:
");
printf("总大小: %u MB
", (stats.totalBlocks * stats.blockSize) / (1024*1024));
printf("已用空间: %u KB
", ((stats.totalBlocks - stats.freeBlocks) * stats.blockSize) / 1024);
printf("可用空间: %u MB
", (stats.freeBlocks * stats.blockSize) / (1024*1024));
// 卸载文件系统
unmountFileSystem(fs);
// 清理资源
cleanupFileSystem(fs);
printf("
演示完成
");
}
// 演示函数:交互式文件系统shell
void demonstrateFileSystemShell() {
printf("
===== 文件系统交互式Shell =====
");
printf("创建新的文件系统 (10MB)...
");
// 创建文件系统
FileSystem* fs = initFileSystem("ShellFS", 10); // 10MB
// 运行shell
simulateShell(fs);
// 清理资源
cleanupFileSystem(fs);
}
// 主函数
int main() {
printf("32位微处理器文件系统模拟
");
printf("=====================
");
printf("本程序演示32位微处理器支持的文件系统基本功能,包括:
");
printf("- 文件和目录的创建、删除和修改
");
printf("- 符号链接
");
printf("- 文件权限和属性
");
printf("- 文件读写操作
");
printf("- 文件系统挂载和卸载
");
printf("- 基本的文件系统管理功能
");
// 初始化全局文件描述符表
for (int i = 0; i < MAX_OPEN_FILES; i++) {
openFiles[i].inUse = false;
}
int choice;
do {
printf("选择演示模式:
");
printf("1. 文件系统基础演示
");
printf("2. 交互式文件系统Shell
");
printf("0. 退出
");
printf("请输入选择 [0-2]: ");
scanf("%d", &choice);
getchar(); // 消耗换行符
switch(choice) {
case 1:
demonstrateFileSystemBasics();
break;
case 2:
demonstrateFileSystemShell();
break;
case 0:
printf("退出程序
");
break;
default:
printf("无效选择,请重试
");
}
} while (choice != 0);
return 0;
}
32位微处理器的文件系统支持
文件系统是操作系统中负责管理持久性数据的核心子系统,负责组织、存储、检索以及控制对数据的访问。32位微处理器通过提供各种硬件特性和架构支持,为操作系统实现高效、可靠的文件系统提供了坚实的基础。
1. 文件系统概述
文件系统的基本功能
文件系统提供了一组关键功能,使得应用程序和用户能够方便地管理数据:
数据存储与组织:将数据以文件形式组织在存储介质上命名空间管理:提供命名和目录结构,帮助用户组织文件数据访问控制:实现权限和安全机制,控制对数据的访问元数据管理:维护文件属性、大小、创建和修改时间等信息数据完整性保证:通过日志、检查点等机制确保文件系统的一致性
文件系统组成部分
一个典型的文件系统通常包含以下组成部分:
超级块(Superblock):包含文件系统的全局信息,如大小、块大小、inode数量等inode表:存储文件和目录的元数据信息位图或空闲列表:用于跟踪可用的inode和数据块目录结构:将文件名映射到inode号数据区域:存储文件内容的实际数据块
2. 32位微处理器对文件系统的硬件支持
32位微处理器架构通过以下几个方面为文件系统提供关键支持:
地址空间支持
4GB地址空间:32位处理器提供了高达4GB的寻址能力,能够处理大型文件系统和大文件内存映射文件:支持将文件内容直接映射到进程的地址空间,提高I/O效率分页机制:通过虚拟内存支持,使文件系统能够高效处理超出物理内存的数据
I/O接口支持
I/O端口和内存映射I/O:为文件系统提供与存储设备交互的基础接口中断和DMA支持:允许高效的异步I/O操作,减少CPU在I/O操作中的介入高速缓存机制:片上和外部缓存提高了文件系统数据访问性能
保护机制
特权级别:通过用户模式和内核模式隔离,保护文件系统免受恶意代码影响内存保护:防止未授权的内存访问,确保文件系统数据安全指令集支持:提供原子操作和同步指令,用于实现文件系统的并发控制
3. 文件系统数据结构
inode结构
inode是文件系统的核心数据结构,存储了文件的元数据信息:
c
typedef struct {
uint32_t id; // inode编号
FileType type; // 文件类型(普通文件/目录/链接等)
uint32_t size; // 文件大小(字节)
uint32_t blockCount; // 占用块数量
uint16_t permissions; // 权限 (rwx)
uint32_t owner; // 所有者ID
uint32_t group; // 所属组ID
time_t creationTime; // 创建时间
time_t modificationTime; // 修改时间
time_t accessTime; // 访问时间
uint32_t directBlocks[12]; // 直接块指针
uint32_t indirectBlock; // 一级间接块指针
uint32_t doubleIndirectBlock; // 二级间接块指针
uint32_t tripleIndirectBlock; // 三级间接块指针(高级文件系统)
} Inode;
inode的地址索引机制使文件系统能够高效支持从小文件到大型文件的各种规模:
直接块:直接指向数据块,适合小文件间接块:指向包含数据块指针的块,扩展文件大小多级间接块:提供更多层次的间接引用,支持更大的文件
目录结构
目录作为特殊类型的文件,存储文件名和对应的inode号的映射:
c
typedef struct DirEntry {
uint32_t inode; // inode号
char name[256]; // 文件名
FileType type; // 文件类型
struct DirEntry* next; // 链表下一个项
} DirEntry;
文件描述符
操作系统使用文件描述符管理已打开的文件:
c
typedef struct {
uint32_t inode; // 关联的inode
uint32_t position; // 当前文件位置
uint16_t flags; // 打开标志(读/写/追加等)
bool inUse; // 是否在使用
} FileDescriptor;
4. 文件系统操作
基本文件操作
32位处理器支持的典型文件系统操作包括:
文件创建与删除
创建inode并分配数据块在目录中添加或删除条目更新元数据和位图
文件读写
通过缓冲区进行数据传输利用处理器缓存和虚拟内存机制优化性能支持随机访问和顺序访问
目录管理
创建和删除目录列出目录内容遍历目录树
高级文件系统功能
文件映射
将文件内容映射到进程地址空间利用处理器的分页机制实现
符号链接和硬链接
符号链接:存储目标路径的特殊文件硬链接:指向同一inode的多个目录项
缓存和预读
利用处理器缓存层次结构预测性读取提高访问速度
日志和事务
确保文件系统操作的原子性提高崩溃后的恢复速度
5. 不同文件系统的实现比较
32位处理器环境下常见的文件系统及其特点:
Linux文件系统
ext2/ext3/ext4
标准Linux文件系统ext3/ext4增加了日志功能ext4支持更大的文件和文件系统
XFS
高性能64位日志文件系统适合大型文件系统和高吞吐量场景
Btrfs
支持写时复制(CoW)、快照和校验和高级数据完整性功能
Windows文件系统
FAT32
简单的文件分配表文件系统32位文件系统限制单个文件最大为4GB广泛兼容性
NTFS
Windows的高级文件系统支持权限、加密、压缩和日志支持大文件和大卷
特殊文件系统
tmpfs/ramfs
内存文件系统,利用32位处理器的虚拟内存管理用于临时存储和高速访问
NFS/CIFS
网络文件系统,利用32位处理器的网络功能允许跨网络透明访问文件
6. 32位架构的文件系统限制与优化
架构限制
4GB寻址限制
影响单个文件和文件系统的最大大小需要特殊技术处理大型文件
缓存大小限制
文件系统缓存受物理内存和地址空间限制影响I/O性能和吞吐量
性能优化技术
块分配策略
连续分配减少寻道时间考虑处理器缓存行和TLB特性
内存映射优化
利用处理器的分页和TLB大页面支持提高缓存效率
异步I/O和预读
利用DMA和中断减少CPU负担根据访问模式预测性加载数据
多线程文件系统操作
利用多核32位处理器并行处理元数据和数据操作
7. 文件系统安全与保护
32位处理器提供的安全机制如何应用于文件系统:
访问控制
文件权限模型
所有者/组/其他人权限模型基于处理器特权级保护实现
访问控制列表(ACL)
更精细的权限控制利用处理器保护机制实施
数据完整性
校验和
检测数据损坏利用处理器的CRC指令加速
加密文件系统
利用处理器加密指令保护数据免受未授权访问
8. 未来发展趋势
尽管64位处理器越来越普及,32位架构在文件系统领域仍有重要地位:
嵌入式和IoT设备
资源受限环境中使用轻量级文件系统32位处理器仍是主流
兼容性层
为32位应用提供文件系统访问在64位系统中模拟32位行为
混合架构系统
32位和64位文件系统共存利用各自优势处理不同工作负载
总结
32位微处理器通过其地址空间管理、I/O接口和保护机制为文件系统提供了全面支持,使操作系统能够实现高效、安全的数据管理功能。尽管存在一些固有限制,但通过各种优化技术,32位架构仍然能够支持丰富的文件系统功能,满足各种应用场景的需求。随着嵌入式系统和物联网的发展,32位处理器的文件系统支持仍将发挥重要作用,同时与64位架构形成互补。


















暂无评论内容