├── 文件系统.exe ├── 文件系统 ├── test.cpp ├── filesystem.h ├── 文件系统.vcxproj.user ├── 文件系统.vcxproj.filters ├── 文件系统.sln ├── 文件系统.vcxproj ├── main.cpp └── filesystem.cpp ├── README.assets ├── clip_image002.jpg ├── clip_image002.png ├── image-20230518220538055.png ├── image-20230518221151506.png ├── clip_image002-168441891836914.jpg ├── clip_image002-168441892612816.jpg ├── clip_image002-168441895017718.jpg ├── clip_image002-168441899377320.jpg ├── clip_image002-168441900522822.jpg ├── clip_image002-168441902614524.jpg └── clip_image002-168441904106026.jpg ├── LICENSE └── README.md /文件系统.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lingbai-kong/file-system/HEAD/文件系统.exe -------------------------------------------------------------------------------- /文件系统/test.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lingbai-kong/file-system/HEAD/文件系统/test.cpp -------------------------------------------------------------------------------- /文件系统/filesystem.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lingbai-kong/file-system/HEAD/文件系统/filesystem.h -------------------------------------------------------------------------------- /README.assets/clip_image002.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lingbai-kong/file-system/HEAD/README.assets/clip_image002.jpg -------------------------------------------------------------------------------- /README.assets/clip_image002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lingbai-kong/file-system/HEAD/README.assets/clip_image002.png -------------------------------------------------------------------------------- /README.assets/image-20230518220538055.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lingbai-kong/file-system/HEAD/README.assets/image-20230518220538055.png -------------------------------------------------------------------------------- /README.assets/image-20230518221151506.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lingbai-kong/file-system/HEAD/README.assets/image-20230518221151506.png -------------------------------------------------------------------------------- /README.assets/clip_image002-168441891836914.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lingbai-kong/file-system/HEAD/README.assets/clip_image002-168441891836914.jpg -------------------------------------------------------------------------------- /README.assets/clip_image002-168441892612816.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lingbai-kong/file-system/HEAD/README.assets/clip_image002-168441892612816.jpg -------------------------------------------------------------------------------- /README.assets/clip_image002-168441895017718.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lingbai-kong/file-system/HEAD/README.assets/clip_image002-168441895017718.jpg -------------------------------------------------------------------------------- /README.assets/clip_image002-168441899377320.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lingbai-kong/file-system/HEAD/README.assets/clip_image002-168441899377320.jpg -------------------------------------------------------------------------------- /README.assets/clip_image002-168441900522822.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lingbai-kong/file-system/HEAD/README.assets/clip_image002-168441900522822.jpg -------------------------------------------------------------------------------- /README.assets/clip_image002-168441902614524.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lingbai-kong/file-system/HEAD/README.assets/clip_image002-168441902614524.jpg -------------------------------------------------------------------------------- /README.assets/clip_image002-168441904106026.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lingbai-kong/file-system/HEAD/README.assets/clip_image002-168441904106026.jpg -------------------------------------------------------------------------------- /文件系统/文件系统.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Lingbai Kong 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /文件系统/文件系统.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 源文件 20 | 21 | 22 | 源文件 23 | 24 | 25 | 26 | 27 | 头文件 28 | 29 | 30 | -------------------------------------------------------------------------------- /文件系统/文件系统.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29806.167 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "文件系统", "文件系统.vcxproj", "{1C53CD6A-5F7C-479E-9926-67746D56E762}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {1C53CD6A-5F7C-479E-9926-67746D56E762}.Debug|x64.ActiveCfg = Debug|x64 17 | {1C53CD6A-5F7C-479E-9926-67746D56E762}.Debug|x64.Build.0 = Debug|x64 18 | {1C53CD6A-5F7C-479E-9926-67746D56E762}.Debug|x86.ActiveCfg = Debug|Win32 19 | {1C53CD6A-5F7C-479E-9926-67746D56E762}.Debug|x86.Build.0 = Debug|Win32 20 | {1C53CD6A-5F7C-479E-9926-67746D56E762}.Release|x64.ActiveCfg = Release|x64 21 | {1C53CD6A-5F7C-479E-9926-67746D56E762}.Release|x64.Build.0 = Release|x64 22 | {1C53CD6A-5F7C-479E-9926-67746D56E762}.Release|x86.ActiveCfg = Release|Win32 23 | {1C53CD6A-5F7C-479E-9926-67746D56E762}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {EC78A921-B85C-4BF5-AA64-47473817097D} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # file-system 2 | 同济大学CS《操作系统》课程设计: 文件系统TongJi University CS OS assignment: file system 3 | ## 概述 4 | 5 | 本项目是为2021年同济大学计算机系操作系统课程设计。实现了类UNIX文件系统。 6 | 7 | ![img](README.assets/clip_image002.jpg) 8 | 9 | ### 功能 10 | 11 | 1. 具有高速缓存 12 | 2. 实现了多用户多用户组的管理和访问权限控制 13 | 3. 实现了一个简单的控制台编辑器,可以直接在文件系统内对文本文件进行编辑 14 | 15 | ### 快速开始 16 | 17 | 1. 打开文件系统.exe 18 | 2. 输入help命令查看可用命令 19 | 3. 输入命令login root登录系统,初始密码为root 20 | 21 | ### 重要注意事项 22 | 23 | 1. 退出程序时禁止直接关闭程序,必须使用exit命令退出文件系统,否则可能导致文件系统错误或崩溃 24 | 2. 慎重修改/etc/users.txt和/etc/groups.txt文件,这两个文件与用户管理相关,如果修改格式不当可能会导致文件系统无法登录或其他权限问题 25 | 3. 如果以上两条问题发生请尝试格式化文件系统 26 | 27 | ## 备注:star: 28 | 29 | 本学期最简单的大作业(主要是没有GUI),开发该文件系统耗时10天 30 | 31 | 如果本仓库有帮助到你,就送我一颗star吧🤗 32 | 33 | 如果有问题也可以在issue提出,方便其他人参考或一起讨论😋 34 | 35 | 仓库遵循MIT开源协议 36 | 37 | ## 设计 38 | 39 | ### 重点函数变量说明 40 | 41 | #### 文件索引相关函数中的length变量 42 | 43 | 这个变量主要用于记录当前读到的文件长度,这个变量的存在降低了文件混合索引的难度。函数不需要实现计算好该文件用了多少个索引块,也不需要实现知道文件的混合索引结构是怎样的,直接将索引文件一律看作是用满了所有索引块的达到最大大小的巨型文件。从直接索引开始遍历文件,再到一级索引,再到二级索引,当length达到了文件的大小直接退出遍历即可完成对任意大小文件的遍历。但这种方法的缺点是每一次读文件都要从文件头开始,降低了随机读写的效率。 44 | 45 | #### 编辑器显示函数start_line变量 46 | 47 | 这个变量主要用于指示编辑器从哪一行开始显示文本,当文件行数超过了控制台高度时这个变量开始生效。控制台光标在控制台中的行数映射到实际文本的行数要加上start_line这个变量。当光标移动到最下面一行时再次按下方向键下,start_line会加一实现文本在编辑器内的向下翻页,向上翻页反之亦然。 48 | 49 | #### 命令行用户界面cur_dir变量 50 | 51 | 这个变量属于命令行用户界面类,主要记录了用户处在文件系统中的路径。因为在文件系统中,所有操作接口都是以绝对路径为基准的,而用户在命令行界面下输入的命令是以cur_dir这个相对路径作为基准的。因此用户界面在使用文件系统的接口时要将cur_dir与用户输入的路径进行拼接,把绝对路径作为参数传入文静系统的接口函数。 52 | 53 | ### 模块调用关系 54 | 55 | ![image-20230518221151506](README.assets/image-20230518221151506.png) 56 | 57 | ### 函数调用关系 58 | 59 | ![image-20230518220538055](README.assets/image-20230518220538055.png) 60 | 61 | ## 用户使用说明 62 | 63 | ### 运行环境 64 | 65 | 本文件系统运行与64位Windows操作系统下,文件系统的模拟文件卷大小为128MB,请确保程序目录下有足够的可用空间。 66 | 67 | ### 重要注意事项 68 | 69 | 1. 退出程序时禁止直接关闭程序,必须使用exit命令退出文件系统,否则可能导致文件系统错误或崩溃。 70 | 71 | 2. 慎重修改/etc/users.txt和/etc/groups.txt文件,这两个文件与用户管理相关,如果修改格式不当可能会导致文件系统无法登录或其他权限问题。 72 | 73 | 如果以上两条问题发生请尝试格式化文件系统。 74 | 75 | ### 使用命令说明 76 | 77 | 未登录状态下可用命令: 78 | 79 | | 命令 | 参数 | 功能 | 80 | | ------ | ---------------- | ---------------- | 81 | | login | 用户名(字符串) | 用户登录 | 82 | | exit | | 退出系统 | 83 | | format | | 格式化文件系统 | 84 | | help | | 显示命令提示清单 | 85 | 86 | 登录状态下可用命令: 87 | 88 | | 命令 | 参数 | 功能 | 89 | | -------- | ------------------------------------------------------------ | -------------------------------------------- | 90 | | logout | | 用户注销 | 91 | | exit | | 退出系统 | 92 | | mkdir | 目录名(字符串,长度小于28字节,不能是多级目录) | 创建子目录 | 93 | | cd | 目录名(字符串,长度小于28字节,当前目录下的子目录名,不能是多级目录) | 进入子目录 | 94 | | ls | | 显示当前目录清单 | 95 | | rmdir | 目录名(字符串,长度小于28字节,当前目录下的子目录名,不能是多级目录) | 删除子目录 | 96 | | touch | 文件名(字符串,长度小于28字节,不能是多级目录) | 创建新文件 | 97 | | chmod | 文件名(字符串,长度小于28字节,当前目录下的文件名,不能是多级目录) 权限(三位八进制数) | 修改文件或目录权限 | 98 | | rm | 文件名(字符串,长度小于28字节,当前目录下的文件名,不能是多级目录) | 删除文件 | 99 | | useradd | 用户名(字符串) 用户组名(字符串,用户组必须已存在) | 添加用户 | 100 | | userdel | 用户名(字符串,用户必须已存在) | 删除用户 | 101 | | groupadd | 用户组名(字符串) | 添加用户组 | 102 | | groupdel | 用户组名(字符串,用户组必须已存在) | 删除用户组 | 103 | | df | | 查看磁盘使用情况 | 104 | | show | 文件名(字符串,长度小于28字节,当前目录下的文件名,不能是多级目录) | 打印文件内容。如果文件不是字符文件可能会出错 | 105 | | vi | 文件名(字符串,长度小于28字节,当前目录下的文件名,不能是多级目录) | 用编辑器打开文件 | 106 | | format | | 格式化文件系统 | 107 | | win2fs | Windows下的文件路径(字符串,符合Windows文件路径规范) FS文件系统当前目录下的文件名(字符串,长度小于28字节,当前目录下的文件名,不能是多级目录) | 将Windows文件内容复制到FS文件系统文件 | 108 | | fs2win | FS文件系统当前目录下的文件名(字符串,长度小于28字节,当前目录下的文件名,不能是多级目录) Windows下的文件路径(字符串,符合Windows文件路径规范) | 将FS文件系统文件内容复制到Windows文件 | 109 | | cls | | 清屏 | 110 | | help | | 显示命令提示清单 | 111 | 112 | 编辑器使用说明: 113 | 114 | 进入编辑器后可以通过方向键移动光标,当光标位于上下边界时,可以再次令光标向边界处移动完成文本内容的翻页,输入回车键删除光标前的字符,输入其他字符在光标处插入字符,按下esc键退出并保存文本。编辑器中的“□”表示回车键,“#”表示文件结尾。注意编辑器仅能够处理ASCII字符。 115 | 116 | ### 异常说明 117 | 118 | 程序可能因为命令输入不当、文件系统空间用满、非法权限等原因导致各种异常,发生异常时程序会将异常信息输出到控制台,请根据输出信息解决异常。如果始终无法解决异常请尝试将文件系统格式化。 119 | 120 | ### 可调参数说明 121 | 122 | 可调参数位于filesystem.h文件中的宏定义 123 | 124 | | 参数 | 说明 | 125 | | --------- | ------------------------------------------------------------ | 126 | | VERSION | 文件系统版本 | 127 | | DISK_NAME | 模拟文件卷文件名 | 128 | | DISK_SIZE | 文件卷磁盘大小,至少大于1024*512个字节,建议设置为(261120+1024) *512个字节即128MB | 129 | 130 | ### 源代码文件说明 131 | 132 | | 文件名 | 说明 | 133 | | -------------- | ------------------------------------------------------------ | 134 | | filesystem.h | 文件系统头文件 | 135 | | filesystem.cpp | 文件系统C++文件 | 136 | | main.cpp | 主程序C++文件(命令行用户界面) | 137 | | test.cpp | 对文件系统文件接口的测试文件,没有将该文件编译到最终的可执行程序 | 138 | | FS.data | 模拟磁盘文件卷 | 139 | | 文件系统.exe | 可执行程序(命令行用户界面) | 140 | 141 | ### 磁盘卷初始内容 142 | 143 | ![img](README.assets/clip_image002.png) 144 | 145 | ## 附录 146 | 147 | ![img](README.assets/clip_image002-168441891836914.jpg) 148 | 149 | ![img](README.assets/clip_image002-168441892612816.jpg) 150 | 151 | ![img](README.assets/clip_image002-168441895017718.jpg) 152 | 153 | ![img](README.assets/clip_image002-168441899377320.jpg) 154 | 155 | ![img](README.assets/clip_image002-168441900522822.jpg) 156 | 157 | ![img](README.assets/clip_image002-168441902614524.jpg) 158 | 159 | ![img](README.assets/clip_image002-168441904106026.jpg) 160 | 161 | -------------------------------------------------------------------------------- /文件系统/文件系统.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {1C53CD6A-5F7C-479E-9926-67746D56E762} 24 | 文件系统 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v142 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v142 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v142 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v142 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | 78 | 79 | false 80 | 81 | 82 | false 83 | 84 | 85 | 86 | Level3 87 | true 88 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 89 | true 90 | 91 | 92 | Console 93 | true 94 | 95 | 96 | 97 | 98 | Level3 99 | true 100 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 101 | true 102 | 103 | 104 | Console 105 | true 106 | 107 | 108 | 109 | 110 | Level3 111 | true 112 | true 113 | true 114 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 115 | true 116 | 117 | 118 | Console 119 | true 120 | true 121 | true 122 | 123 | 124 | 125 | 126 | Level3 127 | true 128 | true 129 | true 130 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 131 | true 132 | 133 | 134 | Console 135 | true 136 | true 137 | true 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /文件系统/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "filesystem.h" 3 | using namespace std; 4 | class editor 5 | { 6 | protected: 7 | unsigned short width, height; 8 | HANDLE handle; //句柄 9 | CONSOLE_SCREEN_BUFFER_INFO scr_info; //窗口缓冲区信息结构体 10 | COORD pos; //坐标结构体 11 | vector> context; 12 | unsigned short start_line; 13 | void printContext(); 14 | void printPos(); 15 | public: 16 | editor(); 17 | ~editor(); 18 | string run(const string data); 19 | }; 20 | editor::editor() 21 | { 22 | system("cls"); 23 | handle = GetStdHandle(STD_OUTPUT_HANDLE); //获得标准输出设备句柄 24 | GetConsoleScreenBufferInfo(handle, &scr_info); //获取窗口信息 25 | width = scr_info.srWindow.Right - scr_info.srWindow.Left + 1; 26 | height = scr_info.srWindow.Bottom - scr_info.srWindow.Top + 1; 27 | pos = { 0,0 }; 28 | SetConsoleCursorPosition(handle, pos); 29 | start_line = 0; 30 | } 31 | editor::~editor() 32 | { 33 | system("cls"); 34 | } 35 | void editor::printContext() 36 | { 37 | GetConsoleScreenBufferInfo(handle, &scr_info); //获取窗口信息 38 | COORD oldpos = scr_info.dwCursorPosition; 39 | for (short i = start_line; i < start_line + height - 1; i++) 40 | { 41 | if (unsigned int(i) < context.size()) 42 | { 43 | for (short j = 0; j < width; j++) 44 | { 45 | SetConsoleCursorPosition(handle, { j ,i - start_line }); 46 | if (unsigned int(j) < context[i].size()) 47 | { 48 | if (context[i][j] == '\n') 49 | { 50 | printf("%c", char(270)); 51 | } 52 | else 53 | { 54 | printf("%c", context[i][j]); 55 | } 56 | } 57 | else 58 | { 59 | printf("%c", ' '); 60 | } 61 | } 62 | } 63 | else 64 | { 65 | for (short j = 0; j < width; j++) 66 | { 67 | SetConsoleCursorPosition(handle, { j ,i - start_line }); 68 | printf("%c", ' '); 69 | } 70 | } 71 | } 72 | SetConsoleCursorPosition(handle, oldpos); 73 | } 74 | void editor::printPos() 75 | { 76 | GetConsoleScreenBufferInfo(handle, &scr_info); //获取窗口信息 77 | COORD oldpos = scr_info.dwCursorPosition; 78 | SetConsoleCursorPosition(handle, { 0,height - 1 }); 79 | for (short i = 0; i < width; i++) 80 | { 81 | printf("%c", ' '); 82 | } 83 | SetConsoleCursorPosition(handle, { 0,height - 1 }); 84 | printf("[行:%d,列:%d]", start_line + pos.Y + 1, pos.X + 1); 85 | SetConsoleCursorPosition(handle, oldpos); 86 | } 87 | string editor::run(const string data) 88 | { 89 | //转换字符串 90 | vector line; 91 | for (unsigned int pos = 0; pos < data.size(); pos++) 92 | { 93 | if (line.size() < width) 94 | { 95 | if (data[pos] == '\n') 96 | { 97 | line.push_back(data[pos]); 98 | context.push_back(line); 99 | line.clear(); 100 | } 101 | else 102 | { 103 | line.push_back(data[pos]); 104 | } 105 | } 106 | else 107 | { 108 | context.push_back(line); 109 | line.clear(); 110 | if (data[pos] == '\n') 111 | { 112 | line.push_back(data[pos]); 113 | context.push_back(line); 114 | line.clear(); 115 | } 116 | else 117 | { 118 | line.push_back(data[pos]); 119 | } 120 | } 121 | } 122 | if (line.size() < width) 123 | { 124 | line.push_back('#'); 125 | } 126 | else 127 | { 128 | context.push_back(line); 129 | line.clear(); 130 | line.push_back('#'); 131 | } 132 | if (line.size() > 0) 133 | { 134 | context.push_back(line); 135 | } 136 | //打印内容 137 | printContext(); 138 | printPos(); 139 | //编辑器主循环 140 | unsigned char ch; 141 | while (true) 142 | { 143 | if (unsigned int(pos.X) > context[start_line + pos.Y].size() - 1) 144 | { 145 | pos.X = short(context[start_line + pos.Y].size() - 1); 146 | } 147 | SetConsoleCursorPosition(handle, pos); 148 | ch = _getch(); 149 | if (ch == 27)//ESC 150 | { 151 | break; 152 | } 153 | else if (ch == 224) 154 | { 155 | ch = _getch(); 156 | if (ch == 72)//UP 157 | { 158 | pos.Y--; 159 | if (pos.Y < 0) 160 | { 161 | pos.Y = 0; 162 | if (start_line > 0) 163 | { 164 | start_line--; 165 | printContext(); 166 | } 167 | } 168 | SetConsoleCursorPosition(handle, pos); 169 | 170 | } 171 | else if (ch == 80)//DOWN 172 | { 173 | pos.Y++; 174 | if (unsigned int(start_line + pos.Y) > context.size() - 1) 175 | { 176 | pos.Y = short(context.size()) - 1 - start_line; 177 | } 178 | else if (pos.Y > height - 2) 179 | { 180 | pos.Y = height - 2; 181 | start_line++; 182 | printContext(); 183 | } 184 | SetConsoleCursorPosition(handle, pos); 185 | } 186 | else if (ch == 75)//LEFT 187 | { 188 | pos.X--; 189 | if (pos.X < 0) 190 | { 191 | pos.X = 0; 192 | } 193 | SetConsoleCursorPosition(handle, pos); 194 | } 195 | else if (ch == 77)//RIGHT 196 | { 197 | pos.X++; 198 | if (pos.X > width - 1) 199 | { 200 | pos.X = width - 1; 201 | } 202 | SetConsoleCursorPosition(handle, pos); 203 | } 204 | printPos(); 205 | } 206 | else if (ch == '\b') 207 | { 208 | pos.X--; 209 | if (pos.X < 0) 210 | { 211 | pos.Y--; 212 | if (pos.Y < 0) 213 | { 214 | if (start_line > 0) 215 | { 216 | start_line--; 217 | pos.X = width - 1; 218 | pos.Y = 0; 219 | } 220 | else 221 | { 222 | pos.X = 0; 223 | pos.Y = 0; 224 | continue; 225 | } 226 | } 227 | else 228 | { 229 | pos.X = width - 1; 230 | } 231 | } 232 | if (unsigned int(pos.X) > context[start_line + pos.Y].size() - 1) 233 | { 234 | pos.X = short(context[start_line + pos.Y].size() - 1); 235 | } 236 | vector> new_context; 237 | vector new_line; 238 | for (unsigned short i = 0; i < context.size(); i++) 239 | { 240 | for (unsigned short j = 0; j < context[i].size(); j++) 241 | { 242 | if ((i == (start_line + pos.Y)) && (j == pos.X)) 243 | { 244 | continue; 245 | } 246 | if (new_line.size() < width) 247 | { 248 | if (context[i][j] == '\n') 249 | { 250 | new_line.push_back(context[i][j]); 251 | new_context.push_back(new_line); 252 | new_line.clear(); 253 | } 254 | else 255 | { 256 | new_line.push_back(context[i][j]); 257 | } 258 | } 259 | else 260 | { 261 | new_context.push_back(new_line); 262 | new_line.clear(); 263 | if (context[i][j] == '\n') 264 | { 265 | new_line.push_back(context[i][j]); 266 | new_context.push_back(new_line); 267 | new_line.clear(); 268 | } 269 | else 270 | { 271 | new_line.push_back(context[i][j]); 272 | } 273 | } 274 | } 275 | } 276 | if (new_line.size() > 0) 277 | { 278 | new_context.push_back(new_line); 279 | } 280 | context = new_context; 281 | SetConsoleCursorPosition(handle, pos); 282 | printContext(); 283 | printPos(); 284 | } 285 | else 286 | { 287 | vector> new_context; 288 | vector new_line; 289 | for (unsigned short i = 0; i < context.size(); i++) 290 | { 291 | for (unsigned short j = 0; j < context[i].size(); j++) 292 | { 293 | if ((i == (start_line + pos.Y)) && (j == pos.X)) 294 | { 295 | if (new_line.size() < width) 296 | { 297 | if (ch == '\r') 298 | { 299 | new_line.push_back('\n'); 300 | new_context.push_back(new_line); 301 | new_line.clear(); 302 | } 303 | else 304 | { 305 | new_line.push_back(ch); 306 | } 307 | } 308 | else 309 | { 310 | new_context.push_back(new_line); 311 | new_line.clear(); 312 | if (ch == '\r') 313 | { 314 | new_line.push_back('\n'); 315 | new_context.push_back(new_line); 316 | new_line.clear(); 317 | } 318 | else 319 | { 320 | new_line.push_back(ch); 321 | } 322 | } 323 | } 324 | if (new_line.size() < width) 325 | { 326 | if (context[i][j] == '\n') 327 | { 328 | new_line.push_back(context[i][j]); 329 | new_context.push_back(new_line); 330 | new_line.clear(); 331 | } 332 | else 333 | { 334 | new_line.push_back(context[i][j]); 335 | } 336 | } 337 | else 338 | { 339 | new_context.push_back(new_line); 340 | new_line.clear(); 341 | if (context[i][j] == '\n') 342 | { 343 | new_line.push_back(context[i][j]); 344 | new_context.push_back(new_line); 345 | new_line.clear(); 346 | } 347 | else 348 | { 349 | new_line.push_back(context[i][j]); 350 | } 351 | } 352 | } 353 | } 354 | if (new_line.size() > 0) 355 | { 356 | new_context.push_back(new_line); 357 | } 358 | context = new_context; 359 | 360 | if (ch == '\r') 361 | { 362 | pos.X = 0; 363 | pos.Y++; 364 | if (unsigned int(start_line + pos.Y) > context.size() - 1) 365 | { 366 | pos.Y = short(context.size()) - 1 - start_line; 367 | } 368 | else if (pos.Y > height - 2) 369 | { 370 | pos.Y = height - 2; 371 | start_line++; 372 | } 373 | } 374 | else { 375 | pos.X++; 376 | if (pos.X > width - 1) 377 | { 378 | pos.Y++; 379 | if (unsigned int(start_line + pos.Y) > context.size() - 1) 380 | { 381 | pos.X = width - 1; 382 | pos.Y = short(context.size()) - 1 - start_line; 383 | } 384 | else if (pos.Y > height - 2) 385 | { 386 | start_line++; 387 | pos.X = 0; 388 | pos.Y = height - 2; 389 | } 390 | else 391 | { 392 | pos.X = 0; 393 | } 394 | } 395 | } 396 | SetConsoleCursorPosition(handle, pos); 397 | printContext(); 398 | printPos(); 399 | } 400 | } 401 | 402 | string newdata; 403 | for (unsigned short i = 0; i < context.size(); i++) 404 | { 405 | for (unsigned short j = 0; j < context[i].size(); j++) 406 | { 407 | newdata += context[i][j]; 408 | } 409 | } 410 | newdata = newdata.substr(0, newdata.length() - 1); 411 | 412 | return newdata; 413 | } 414 | class FSui 415 | { 416 | protected: 417 | FS fs; 418 | bool is_login; 419 | int cur_uid; 420 | string cur_user; 421 | int cur_gid; 422 | string cur_group; 423 | string cur_dir; 424 | string cur_host; 425 | void initialize(); 426 | void format(); 427 | void mkdir(const char* name); 428 | void cd(const char* name); 429 | void ls(); 430 | void rmdir(const char* name); 431 | void touch(const char* name); 432 | void chmod(const char* name, int mode); 433 | void rm(const char* name); 434 | void login(string name, string passwd); 435 | void useradd(string uname, string gname, string passwd); 436 | void userdel(string uname); 437 | void groupadd(string uname); 438 | void groupdel(string uname); 439 | void df(); 440 | void show(const char* name); 441 | void edit(const char* name); 442 | void win2fs(const char* win_fname, const char* fs_fname); 443 | void fs2win(const char* fs_fname, const char* win_fname); 444 | void help(); 445 | public: 446 | FSui(); 447 | void run(); 448 | }; 449 | void FSui::initialize() 450 | { 451 | is_login = false; 452 | cur_uid = -1; 453 | cur_user = ""; 454 | cur_gid = -1; 455 | cur_group = ""; 456 | cur_dir = ""; 457 | DWORD size = 0; 458 | wstring wstr; 459 | GetComputerName(NULL, &size); //得到电脑名称长度 460 | wchar_t* name = new wchar_t[size]; 461 | if (GetComputerName(name, &size)) 462 | { 463 | wstr = name; 464 | } 465 | delete[] name; 466 | cur_host = wstring2string(wstr); 467 | } 468 | void FSui::format() 469 | { 470 | printf("文件系统正在格式化......\n"); 471 | fs.fformat(); 472 | initialize(); 473 | printf("文件系统格式化完成......\n"); 474 | system("pause"); 475 | system("cls"); 476 | 477 | } 478 | void FSui::mkdir(const char* name) 479 | { 480 | string new_dir = string(name); 481 | if (new_dir.find("/") != string::npos) 482 | { 483 | throw("参数中不能包含多级目录\n"); 484 | } 485 | string dir = cur_dir + "/" + new_dir; 486 | fs.dcreate(dir.data(), cur_uid, cur_gid); 487 | } 488 | void FSui::cd(const char* name) 489 | { 490 | string sub_dir = string(name); 491 | if (sub_dir.find("/") != string::npos) 492 | { 493 | throw("参数中不能包含多级目录\n"); 494 | } 495 | string dir = cur_dir + "/" + sub_dir; 496 | if (!fs.enter(dir.data(), cur_uid, cur_gid)) 497 | { 498 | if (sub_dir == ".") {} 499 | else if (sub_dir == "..") 500 | { 501 | size_t pos = cur_dir.find_last_of('/'); 502 | cur_dir = cur_dir.substr(0, pos); 503 | } 504 | else 505 | { 506 | cur_dir = dir; 507 | } 508 | } 509 | else 510 | { 511 | throw("无法进入指定目录\n"); 512 | } 513 | } 514 | void FSui::ls() 515 | { 516 | vectorlist = fs.list(cur_dir.data(), cur_uid, cur_gid); 517 | for (unsigned int i = 0; i < list.size(); i++) 518 | { 519 | cout << list[i]; 520 | } 521 | } 522 | void FSui::rmdir(const char* name) 523 | { 524 | string new_dir = string(name); 525 | if (new_dir.find("/") != string::npos) 526 | { 527 | throw("参数中不能包含多级目录\n"); 528 | } 529 | string dir = cur_dir + "/" + new_dir; 530 | fs.ddelete(dir.data(), cur_uid, cur_gid); 531 | } 532 | void FSui::touch(const char* name) 533 | { 534 | string new_dir = string(name); 535 | if (new_dir.find("/") != string::npos) 536 | { 537 | throw("参数中不能包含多级目录\n"); 538 | } 539 | string dir = cur_dir + "/" + new_dir; 540 | fs.fcreate(dir.data(), cur_uid, cur_gid); 541 | } 542 | void FSui::chmod(const char* name, int mode) 543 | { 544 | string new_dir = string(name); 545 | if (new_dir.find("/") != string::npos) 546 | { 547 | throw("参数中不能包含多级目录\n"); 548 | } 549 | string dir = cur_dir + "/" + new_dir; 550 | fs.chmod(dir.data(), mode, cur_uid, cur_gid); 551 | } 552 | void FSui::rm(const char* name) 553 | { 554 | string new_dir = string(name); 555 | if (new_dir.find("/") != string::npos) 556 | { 557 | throw("参数中不能包含多级目录\n"); 558 | } 559 | string dir = cur_dir + "/" + new_dir; 560 | fs.fdelete(dir.data(), cur_uid, cur_gid); 561 | } 562 | void FSui::login(string name, string passwd) 563 | { 564 | File* user = fs.fopen("/etc/users.txt"); 565 | char* udata = new char[user->f_inode->i_size + 1]{ 0 }; 566 | fs.fread(udata, user->f_inode->i_size, 1, user); 567 | string ustrdata = udata; 568 | delete[] udata; 569 | fs.fclose(user); 570 | vector users; 571 | users = splitstr(ustrdata, "\n"); 572 | for (unsigned int i = 0; i < users.size(); i++) 573 | { 574 | vectorumsg = splitstr(users[i], "-"); 575 | if (umsg[0] == name && umsg[1] == passwd) 576 | { 577 | is_login = true; 578 | cur_uid = stoi(umsg[2]); 579 | cur_user = name; 580 | cur_gid = stoi(umsg[3]); 581 | 582 | File* group = fs.fopen("/etc/groups.txt"); 583 | char* gdata = new char[group->f_inode->i_size + 1]{ 0 }; 584 | fs.fread(gdata, group->f_inode->i_size, 1, group); 585 | string gstrdata = gdata; 586 | delete[] gdata; 587 | fs.fclose(group); 588 | vector groups; 589 | groups = splitstr(gstrdata, "\n"); 590 | for (unsigned int j = 0; j < groups.size(); j++) 591 | { 592 | vectorgmsg = splitstr(groups[j], "-"); 593 | if (gmsg[1] == umsg[3]) 594 | { 595 | cur_group = gmsg[0].data(); 596 | break; 597 | } 598 | } 599 | 600 | cur_dir = ""; 601 | break; 602 | } 603 | } 604 | } 605 | void FSui::useradd(string uname, string gname, string passwd) 606 | { 607 | if (cur_uid != 0) 608 | { 609 | throw("权限不足\n"); 610 | } 611 | 612 | File* user = fs.fopen("/etc/users.txt"); 613 | char* data = new char[user->f_inode->i_size + 1]{ 0 }; 614 | fs.fread(data, user->f_inode->i_size, 1, user); 615 | string ustrdata = data; 616 | delete[] data; 617 | vector users; 618 | users = splitstr(ustrdata, "\n"); 619 | int next_uid = 0; 620 | for (unsigned int i = 0; i < users.size(); i++) 621 | { 622 | vectorumsg = splitstr(users[i], "-"); 623 | if (umsg[0] == uname) 624 | { 625 | fs.fclose(user); 626 | throw("该用户已存在\n"); 627 | } 628 | if (stoi(umsg[2]) >= next_uid) 629 | { 630 | next_uid = stoi(umsg[2]) + 1; 631 | } 632 | } 633 | 634 | int gid = -1; 635 | File* group = fs.fopen("/etc/groups.txt"); 636 | char* gdata = new char[group->f_inode->i_size + 1]{ 0 }; 637 | fs.fread(gdata, group->f_inode->i_size, 1, group); 638 | string gstrdata = gdata; 639 | delete[] gdata; 640 | vector groups; 641 | groups = splitstr(gstrdata, "\n"); 642 | for (unsigned int i = 0; i < groups.size(); i++) 643 | { 644 | vectorgmsg = splitstr(groups[i], "-"); 645 | if (gmsg[0] == gname) 646 | { 647 | gid = stoi(gmsg[1]); 648 | groups[i] += (gmsg.size() == 2 ? to_string(next_uid) : "," + to_string(next_uid)); 649 | break; 650 | } 651 | } 652 | 653 | if (gid != -1) 654 | { 655 | string new_gdata; 656 | for (unsigned int i = 0; i < groups.size(); i++) 657 | { 658 | new_gdata += groups[i] + "\n"; 659 | } 660 | fs.fseek(group, 0, SEEK_SET); 661 | fs.fwrite(new_gdata.data(), new_gdata.length(), 1, group); 662 | ustrdata += uname + "-" + passwd + "-" + to_string(next_uid) + "-" + to_string(gid) + "\n"; 663 | fs.fseek(user, 0, SEEK_SET); 664 | fs.fwrite(ustrdata.data(), ustrdata.length(), 1, user); 665 | } 666 | else 667 | { 668 | fs.fclose(user); 669 | fs.fclose(group); 670 | throw("用户组不存在\n"); 671 | } 672 | 673 | fs.fclose(user); 674 | fs.fclose(group); 675 | } 676 | void FSui::userdel(string uname) 677 | { 678 | if (cur_uid != 0) 679 | { 680 | throw("权限不足\n"); 681 | } 682 | if (uname == "root") 683 | { 684 | throw("不能删除root用户\n"); 685 | } 686 | 687 | File* user = fs.fopen("/etc/users.txt"); 688 | char* data = new char[user->f_inode->i_size + 1]{ 0 }; 689 | fs.fread(data, user->f_inode->i_size, 1, user); 690 | string ustrdata = data; 691 | delete[] data; 692 | vector users; 693 | users = splitstr(ustrdata, "\n"); 694 | string new_udata; 695 | int uid = -1; 696 | int gid = -1; 697 | for (unsigned int i = 0; i < users.size(); i++) 698 | { 699 | vectorumsg = splitstr(users[i], "-"); 700 | if (umsg[0] == uname) 701 | { 702 | uid = stoi(umsg[2]); 703 | gid = stoi(umsg[3]); 704 | } 705 | else 706 | { 707 | new_udata += users[i] + "\n"; 708 | } 709 | } 710 | if (uid == -1) 711 | { 712 | fs.fclose(user); 713 | throw("该用户不存在\n"); 714 | } 715 | fs.fseek(user, 0, SEEK_SET); 716 | fs.freplace(new_udata.data(), new_udata.length(), 1, user); 717 | fs.fclose(user); 718 | 719 | 720 | File* group = fs.fopen("/etc/groups.txt"); 721 | char* gdata = new char[group->f_inode->i_size + 1]{ 0 }; 722 | fs.fread(gdata, group->f_inode->i_size, 1, group); 723 | string gstrdata = gdata; 724 | delete[] gdata; 725 | vector groups; 726 | groups = splitstr(gstrdata, "\n"); 727 | string new_gdata; 728 | for (unsigned int i = 0; i < groups.size(); i++) 729 | { 730 | vectorgmsg = splitstr(groups[i], "-"); 731 | if (stoi(gmsg[1]) == gid) 732 | { 733 | vectoruids = splitstr(gmsg[2], ","); 734 | string newuids; 735 | for (unsigned int j = 0; j < uids.size(); j++) 736 | { 737 | if (stoi(uids[j]) != uid) 738 | { 739 | newuids += (newuids.length() == 0 ? uids[j] : "," + uids[j]); 740 | } 741 | } 742 | new_gdata += gmsg[0] + "-" + gmsg[1] + "-" + newuids + "\n"; 743 | } 744 | else 745 | { 746 | new_gdata += groups[i] + "\n"; 747 | } 748 | } 749 | 750 | fs.fseek(group, 0, SEEK_SET); 751 | fs.freplace(new_gdata.data(), new_gdata.length(), 1, group); 752 | fs.fclose(group); 753 | } 754 | void FSui::groupadd(string gname) 755 | { 756 | if (cur_uid != 0) 757 | { 758 | throw("权限不足\n"); 759 | } 760 | File* group = fs.fopen("/etc/groups.txt"); 761 | char* gdata = new char[group->f_inode->i_size + 1]{ 0 }; 762 | fs.fread(gdata, group->f_inode->i_size, 1, group); 763 | string gstrdata = gdata; 764 | delete[] gdata; 765 | vector groups; 766 | groups = splitstr(gstrdata, "\n"); 767 | int next_gid = 0; 768 | for (unsigned int i = 0; i < groups.size(); i++) 769 | { 770 | vectorgmsg = splitstr(groups[i], "-"); 771 | if (gmsg[0] == gname) 772 | { 773 | fs.fclose(group); 774 | throw("该用户组已存在\n"); 775 | } 776 | if (stoi(gmsg[1]) >= next_gid) 777 | { 778 | next_gid = stoi(gmsg[1]) + 1; 779 | } 780 | } 781 | gstrdata += gname + "-" + to_string(next_gid) + "-\n"; 782 | fs.fseek(group, 0, SEEK_SET); 783 | fs.fwrite(gstrdata.data(), gstrdata.length(), 1, group); 784 | fs.fclose(group); 785 | } 786 | void FSui::groupdel(string gname) 787 | { 788 | if (cur_uid != 0) 789 | { 790 | throw("权限不足\n"); 791 | } 792 | if (gname == "root") 793 | { 794 | throw("不能删除root用户组\n"); 795 | } 796 | 797 | File* group = fs.fopen("/etc/groups.txt"); 798 | char* gdata = new char[group->f_inode->i_size + 1]{ 0 }; 799 | fs.fread(gdata, group->f_inode->i_size, 1, group); 800 | string gstrdata = gdata; 801 | delete[] gdata; 802 | vector groups; 803 | groups = splitstr(gstrdata, "\n"); 804 | string new_gdata; 805 | vectoruids; 806 | bool flag = false; 807 | for (unsigned int i = 0; i < groups.size(); i++) 808 | { 809 | vectorgmsg = splitstr(groups[i], "-"); 810 | if (gmsg[0] == gname) 811 | { 812 | flag = true; 813 | uids = splitstr(gmsg[2], ","); 814 | } 815 | else 816 | { 817 | new_gdata += groups[i] + "\n"; 818 | } 819 | } 820 | if (!flag) 821 | { 822 | fs.fclose(group); 823 | throw("该用户组不存在\n"); 824 | } 825 | fs.fseek(group, 0, SEEK_SET); 826 | fs.freplace(new_gdata.data(), new_gdata.length(), 1, group); 827 | fs.fclose(group); 828 | 829 | File* user = fs.fopen("/etc/users.txt"); 830 | char* data = new char[user->f_inode->i_size + 1]{ 0 }; 831 | fs.fread(data, user->f_inode->i_size, 1, user); 832 | string ustrdata = data; 833 | delete[] data; 834 | vector users; 835 | users = splitstr(ustrdata, "\n"); 836 | string new_udata; 837 | for (unsigned int i = 0; i < users.size(); i++) 838 | { 839 | vectorumsg = splitstr(users[i], "-"); 840 | if (find(uids.begin(), uids.end(), umsg[2]) == uids.end()) 841 | { 842 | new_udata += users[i] + "\n"; 843 | } 844 | } 845 | fs.fseek(user, 0, SEEK_SET); 846 | fs.freplace(new_udata.data(), new_udata.length(), 1, user); 847 | fs.fclose(user); 848 | } 849 | void FSui::df() 850 | { 851 | SuperBlock superblock = fs.getSpb(); 852 | int size = superblock.s_block_num * superblock.s_block_size; 853 | int used = (superblock.s_block_num - superblock.s_block_fnum) * superblock.s_block_size; 854 | int avaial = superblock.s_block_fnum * superblock.s_block_size; 855 | double use = 100 * double((double)superblock.s_block_num - (double)superblock.s_block_fnum) / double(superblock.s_block_num); 856 | int inode = superblock.s_inode_num; 857 | int iavaial = superblock.s_inode_fnum; 858 | printf("%-10s %-10s %-10s %-10s %-10s %-10s %-10s %s\n", "Filesystem", "Size", "Used", "Avaial", "Use%", "Inode", "Ifree", "Monted on"); 859 | printf("%-10s %-10d %-10d %-10d %-10.2f %-10d %-10d %s\n", "FS", size, used, avaial, use, inode, iavaial, "/"); 860 | } 861 | void FSui::show(const char* name) 862 | { 863 | string fname = string(name); 864 | if (fname.find("/") != string::npos) 865 | { 866 | throw("参数中不能包含多级目录\n"); 867 | } 868 | string dir = cur_dir + "/" + fname; 869 | File* fp = fs.fopen(dir.data(), cur_uid, cur_gid); 870 | char* fdata = new char[fp->f_inode->i_size + 1]{ 0 }; 871 | fs.fread(fdata, fp->f_inode->i_size, 1, fp); 872 | cout << fdata << endl; 873 | fs.fclose(fp); 874 | delete[] fdata; 875 | } 876 | void FSui::edit(const char* name) 877 | { 878 | string fname = string(name); 879 | if (fname.find("/") != string::npos) 880 | { 881 | throw("参数中不能包含多级目录\n"); 882 | } 883 | string dir = cur_dir + "/" + fname; 884 | File* fp = fs.fopen(dir.data(), cur_uid, cur_gid); 885 | char* fdata = new char[fp->f_inode->i_size + 1]{ 0 }; 886 | fs.fread(fdata, fp->f_inode->i_size, 1, fp); 887 | editor e; 888 | string newdata = e.run(string(fdata)); 889 | 890 | fs.fseek(fp, 0, SEEK_SET); 891 | fs.freplace(newdata.data(), newdata.length(), 1, fp); 892 | fs.fclose(fp); 893 | delete[] fdata; 894 | } 895 | void FSui::win2fs(const char* win_fname, const char* fs_fname) 896 | { 897 | if (string(fs_fname).find("/") != string::npos) 898 | { 899 | throw("参数中不能包含多级目录\n"); 900 | } 901 | string fs_dir = cur_dir + "/" + string(fs_fname); 902 | 903 | FILE* winfp; 904 | fopen_s(&winfp, win_fname, "rb"); 905 | if (winfp == NULL) 906 | { 907 | throw("打开windows文件失败\n"); 908 | } 909 | fseek(winfp, 0, SEEK_END); 910 | unsigned int file_size = ftell(winfp); 911 | fseek(winfp, 0, SEEK_SET); 912 | char* data = new char[file_size + 1]{ 0 }; 913 | fread(data, file_size, 1, winfp); 914 | fclose(winfp); 915 | File* fsfp = fs.fopen(fs_dir.data(), cur_uid, cur_gid); 916 | fs.freplace(data, file_size, 1, fsfp); 917 | fs.fclose(fsfp); 918 | delete[] data; 919 | } 920 | void FSui::fs2win(const char* fs_fname, const char* win_fname) 921 | { 922 | 923 | if (string(fs_fname).find("/") != string::npos) 924 | { 925 | throw("参数中不能包含多级目录\n"); 926 | } 927 | string fs_dir = cur_dir + "/" + string(fs_fname); 928 | 929 | File* fsfp = fs.fopen(fs_dir.data(), cur_uid, cur_gid); 930 | unsigned file_size = fsfp->f_inode->i_size; 931 | char* data = new char[file_size + 1]{ 0 }; 932 | fs.fread(data, file_size, 1, fsfp); 933 | fs.fclose(fsfp); 934 | FILE* winfp; 935 | fopen_s(&winfp, win_fname, "wb"); 936 | if (winfp == NULL) 937 | { 938 | throw("打开windows文件失败\n"); 939 | } 940 | fwrite(data, file_size, 1, winfp); 941 | fclose(winfp); 942 | delete[] data; 943 | } 944 | void FSui::help() 945 | { 946 | printf("format - 格式化文件系统\n"); 947 | printf("mkdir - 创建目录\n"); 948 | printf("cd - 进入目录\n"); 949 | printf("ls - 显示当前目录清单\n"); 950 | printf("rmdir - 删除目录\n"); 951 | printf("touch - 创建新文件\n"); 952 | printf("chmod - 修改文件或目录权限\n"); 953 | printf("rm - 删除文件\n"); 954 | printf("login - 用户登录\n"); 955 | printf("logout - 用户注销\n"); 956 | printf("useradd - 添加用户\n"); 957 | printf("userdel - 删除用户\n"); 958 | printf("groupadd - 添加用户组\n"); 959 | printf("groupdel - 删除用户组\n"); 960 | printf("df - 查看磁盘使用情况\n"); 961 | printf("show - 打印文件内容\n"); 962 | printf("vi - 用编辑器打开文件\n"); 963 | printf("win2fs - 将Windows文件内容复制到FS文件系统文件\n"); 964 | printf("fs2win - 将FS文件系统文件内容复制到Windows文件\n"); 965 | printf("help - 显示命令清单\n"); 966 | printf("cls - 清屏\n"); 967 | printf("exit - 退出系统\n"); 968 | } 969 | FSui::FSui() 970 | { 971 | initialize(); 972 | } 973 | void FSui::run() 974 | { 975 | cout << 976 | "\ 977 | ________ ________ \n\ 978 | | ____| | ____| FILE SYSTEM \n\ 979 | | |____ | |____ verson " << VERSION << " \n\ 980 | | ____| |____ | Copyright 2021 \n\ 981 | | | ____| | https://github.com/lingbai-kong \n\ 982 | |__| |_______| ALL Rights Reserved \n\ 983 | \n"; 984 | while (true) 985 | { 986 | cout << "[" << cur_user << "@" << cur_host << ":" << ROOT_DIR_SYMBOL << cur_dir << "]" << (cur_user == "root" ? "#" : "$") << " "; 987 | string buf; 988 | vectorargs; 989 | getline(cin, buf); 990 | args = splitstr(buf, " "); 991 | try { 992 | if (args.size() <= 0) 993 | { 994 | continue; 995 | } 996 | else if (is_login) 997 | { 998 | if (args[0] == "logout") 999 | { 1000 | initialize(); 1001 | } 1002 | else if (args[0] == "exit") 1003 | { 1004 | return; 1005 | } 1006 | else if (args[0] == "mkdir" && args.size() == 2) 1007 | { 1008 | mkdir(args[1].data()); 1009 | } 1010 | else if (args[0] == "cd" && args.size() == 2) 1011 | { 1012 | cd(args[1].data()); 1013 | } 1014 | else if (args[0] == "ls") 1015 | { 1016 | ls(); 1017 | } 1018 | else if (args[0] == "rmdir" && args.size() == 2) 1019 | { 1020 | rmdir(args[1].data()); 1021 | } 1022 | else if (args[0] == "touch" && args.size() == 2) 1023 | { 1024 | touch(args[1].data()); 1025 | } 1026 | else if (args[0] == "chmod" && args.size() == 3 && args[2].size() == 3) 1027 | { 1028 | int master = stoi(args[2].substr(0, 1)); 1029 | int group = stoi(args[2].substr(1, 1)); 1030 | int others = stoi(args[2].substr(2, 1)); 1031 | if (master >= 0 && master <= 7 && group >= 0 && group <= 7 && others >= 0 && others <= 7) 1032 | { 1033 | int mode = (master << 6) + (group << 3) + others; 1034 | chmod(args[1].data(), mode); 1035 | } 1036 | else 1037 | { 1038 | cout << "无效的权限\n"; 1039 | } 1040 | } 1041 | else if (args[0] == "rm" && args.size() == 2) 1042 | { 1043 | rm(args[1].data()); 1044 | } 1045 | else if (args[0] == "useradd" && args.size() == 3) 1046 | { 1047 | cout << "password: "; 1048 | char password[256] = { 0 }; 1049 | char ch = '\0'; 1050 | int pos = 0; 1051 | while ((ch = _getch()) != '\r' && pos < 255) 1052 | { 1053 | if (ch != 8)//不是回撤就录入 1054 | { 1055 | password[pos] = ch; 1056 | putchar('*');//并且输出*号 1057 | pos++; 1058 | } 1059 | else 1060 | { 1061 | putchar('\b');//这里是删除一个,我们通过输出回撤符 /b,回撤一格, 1062 | putchar(' ');//再显示空格符把刚才的*给盖住, 1063 | putchar('\b');//然后再 回撤一格等待录入。 1064 | pos--; 1065 | } 1066 | } 1067 | password[pos] = '\0'; 1068 | putchar('\n'); 1069 | useradd(args[1], args[2], string(password)); 1070 | } 1071 | else if (args[0] == "userdel" && args.size() == 2) 1072 | { 1073 | userdel(args[1]); 1074 | } 1075 | else if (args[0] == "groupadd" && args.size() == 2) 1076 | { 1077 | groupadd(args[1]); 1078 | } 1079 | else if (args[0] == "groupdel" && args.size() == 2) 1080 | { 1081 | groupdel(args[1]); 1082 | } 1083 | else if (args[0] == "df") 1084 | { 1085 | df(); 1086 | } 1087 | else if (args[0] == "show" && args.size() == 2) 1088 | { 1089 | show(args[1].data()); 1090 | } 1091 | else if (args[0] == "vi" && args.size() == 2) 1092 | { 1093 | edit(args[1].data()); 1094 | } 1095 | else if (args[0] == "format") 1096 | { 1097 | cout << "确定要进行格式化?[y] "; 1098 | string ck; 1099 | getline(cin, ck); 1100 | if (ck == "y" || ck == "Y") 1101 | { 1102 | format(); 1103 | } 1104 | } 1105 | else if (args[0] == "win2fs" && args.size() == 3) 1106 | { 1107 | win2fs(args[1].data(), args[2].data()); 1108 | } 1109 | else if (args[0] == "fs2win" && args.size() == 3) 1110 | { 1111 | fs2win(args[1].data(), args[2].data()); 1112 | } 1113 | else if (args[0] == "cls") 1114 | { 1115 | system("cls"); 1116 | } 1117 | else if (args[0] == "help") 1118 | { 1119 | help(); 1120 | } 1121 | else 1122 | { 1123 | cout << "无效的命令!\n"; 1124 | } 1125 | } 1126 | else 1127 | { 1128 | if (args[0] == "login" && args.size() == 2) 1129 | { 1130 | cout << "password: "; 1131 | char password[256] = { 0 }; 1132 | char ch = '\0'; 1133 | int pos = 0; 1134 | while ((ch = _getch()) != '\r' && pos < 255) 1135 | { 1136 | if (ch != 8)//不是回撤就录入 1137 | { 1138 | password[pos] = ch; 1139 | putchar('*');//并且输出*号 1140 | pos++; 1141 | } 1142 | else 1143 | { 1144 | putchar('\b');//这里是删除一个,我们通过输出回撤符 /b,回撤一格, 1145 | putchar(' ');//再显示空格符把刚才的*给盖住, 1146 | putchar('\b');//然后再 回撤一格等待录入。 1147 | pos--; 1148 | } 1149 | } 1150 | password[pos] = '\0'; 1151 | putchar('\n'); 1152 | login(args[1], string(password)); 1153 | } 1154 | else if (args[0] == "exit") 1155 | { 1156 | return; 1157 | } 1158 | else if (args[0] == "format") 1159 | { 1160 | cout << "确定要进行格式化?[y] "; 1161 | string ck; 1162 | getline(cin, ck); 1163 | if (ck == "y" || ck == "Y") 1164 | { 1165 | format(); 1166 | } 1167 | } 1168 | else if (args[0] == "help") 1169 | { 1170 | help(); 1171 | } 1172 | else 1173 | { 1174 | cout << "无效的命令!\n"; 1175 | } 1176 | } 1177 | } 1178 | catch (const char* errMsg) { 1179 | cout << errMsg; 1180 | } 1181 | } 1182 | } 1183 | int main() 1184 | { 1185 | try { 1186 | FSui app; 1187 | app.run(); 1188 | } 1189 | catch (...) 1190 | { 1191 | cout << "程序运行错误\n"; 1192 | } 1193 | return 0; 1194 | } 1195 | -------------------------------------------------------------------------------- /文件系统/filesystem.cpp: -------------------------------------------------------------------------------- 1 | #include "filesystem.h" 2 | using namespace std; 3 | string wstring2string(wstring wstr) 4 | { 5 | string result; 6 | //获取缓冲区大小,并申请空间,缓冲区大小事按字节计算的 7 | int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), NULL, 0, NULL, NULL); 8 | char* buffer = new char[len + 1]; 9 | //宽字节编码转换成多字节编码 10 | WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), buffer, len, NULL, NULL); 11 | buffer[len] = '\0'; 12 | //删除缓冲区并返回值 13 | result.append(buffer); 14 | delete[] buffer; 15 | return result; 16 | } 17 | vector splitstr(string str, string pattern) 18 | { 19 | vector res; 20 | char* pTmp = NULL; 21 | char* temp = strtok_s((char*)str.c_str(), pattern.c_str(), &pTmp); 22 | while (temp != NULL) 23 | { 24 | res.push_back(string(temp)); 25 | temp = strtok_s(NULL, pattern.c_str(), &pTmp); 26 | } 27 | return res; 28 | } 29 | 30 | BufferManager::BufferManager() 31 | { 32 | initialize(); 33 | } 34 | BufferManager::~BufferManager() 35 | { 36 | for (auto i = 0; i < NBUF; i++) 37 | { 38 | relseBlk(&m_Buf[i]); 39 | } 40 | } 41 | void BufferManager::initialize() 42 | { 43 | bFreeList.b_blkno = -1; 44 | bFreeList.b_addr = NULL; 45 | bFreeList.b_flags = BufFlag::B_NONE; 46 | bFreeList.b_forw = &m_Buf[NBUF - 1]; 47 | bFreeList.b_back = &m_Buf[0]; 48 | bFreeList.av_forw = &m_Buf[0]; 49 | bFreeList.av_back = &m_Buf[NBUF - 1]; 50 | for (auto i = 0; i < NBUF; i++) 51 | { 52 | m_Buf[i].b_blkno = -1; 53 | m_Buf[i].b_addr = Buffer[i]; 54 | m_Buf[i].b_flags = BufFlag::B_NONE; 55 | if (i - 1 >= 0) 56 | { 57 | m_Buf[i].b_forw = &m_Buf[i - 1]; 58 | m_Buf[i].av_back = &m_Buf[i - 1]; 59 | } 60 | else 61 | { 62 | m_Buf[i].b_forw = &bFreeList; 63 | m_Buf[i].av_back = &bFreeList; 64 | } 65 | if (i + 1 < NBUF) 66 | { 67 | m_Buf[i].b_back = &m_Buf[i + 1]; 68 | m_Buf[i].av_forw = &m_Buf[i + 1]; 69 | } 70 | else 71 | { 72 | m_Buf[i].b_back = &bFreeList; 73 | m_Buf[i].av_forw = &bFreeList; 74 | } 75 | } 76 | diskTab.b_blkno = -1; 77 | diskTab.b_addr = NULL; 78 | diskTab.b_flags = BufFlag::B_NONE; 79 | diskTab.b_forw = &diskTab; 80 | diskTab.b_back = &diskTab; 81 | diskTab.av_forw = &diskTab; 82 | diskTab.av_back = &diskTab; 83 | } 84 | Buf* BufferManager::getBlk(unsigned int blkno) 85 | { 86 | Buf* bp = NULL; 87 | for (bp = diskTab.b_back; bp != &diskTab; bp = bp->b_back) 88 | { 89 | if (bp->b_blkno == blkno) 90 | { 91 | return bp; 92 | } 93 | } 94 | // 自由队列空 95 | if (bFreeList.av_back == &bFreeList) 96 | { 97 | // 实际中I/O请求队列中最多有一个缓存,因此自由队列不可能为空 98 | } 99 | else 100 | { 101 | bp = bFreeList.av_back; 102 | // 从自由队列取出 103 | bp->av_forw->av_back = bp->av_back; 104 | bp->av_back->av_forw = bp->av_forw; 105 | // 从原设备队列或NODEV队列取出 106 | bp->b_forw->b_back = bp->b_back; 107 | bp->b_back->b_forw = bp->b_forw; 108 | // 含有延迟写 109 | if ((bp->b_flags & BufFlag::B_DELWRI) == BufFlag::B_DELWRI) 110 | { 111 | // 立即写入 112 | Bwrite(bp); 113 | // 清除延迟写标志 114 | bp->b_flags = bp->b_flags & (~BufFlag::B_DELWRI); 115 | } 116 | // 清除所有标志 117 | bp->b_flags = BufFlag::B_NONE; 118 | // 填写blkno,插入设备队列队头 119 | bp->b_blkno = blkno; 120 | bp->b_forw = &diskTab; 121 | bp->b_back = diskTab.b_back; 122 | bp->b_forw->b_back = bp; 123 | bp->b_back->b_forw = bp; 124 | } 125 | return bp; 126 | } 127 | void BufferManager::relseBlk(Buf* bp) 128 | { 129 | if ((bp->b_flags & BufFlag::B_DELWRI) == BufFlag::B_DELWRI) 130 | { 131 | // 立即写入 132 | Bwrite(bp); 133 | // 清除延迟写标志 134 | bp->b_flags = bp->b_flags & (~BufFlag::B_DELWRI); 135 | } 136 | // 清除所有标志 137 | bp->b_flags = BufFlag::B_NONE; 138 | // 置入自由队列和NODEV队列 139 | bp->b_forw->b_back = bp->b_back; 140 | bp->b_back->b_forw = bp->b_forw; 141 | bp->av_forw->av_back = bp->av_back; 142 | bp->av_back->av_forw = bp->av_forw; 143 | 144 | bp->av_forw = bFreeList.av_forw; 145 | bp->av_back = &bFreeList; 146 | bp->av_forw->av_back = bp; 147 | bp->av_back->av_forw = bp; 148 | 149 | bp->b_forw = &bFreeList; 150 | bp->b_back = bFreeList.b_back; 151 | bp->b_forw->b_back = bp; 152 | bp->b_back->b_forw = bp; 153 | } 154 | Buf* BufferManager::Bread(unsigned int blkno) 155 | { 156 | Buf* bp = getBlk(blkno); 157 | if ((bp->b_flags & BufFlag::B_DONE) == BufFlag::B_DONE) 158 | { 159 | return bp; 160 | } 161 | else 162 | { 163 | // I/O读操作,送入I/O请求队列 164 | bp->av_forw = diskTab.av_forw; 165 | bp->av_back = &diskTab; 166 | bp->av_forw->av_back = bp; 167 | bp->av_back->av_forw = bp; 168 | // 开始读操作 169 | fstream fin; 170 | fin.open(DISK_NAME, ios::in | ios::binary); 171 | if (!fin.is_open()) 172 | { 173 | throw("磁盘映像输入文件流打开失败\n"); 174 | } 175 | fin.seekg(streampos(blkno) * streampos(BUFFER_SIZE), ios::beg); 176 | fin.read(bp->b_addr, BUFFER_SIZE); 177 | fin.close(); 178 | // 读操作完成 179 | // 更新标志 180 | bp->b_flags = BufFlag::B_DONE; 181 | // 从I/O请求队列取出 182 | bp->av_forw->av_back = bp->av_back; 183 | bp->av_back->av_forw = bp->av_forw; 184 | // 加入自由队列 185 | bp->av_forw = bFreeList.av_forw; 186 | bp->av_back = &bFreeList; 187 | bp->av_forw->av_back = bp; 188 | bp->av_back->av_forw = bp; 189 | return bp; 190 | } 191 | } 192 | void BufferManager::Bwrite(Buf* bp) 193 | { 194 | // I/O写操作,送入I/O请求队列 195 | bp->av_forw = diskTab.av_forw; 196 | bp->av_back = &diskTab; 197 | bp->av_forw->av_back = bp; 198 | bp->av_back->av_forw = bp; 199 | // 开始写操作 200 | fstream fout; 201 | fout.open(DISK_NAME, ios::in | ios::out | ios::binary); 202 | if (!fout.is_open()) 203 | { 204 | throw("磁盘映像输出文件流打开失败\n"); 205 | } 206 | fout.seekp(streampos(bp->b_blkno) * streampos(BUFFER_SIZE), ios::beg); 207 | fout.write((const char*)bp->b_addr, BUFFER_SIZE); 208 | fout.close(); 209 | // 写操作完成 210 | // 更新标志 211 | bp->b_flags = BufFlag::B_DONE; 212 | // 从I/O请求队列取出 213 | bp->av_forw->av_back = bp->av_back; 214 | bp->av_back->av_forw = bp->av_forw; 215 | // 加入自由队列 216 | bp->av_forw = bFreeList.av_forw; 217 | bp->av_back = &bFreeList; 218 | bp->av_forw->av_back = bp; 219 | bp->av_back->av_forw = bp; 220 | } 221 | void BufferManager::Bdwirte(Buf* bp) 222 | { 223 | bp->b_flags |= BufFlag::B_DELWRI; 224 | } 225 | void BufferManager::bread(char* buf, unsigned int start_addr, unsigned int length) 226 | { 227 | if (buf == NULL) 228 | return; 229 | unsigned int pos = 0; 230 | unsigned int start_blkno = start_addr / BUFFER_SIZE; 231 | unsigned int end_blkno = (start_addr + length - 1) / BUFFER_SIZE; 232 | for (unsigned int blkno = start_blkno; blkno <= end_blkno; blkno++) 233 | { 234 | Buf* bp = Bread(blkno); 235 | if (blkno == start_blkno && blkno == end_blkno) 236 | { 237 | memcpy_s(buf + pos, length, bp->b_addr + start_addr % BUFFER_SIZE, length); 238 | pos += length; 239 | } 240 | else if (blkno == start_blkno) 241 | { 242 | memcpy_s(buf + pos, (BUFFER_SIZE - 1) - (start_addr % BUFFER_SIZE) + 1, bp->b_addr + start_addr % BUFFER_SIZE, (BUFFER_SIZE - 1) - (start_addr % BUFFER_SIZE) + 1); 243 | pos += BUFFER_SIZE - (start_addr % BUFFER_SIZE); 244 | } 245 | else if (blkno == end_blkno) 246 | { 247 | memcpy_s(buf + pos, (start_addr + length - 1) % BUFFER_SIZE - 0 + 1, bp->b_addr, (start_addr + length - 1) % BUFFER_SIZE - 0 + 1); 248 | pos += (start_addr + length - 1) % BUFFER_SIZE - 0 + 1; 249 | } 250 | else 251 | { 252 | memcpy_s(buf + pos, BUFFER_SIZE, bp->b_addr, BUFFER_SIZE); 253 | pos += BUFFER_SIZE; 254 | } 255 | } 256 | } 257 | void BufferManager::bwrite(const char* buf, unsigned int start_addr, unsigned int length) 258 | { 259 | unsigned int pos = 0; 260 | unsigned int start_blkno = start_addr / BUFFER_SIZE; 261 | unsigned int end_blkno = (start_addr + length - 1) / BUFFER_SIZE; 262 | for (unsigned int blkno = start_blkno; blkno <= end_blkno; blkno++) 263 | { 264 | Buf* bp = Bread(blkno); 265 | if (blkno == start_blkno && blkno == end_blkno) 266 | { 267 | memcpy_s(bp->b_addr + start_addr % BUFFER_SIZE, length, buf + pos, length); 268 | pos += length; 269 | } 270 | else if (blkno == start_blkno) 271 | { 272 | memcpy_s(bp->b_addr + start_addr % BUFFER_SIZE, (BUFFER_SIZE - 1) - (start_addr % BUFFER_SIZE) + 1, buf + pos, (BUFFER_SIZE - 1) - (start_addr % BUFFER_SIZE) + 1); 273 | pos += BUFFER_SIZE - (start_addr % BUFFER_SIZE); 274 | } 275 | else if (blkno == end_blkno) 276 | { 277 | memcpy_s(bp->b_addr, (start_addr + length - 1) % BUFFER_SIZE - 0 + 1, buf + pos, (start_addr + length - 1) % BUFFER_SIZE - 0 + 1); 278 | pos += (start_addr + length - 1) % BUFFER_SIZE - 0 + 1; 279 | } 280 | else 281 | { 282 | memcpy_s(bp->b_addr, BUFFER_SIZE, buf + pos, BUFFER_SIZE); 283 | pos += BUFFER_SIZE; 284 | } 285 | Bdwirte(bp); 286 | } 287 | } 288 | 289 | Inode FS::iload(int inode_no) 290 | { 291 | DiskInode d_inode; 292 | buffer.bread((char*)&d_inode, spb.s_inode_start_addr + inode_no * spb.s_inode_size, spb.s_inode_size); 293 | Inode inode; 294 | memcpy_s(&inode, spb.s_inode_size, &d_inode, spb.s_inode_size); 295 | inode.i_no = inode_no; 296 | return inode; 297 | } 298 | void FS::isave(Inode inode) 299 | { 300 | DiskInode d_inode; 301 | memcpy_s(&d_inode, spb.s_inode_size, &inode, spb.s_inode_size); 302 | buffer.bwrite((const char*)&d_inode, spb.s_inode_start_addr + inode.i_no * spb.s_inode_size, spb.s_inode_size); 303 | } 304 | Inode FS::ialloc() 305 | { 306 | if (spb.s_inode_fnum <= 0) 307 | { 308 | throw("Inode分配失败,因为没有空闲的Inode\n"); 309 | } 310 | 311 | if (spb.s_ninode <= 0) 312 | { 313 | for (unsigned int i = 0; i < spb.s_inode_num && spb.s_ninode < 100; i++) 314 | { 315 | Inode item = iload(i); 316 | if ((item.i_mode & IALLOC) == 0) 317 | { 318 | spb.s_inode[spb.s_ninode++] = i; 319 | } 320 | } 321 | } 322 | if (spb.s_ninode <= 0 || spb.s_ninode > 100) 323 | { 324 | throw("读取spb.s_inode越界\n"); 325 | } 326 | spb.s_inode_fnum--; 327 | int ret_no = spb.s_inode[--spb.s_ninode]; 328 | return iload(ret_no); 329 | } 330 | void FS::ifree(Inode inode) 331 | { 332 | memset(&inode, 0, spb.s_inode_size); 333 | isave(inode); 334 | spb.s_inode_fnum++; 335 | if (spb.s_ninode < 100) 336 | { 337 | spb.s_inode[spb.s_ninode++] = inode.i_no; 338 | } 339 | } 340 | int FS::balloc() 341 | { 342 | if (spb.s_block_fnum <= 0) 343 | { 344 | throw("block分配失败,因为没有空闲的block\n"); 345 | } 346 | if (spb.s_nfree <= 0 || spb.s_nfree > 100) 347 | { 348 | throw("读取spb.s_free越界\n"); 349 | } 350 | spb.s_block_fnum--; 351 | int ret_no = spb.s_free[--spb.s_nfree]; 352 | if (spb.s_nfree == 0 && spb.s_block_fnum > 0) 353 | { 354 | int address = spb.s_block_start_addr + spb.s_free[0] * spb.s_block_size; 355 | buffer.bread((char*)&spb.s_nfree, address, sizeof(spb.s_nfree)); 356 | buffer.bread((char*)spb.s_free, address + sizeof(spb.s_nfree), sizeof(spb.s_free)); 357 | } 358 | return ret_no; 359 | } 360 | void FS::bfree(int no) 361 | { 362 | spb.s_block_fnum++; 363 | if (spb.s_nfree == 100) 364 | { 365 | int cur_block_address = spb.s_block_start_addr + no * spb.s_block_size; 366 | buffer.bwrite((const char*)&spb.s_nfree, cur_block_address, sizeof(spb.s_nfree)); 367 | buffer.bwrite((const char*)spb.s_free, cur_block_address + int(sizeof(spb.s_nfree)), sizeof(spb.s_free)); 368 | spb.s_nfree = 0; 369 | memset(spb.s_free, 0, sizeof(spb.s_free)); 370 | } 371 | spb.s_free[spb.s_nfree++] = no; 372 | } 373 | Inode FS::_ffind(Inode& cur_inode, const char* name) 374 | { 375 | if ((cur_inode.i_mode & (3 << 13)) != DIR_FILE) 376 | { 377 | throw("当前路径非目录文件\n"); 378 | } 379 | 380 | DirItem* dir_list = new DirItem[cur_inode.i_size / spb.dir_item_size]{ 0 }; 381 | _fread(cur_inode, (char*)dir_list, 0, cur_inode.i_size); 382 | for (unsigned int i = 0; i < cur_inode.i_size / spb.dir_item_size; i++) 383 | { 384 | if (strcmp(dir_list[i].item_name, name) == 0) 385 | { 386 | int ret_no = dir_list[i].inode_no; 387 | delete[] dir_list; 388 | return iload(ret_no); 389 | } 390 | } 391 | delete[] dir_list; 392 | throw("找不到该文件\n"); 393 | } 394 | void FS::_fread(Inode& cur_inode, char* buf, unsigned int start_addr, unsigned int len) 395 | { 396 | if (int(start_addr + len) > cur_inode.i_size) 397 | { 398 | throw("读文件越界\n"); 399 | } 400 | if (cur_inode.i_size == 0) 401 | { 402 | return; 403 | } 404 | char* filedata = new char[cur_inode.i_size]{ 0 }; 405 | unsigned int length = 0; 406 | for (unsigned int i = 0; i < 6 && length < cur_inode.i_size; i++) 407 | { 408 | if (length + spb.s_block_size < cur_inode.i_size) 409 | { 410 | buffer.bread((char*)filedata + length, spb.s_block_start_addr + cur_inode.i_addr[i] * spb.s_block_size, spb.s_block_size); 411 | length += spb.s_block_size; 412 | } 413 | else 414 | { 415 | buffer.bread((char*)filedata + length, spb.s_block_start_addr + cur_inode.i_addr[i] * spb.s_block_size, cur_inode.i_size - length); 416 | length = cur_inode.i_size; 417 | } 418 | } 419 | for (unsigned int i = 6; i < 8 && length < cur_inode.i_size; i++) 420 | { 421 | int* one_time_indirect_index = new int[spb.s_block_size / sizeof(int)]{ 0 }; 422 | buffer.bread((char*)one_time_indirect_index, spb.s_block_start_addr + cur_inode.i_addr[i] * spb.s_block_size, spb.s_block_size); 423 | for (unsigned int j = 0; j < spb.s_block_size / sizeof(int) && length < cur_inode.i_size; j++) 424 | { 425 | if (length + spb.s_block_size < cur_inode.i_size) 426 | { 427 | buffer.bread((char*)filedata + length, spb.s_block_start_addr + one_time_indirect_index[j] * spb.s_block_size, spb.s_block_size); 428 | length += spb.s_block_size; 429 | } 430 | else 431 | { 432 | buffer.bread((char*)filedata + length, spb.s_block_start_addr + one_time_indirect_index[j] * spb.s_block_size, cur_inode.i_size - length); 433 | length = cur_inode.i_size; 434 | } 435 | } 436 | delete[] one_time_indirect_index; 437 | } 438 | for (unsigned int i = 8; i < 10 && length < cur_inode.i_size; i++) 439 | { 440 | int* two_time_indirect_index = new int[spb.s_block_size / sizeof(int)]{ 0 }; 441 | buffer.bread((char*)two_time_indirect_index, spb.s_block_start_addr + cur_inode.i_addr[i] * spb.s_block_size, spb.s_block_size); 442 | for (unsigned int j = 0; j < spb.s_block_size / sizeof(int) && length < cur_inode.i_size; j++) 443 | { 444 | int* one_time_indirect_index = new int[spb.s_block_size / sizeof(int)]{ 0 }; 445 | buffer.bread((char*)one_time_indirect_index, spb.s_block_start_addr + two_time_indirect_index[j] * spb.s_block_size, spb.s_block_size); 446 | for (unsigned int k = 0; k < spb.s_block_size / sizeof(int) && length < cur_inode.i_size; k++) 447 | { 448 | if (length + spb.s_block_size < cur_inode.i_size) 449 | { 450 | buffer.bread((char*)filedata + length, spb.s_block_start_addr + one_time_indirect_index[k] * spb.s_block_size, spb.s_block_size); 451 | length += spb.s_block_size; 452 | } 453 | else 454 | { 455 | buffer.bread((char*)filedata + length, spb.s_block_start_addr + one_time_indirect_index[k] * spb.s_block_size, cur_inode.i_size - length); 456 | length = cur_inode.i_size; 457 | } 458 | } 459 | delete[] one_time_indirect_index; 460 | } 461 | delete[] two_time_indirect_index; 462 | } 463 | memcpy_s(buf, len, filedata + start_addr, len); 464 | delete[] filedata; 465 | cur_inode.i_atime = unsigned int(time(NULL)); 466 | } 467 | void FS::_fwrite(Inode& cur_inode, const char* buf, unsigned int start_addr, unsigned int len) 468 | { 469 | if (int(start_addr + len) > spb.file_max_size) 470 | { 471 | throw("写文件过大\n"); 472 | } 473 | unsigned int new_size = int(start_addr + len) > cur_inode.i_size ? start_addr + len : cur_inode.i_size; 474 | char* filedata = new char[new_size + 1]{ 0 }; 475 | _fread(cur_inode, filedata, 0, cur_inode.i_size); 476 | if (start_addr > cur_inode.i_size) 477 | { 478 | memset(filedata + cur_inode.i_size, 0, start_addr - cur_inode.i_size); 479 | } 480 | memcpy_s(filedata + start_addr, len, buf, len); 481 | 482 | int last_block_num = (cur_inode.i_size + spb.s_block_size - 1) / spb.s_block_size; 483 | int cur_block_num = (new_size + spb.s_block_size - 1) / spb.s_block_size; 484 | int block_count = 0; 485 | for (unsigned int i = 0; i < 6 && block_count < cur_block_num; i++) 486 | { 487 | if (block_count < last_block_num) 488 | { 489 | block_count++; 490 | } 491 | else 492 | { 493 | int block_no = balloc(); 494 | cur_inode.i_addr[i] = block_no; 495 | block_count++; 496 | } 497 | } 498 | for (unsigned int i = 6; i < 8 && block_count < cur_block_num; i++) 499 | { 500 | int* one_time_indirect_index = new int[spb.s_block_size / sizeof(int)]{ 0 }; 501 | if (block_count < last_block_num) 502 | { 503 | buffer.bread((char*)one_time_indirect_index, spb.s_block_start_addr + cur_inode.i_addr[i] * spb.s_block_size, spb.s_block_size); 504 | } 505 | else 506 | { 507 | int block_no = balloc(); 508 | cur_inode.i_addr[i] = block_no; 509 | } 510 | for (unsigned int j = 0; j < spb.s_block_size / sizeof(int) && block_count < cur_block_num; j++) 511 | { 512 | if (block_count < last_block_num) 513 | { 514 | block_count++; 515 | } 516 | else 517 | { 518 | int block_no = balloc(); 519 | one_time_indirect_index[j] = block_no; 520 | block_count++; 521 | } 522 | } 523 | buffer.bwrite((const char*)one_time_indirect_index, spb.s_block_start_addr + cur_inode.i_addr[i] * spb.s_block_size, spb.s_block_size); 524 | delete[] one_time_indirect_index; 525 | } 526 | for (unsigned int i = 8; i < 10 && block_count < cur_block_num; i++) 527 | { 528 | int* two_time_indirect_index = new int[spb.s_block_size / sizeof(int)]{ 0 }; 529 | if (block_count < last_block_num) 530 | { 531 | buffer.bread((char*)two_time_indirect_index, spb.s_block_start_addr + cur_inode.i_addr[i] * spb.s_block_size, spb.s_block_size); 532 | } 533 | else 534 | { 535 | int block_no = balloc(); 536 | cur_inode.i_addr[i] = block_no; 537 | } 538 | for (unsigned int j = 0; j < spb.s_block_size / sizeof(int) && block_count < cur_block_num; j++) 539 | { 540 | int* one_time_indirect_index = new int[spb.s_block_size / sizeof(int)]{ 0 }; 541 | if (block_count < last_block_num) 542 | { 543 | buffer.bread((char*)one_time_indirect_index, spb.s_block_start_addr + two_time_indirect_index[j] * spb.s_block_size, spb.s_block_size); 544 | } 545 | else 546 | { 547 | int block_no = balloc(); 548 | two_time_indirect_index[j] = block_no; 549 | } 550 | for (unsigned int k = 0; k < spb.s_block_size / sizeof(int) && block_count < cur_block_num; k++) 551 | { 552 | if (block_count < last_block_num) 553 | { 554 | block_count++; 555 | } 556 | else 557 | { 558 | int block_no = balloc(); 559 | one_time_indirect_index[k] = block_no; 560 | block_count++; 561 | } 562 | } 563 | buffer.bwrite((const char*)one_time_indirect_index, spb.s_block_start_addr + two_time_indirect_index[j] * spb.s_block_size, spb.s_block_size); 564 | delete[] one_time_indirect_index; 565 | } 566 | buffer.bwrite((const char*)two_time_indirect_index, spb.s_block_start_addr + cur_inode.i_addr[i] * spb.s_block_size, spb.s_block_size); 567 | delete[] two_time_indirect_index; 568 | } 569 | cur_inode.i_size = new_size; 570 | 571 | unsigned int length = 0; 572 | for (unsigned int i = 0; i < 6 && length < cur_inode.i_size; i++) 573 | { 574 | if (length + spb.s_block_size < cur_inode.i_size) 575 | { 576 | buffer.bwrite((const char*)filedata + length, spb.s_block_start_addr + cur_inode.i_addr[i] * spb.s_block_size, spb.s_block_size); 577 | length += spb.s_block_size; 578 | } 579 | else 580 | { 581 | buffer.bwrite((const char*)filedata + length, spb.s_block_start_addr + cur_inode.i_addr[i] * spb.s_block_size, cur_inode.i_size - length); 582 | length = cur_inode.i_size; 583 | } 584 | } 585 | for (unsigned int i = 6; i < 8 && length < cur_inode.i_size; i++) 586 | { 587 | int* one_time_indirect_index = new int[spb.s_block_size / sizeof(int)]{ 0 }; 588 | buffer.bread((char*)one_time_indirect_index, spb.s_block_start_addr + cur_inode.i_addr[i] * spb.s_block_size, spb.s_block_size); 589 | for (unsigned int j = 0; j < spb.s_block_size / sizeof(int) && length < cur_inode.i_size; j++) 590 | { 591 | if (length + spb.s_block_size < cur_inode.i_size) 592 | { 593 | buffer.bwrite((const char*)filedata + length, spb.s_block_start_addr + one_time_indirect_index[j] * spb.s_block_size, spb.s_block_size); 594 | length += spb.s_block_size; 595 | } 596 | else 597 | { 598 | buffer.bwrite((const char*)filedata + length, spb.s_block_start_addr + one_time_indirect_index[j] * spb.s_block_size, cur_inode.i_size - length); 599 | length = cur_inode.i_size; 600 | } 601 | } 602 | delete[] one_time_indirect_index; 603 | } 604 | for (unsigned int i = 8; i < 10 && length < cur_inode.i_size; i++) 605 | { 606 | int* two_time_indirect_index = new int[spb.s_block_size / sizeof(int)]{ 0 }; 607 | buffer.bread((char*)two_time_indirect_index, spb.s_block_start_addr + cur_inode.i_addr[i] * spb.s_block_size, spb.s_block_size); 608 | for (unsigned int j = 0; j < spb.s_block_size / sizeof(int) && length < cur_inode.i_size; j++) 609 | { 610 | int* one_time_indirect_index = new int[spb.s_block_size / sizeof(int)]{ 0 }; 611 | buffer.bread((char*)one_time_indirect_index, spb.s_block_start_addr + two_time_indirect_index[j] * spb.s_block_size, spb.s_block_size); 612 | for (unsigned int k = 0; k < spb.s_block_size / sizeof(int) && length < cur_inode.i_size; k++) 613 | { 614 | if (length + spb.s_block_size < cur_inode.i_size) 615 | { 616 | buffer.bwrite((const char*)filedata + length, spb.s_block_start_addr + one_time_indirect_index[k] * spb.s_block_size, spb.s_block_size); 617 | length += spb.s_block_size; 618 | } 619 | else 620 | { 621 | buffer.bwrite((const char*)filedata + length, spb.s_block_start_addr + one_time_indirect_index[k] * spb.s_block_size, cur_inode.i_size - length); 622 | length = cur_inode.i_size; 623 | } 624 | } 625 | delete[] one_time_indirect_index; 626 | } 627 | delete[] two_time_indirect_index; 628 | } 629 | delete[] filedata; 630 | if (cur_inode.i_size <= 6 * spb.s_block_size) 631 | { 632 | cur_inode.i_mode &= (~(1 << 12)); 633 | } 634 | else 635 | { 636 | cur_inode.i_mode |= HUGE_FILE; 637 | } 638 | cur_inode.i_atime = unsigned int(time(NULL)); 639 | cur_inode.i_mtime = unsigned int(time(NULL)); 640 | } 641 | void FS::_fdelete(Inode& cur_inode) 642 | { 643 | unsigned int length = 0; 644 | for (unsigned int i = 0; i < 6 && length < cur_inode.i_size; i++) 645 | { 646 | bfree(cur_inode.i_addr[i]); 647 | length += spb.s_block_size; 648 | } 649 | for (unsigned int i = 6; i < 8 && length < cur_inode.i_size; i++) 650 | { 651 | int* one_time_indirect_index = new int[spb.s_block_size / sizeof(int)]{ 0 }; 652 | buffer.bread((char*)one_time_indirect_index, spb.s_block_start_addr + cur_inode.i_addr[i] * spb.s_block_size, spb.s_block_size); 653 | for (unsigned int j = 0; j < spb.s_block_size / sizeof(int) && length < cur_inode.i_size; j++) 654 | { 655 | bfree(one_time_indirect_index[j]); 656 | length += spb.s_block_size; 657 | } 658 | bfree(cur_inode.i_addr[i]); 659 | delete[] one_time_indirect_index; 660 | } 661 | for (unsigned int i = 8; i < 10 && length < cur_inode.i_size; i++) 662 | { 663 | int* two_time_indirect_index = new int[spb.s_block_size / sizeof(int)]{ 0 }; 664 | buffer.bread((char*)two_time_indirect_index, spb.s_block_start_addr + cur_inode.i_addr[i] * spb.s_block_size, spb.s_block_size); 665 | for (unsigned int j = 0; j < spb.s_block_size / sizeof(int) && length < cur_inode.i_size; j++) 666 | { 667 | int* one_time_indirect_index = new int[spb.s_block_size / sizeof(int)]{ 0 }; 668 | buffer.bread((char*)one_time_indirect_index, spb.s_block_start_addr + two_time_indirect_index[j] * spb.s_block_size, spb.s_block_size); 669 | for (unsigned int k = 0; k < spb.s_block_size / sizeof(int) && length < cur_inode.i_size; k++) 670 | { 671 | bfree(one_time_indirect_index[k]); 672 | length += spb.s_block_size; 673 | } 674 | bfree(two_time_indirect_index[j]); 675 | delete[] one_time_indirect_index; 676 | } 677 | bfree(cur_inode.i_addr[i]); 678 | delete[] two_time_indirect_index; 679 | } 680 | cur_inode.i_size = 0; 681 | cur_inode.i_mode &= (~(1 << 12)); 682 | cur_inode.i_atime = unsigned int(time(NULL)); 683 | cur_inode.i_mtime = unsigned int(time(NULL)); 684 | } 685 | void FS::_ddeleteall(Inode& cur_inode) 686 | { 687 | if ((cur_inode.i_mode & (3 << 13)) != DIR_FILE) 688 | { 689 | _fdelete(cur_inode); 690 | } 691 | else 692 | { 693 | DirItem* dir_list = new DirItem[cur_inode.i_size / spb.dir_item_size]{ 0 }; 694 | _fread(cur_inode, (char*)dir_list, 0, cur_inode.i_size); 695 | for (unsigned int i = 0; i < cur_inode.i_size / spb.dir_item_size; i++) 696 | { 697 | if (strcmp(dir_list[i].item_name, ".") == 0 || strcmp(dir_list[i].item_name, "..") == 0) 698 | { 699 | continue; 700 | } 701 | else 702 | { 703 | Inode sub_dir = iload(dir_list[i].inode_no); 704 | _ddeleteall(sub_dir); 705 | ifree(sub_dir); 706 | } 707 | } 708 | _fdelete(cur_inode); 709 | delete[] dir_list; 710 | } 711 | } 712 | void FS::initialize() 713 | { 714 | ifstream fin; 715 | ofstream fout; 716 | fin.open(DISK_NAME, ios::in | ios::binary | ios::_Nocreate); 717 | if (!fin.is_open()) { 718 | 719 | fformat(); 720 | } 721 | } 722 | File* FS::fopen(const char* dir, short uid, short gid) 723 | { 724 | Inode cur_dir = iload(root_dir_no); 725 | vector route = splitstr(dir, "/"); 726 | for (unsigned int i = 0; i < route.size(); i++) 727 | { 728 | cur_dir = _ffind(cur_dir, route[i].data()); 729 | } 730 | 731 | if ((cur_dir.i_mode & (3 << 13)) == DIR_FILE) 732 | { 733 | throw("不能打开目录文件\n"); 734 | } 735 | 736 | File* fp = new File; 737 | Inode* ip = new Inode; 738 | memcpy_s(ip, sizeof(Inode), &cur_dir, sizeof(Inode)); 739 | fp->f_uid = uid; 740 | fp->f_gid = gid; 741 | fp->f_inode = ip; 742 | fp->f_offset = 0; 743 | return fp; 744 | } 745 | int FS::fclose(File* fp) 746 | { 747 | isave(*fp->f_inode); 748 | delete fp->f_inode; 749 | delete fp; 750 | return 0; 751 | } 752 | int FS::fread(char* buffer, int size, int count, File* fp) 753 | { 754 | int file_mode; 755 | if (fp->f_uid == fp->f_inode->i_uid) 756 | { 757 | file_mode = 6; 758 | } 759 | else if (fp->f_gid == fp->f_inode->i_gid) 760 | { 761 | file_mode = 3; 762 | } 763 | else 764 | { 765 | file_mode = 0; 766 | } 767 | if (((fp->f_inode->i_mode >> file_mode) & 4) == 0 && fp->f_uid != 0) 768 | { 769 | throw("权限不足:缺少读权限\n"); 770 | } 771 | int length; 772 | if (int(fp->f_offset + size * count) > fp->f_inode->i_size) 773 | { 774 | length = fp->f_inode->i_size - fp->f_offset; 775 | } 776 | else 777 | { 778 | length = size * count; 779 | } 780 | _fread(*fp->f_inode, buffer, fp->f_offset, length); 781 | fp->f_offset += length; 782 | return length/size; 783 | } 784 | int FS::fwrite(const char* buffer, int size, int count, File* fp) 785 | { 786 | int file_mode; 787 | if (fp->f_uid == fp->f_inode->i_uid) 788 | { 789 | file_mode = 6; 790 | } 791 | else if (fp->f_gid == fp->f_inode->i_gid) 792 | { 793 | file_mode = 3; 794 | } 795 | else 796 | { 797 | file_mode = 0; 798 | } 799 | if (((fp->f_inode->i_mode >> file_mode) & 2) == 0 && fp->f_uid != 0) 800 | { 801 | throw("权限不足:缺少写权限\n"); 802 | } 803 | _fwrite(*fp->f_inode, buffer, fp->f_offset, size * count); 804 | fp->f_offset += size * count; 805 | return count; 806 | } 807 | int FS::freplace(const char* buffer, int size, int count, File* fp) 808 | { 809 | int file_mode; 810 | if (fp->f_uid == fp->f_inode->i_uid) 811 | { 812 | file_mode = 6; 813 | } 814 | else if (fp->f_gid == fp->f_inode->i_gid) 815 | { 816 | file_mode = 3; 817 | } 818 | else 819 | { 820 | file_mode = 0; 821 | } 822 | if (((fp->f_inode->i_mode >> file_mode) & 2) == 0 && fp->f_uid != 0) 823 | { 824 | throw("权限不足:缺少写权限\n"); 825 | } 826 | char* data = new char[fp->f_inode->i_size + 1]{ 0 }; 827 | _fread(*fp->f_inode, data, 0, fp->f_inode->i_size); 828 | _fdelete(*fp->f_inode); 829 | char* new_data = new char[fp->f_offset + size * count + 1]{ 0 }; 830 | memcpy_s(new_data, fp->f_offset, data, fp->f_offset); 831 | memcpy_s(new_data + fp->f_offset, size * count, buffer, size * count); 832 | _fwrite(*fp->f_inode, new_data, 0, fp->f_offset + size * count); 833 | delete[] data; 834 | delete[] new_data; 835 | fp->f_offset += size * count; 836 | return size * count; 837 | } 838 | int FS::fcreate(const char* dir, short uid, short gid) 839 | { 840 | vector route = splitstr(dir, "/"); 841 | string fname = route[route.size() - 1]; 842 | if (fname.size() > spb.name_max_size) 843 | { 844 | throw("新增文件名超过最大长度\n"); 845 | } 846 | 847 | Inode cur_dir = iload(root_dir_no); 848 | for (unsigned int i = 0; i < route.size() - 1; i++) 849 | { 850 | cur_dir = _ffind(cur_dir, route[i].data()); 851 | } 852 | 853 | 854 | if ((cur_dir.i_mode & (3 << 13)) != DIR_FILE) 855 | { 856 | throw("当前路径非目录文件\n"); 857 | } 858 | 859 | int file_mode; 860 | if (uid == cur_dir.i_uid) 861 | { 862 | file_mode = 6; 863 | } 864 | else if (gid == cur_dir.i_gid) 865 | { 866 | file_mode = 3; 867 | } 868 | else 869 | { 870 | file_mode = 0; 871 | } 872 | if (((cur_dir.i_mode >> file_mode) & 2) == 0 && uid != 0) 873 | { 874 | throw("权限不足:缺少写权限\n"); 875 | } 876 | 877 | if (cur_dir.i_size >= spb.file_max_size) 878 | { 879 | throw("当前路径目录项已写满\n"); 880 | } 881 | 882 | DirItem* dir_list = new DirItem[cur_dir.i_size / spb.dir_item_size]{ 0 }; 883 | _fread(cur_dir, (char*)dir_list, 0, cur_dir.i_size); 884 | for (unsigned int i = 0; i < cur_dir.i_size / spb.dir_item_size; i++) 885 | { 886 | if (string(dir_list[i].item_name) == fname) 887 | { 888 | throw("当前路径下已有该文件名\n"); 889 | } 890 | } 891 | delete[] dir_list; 892 | 893 | Inode new_inode = ialloc(); 894 | new_inode.i_mode = IALLOC | NORMAL_DATA_FILE | SMALL_FILE | FILE_DEF_PERMISSION; 895 | new_inode.i_nlink = 1; 896 | new_inode.i_uid = uid; 897 | new_inode.i_gid = gid; 898 | new_inode.i_size = 0; 899 | new_inode.i_mtime = unsigned int(time(NULL)); 900 | new_inode.i_atime = unsigned int(time(NULL)); 901 | isave(new_inode); 902 | 903 | DirItem new_dir; 904 | strcpy_s(new_dir.item_name, fname.data()); 905 | new_dir.inode_no = new_inode.i_no; 906 | _fwrite(cur_dir, (const char*)&new_dir, cur_dir.i_size, spb.dir_item_size); 907 | isave(cur_dir); 908 | 909 | return 0; 910 | } 911 | int FS::fdelete(const char* dir, short uid, short gid) 912 | { 913 | vector route = splitstr(dir, "/"); 914 | string fname = route[route.size() - 1]; 915 | 916 | Inode cur_dir = iload(root_dir_no); 917 | for (unsigned int i = 0; i < route.size() - 1; i++) 918 | { 919 | cur_dir = _ffind(cur_dir, route[i].data()); 920 | } 921 | 922 | if ((cur_dir.i_mode & (3 << 13)) != DIR_FILE) 923 | { 924 | throw("当前路径非目录文件\n"); 925 | } 926 | 927 | int file_mode; 928 | if (uid == cur_dir.i_uid) 929 | { 930 | file_mode = 6; 931 | } 932 | else if (gid == cur_dir.i_gid) 933 | { 934 | file_mode = 3; 935 | } 936 | else 937 | { 938 | file_mode = 0; 939 | } 940 | if (((cur_dir.i_mode >> file_mode) & 2) == 0 && uid != 0) 941 | { 942 | throw("权限不足:缺少写权限\n"); 943 | } 944 | 945 | DirItem* dir_list = new DirItem[cur_dir.i_size / spb.dir_item_size]{ 0 }; 946 | _fread(cur_dir, (char*)dir_list, 0, cur_dir.i_size); 947 | int fno = -1; 948 | int pos = -1; 949 | for (unsigned int i = 0; i < cur_dir.i_size / spb.dir_item_size; i++) 950 | { 951 | if (string(dir_list[i].item_name) == fname) 952 | { 953 | fno = dir_list[i].inode_no; 954 | pos = i; 955 | break; 956 | } 957 | } 958 | if (pos == -1) 959 | { 960 | throw("找不到该文件\n"); 961 | } 962 | Inode finode = iload(fno); 963 | 964 | if ((finode.i_mode & (3 << 13)) == DIR_FILE) 965 | { 966 | delete[] dir_list; 967 | throw("该文件是目录文件,不能用fdelete删除\n"); 968 | } 969 | 970 | _fdelete(finode); 971 | ifree(finode); 972 | 973 | unsigned int old_size = cur_dir.i_size; 974 | _fdelete(cur_dir); 975 | for (unsigned int i = pos; i < old_size / spb.dir_item_size - 1; i++) 976 | { 977 | dir_list[i] = dir_list[i + 1]; 978 | } 979 | _fwrite(cur_dir, (const char*)dir_list, 0, old_size - spb.dir_item_size); 980 | delete[] dir_list; 981 | isave(cur_dir); 982 | return 0; 983 | } 984 | int FS::fseek(File* fp, int offset, int whence) 985 | { 986 | if (whence == SEEK_SET) 987 | { 988 | fp->f_offset = offset; 989 | } 990 | else if (whence == SEEK_CUR) 991 | { 992 | fp->f_offset = fp->f_offset + offset; 993 | } 994 | else 995 | { 996 | fp->f_offset = fp->f_inode->i_size - 1 + offset; 997 | } 998 | return 0; 999 | } 1000 | int FS::ftell(File* fp) 1001 | { 1002 | return fp->f_offset; 1003 | } 1004 | int FS::dcreate(const char* dir, short uid, short gid) 1005 | { 1006 | vector route = splitstr(dir, "/"); 1007 | string fname = route[route.size() - 1]; 1008 | if (fname.size() > spb.name_max_size) 1009 | { 1010 | throw("新增目录名超过最大长度\n"); 1011 | } 1012 | 1013 | Inode cur_dir = iload(root_dir_no); 1014 | for (unsigned int i = 0; i < route.size() - 1; i++) 1015 | { 1016 | cur_dir = _ffind(cur_dir, route[i].data()); 1017 | } 1018 | 1019 | if ((cur_dir.i_mode & (3 << 13)) != DIR_FILE) 1020 | { 1021 | throw("当前路径非目录文件\n"); 1022 | } 1023 | 1024 | int file_mode; 1025 | if (uid == cur_dir.i_uid) 1026 | { 1027 | file_mode = 6; 1028 | } 1029 | else if (gid == cur_dir.i_gid) 1030 | { 1031 | file_mode = 3; 1032 | } 1033 | else 1034 | { 1035 | file_mode = 0; 1036 | } 1037 | if (((cur_dir.i_mode >> file_mode) & 2) == 0 && uid != 0) 1038 | { 1039 | throw("权限不足:缺少写权限\n"); 1040 | } 1041 | 1042 | if (cur_dir.i_size >= spb.file_max_size) 1043 | { 1044 | throw("当前路径目录项已写满\n"); 1045 | } 1046 | 1047 | DirItem* dir_list = new DirItem[cur_dir.i_size / spb.dir_item_size]{ 0 }; 1048 | _fread(cur_dir, (char*)dir_list, 0, cur_dir.i_size); 1049 | for (unsigned int i = 0; i < cur_dir.i_size / spb.dir_item_size; i++) 1050 | { 1051 | if (string(dir_list[i].item_name) == fname) 1052 | { 1053 | throw("当前路径下已有该目录名\n"); 1054 | } 1055 | } 1056 | delete[] dir_list; 1057 | 1058 | Inode new_dir = ialloc(); 1059 | new_dir.i_mode = IALLOC | DIR_FILE | SMALL_FILE | DIR_DEF_PERMISSION; 1060 | new_dir.i_nlink = 1; 1061 | new_dir.i_uid = uid; 1062 | new_dir.i_gid = gid; 1063 | new_dir.i_size = 0; 1064 | new_dir.i_mtime = unsigned int(time(NULL)); 1065 | new_dir.i_atime = unsigned int(time(NULL)); 1066 | 1067 | DirItem* new_dir_list = new DirItem[2]{ 0 }; 1068 | strcpy_s(new_dir_list[0].item_name, "."); 1069 | new_dir_list[0].inode_no = new_dir.i_no; 1070 | strcpy_s(new_dir_list[1].item_name, ".."); 1071 | new_dir_list[1].inode_no = cur_dir.i_no; 1072 | _fwrite(new_dir, (const char*)new_dir_list, 0, 2 * spb.dir_item_size); 1073 | delete[] new_dir_list; 1074 | isave(new_dir); 1075 | 1076 | DirItem new_item; 1077 | strcpy_s(new_item.item_name, fname.data()); 1078 | new_item.inode_no = new_dir.i_no; 1079 | cur_dir.i_nlink++; 1080 | _fwrite(cur_dir, (const char*)&new_item, cur_dir.i_size, spb.dir_item_size); 1081 | isave(cur_dir); 1082 | return 0; 1083 | } 1084 | int FS::ddelete(const char* dir, short uid, short gid) 1085 | { 1086 | vector route = splitstr(dir, "/"); 1087 | string fname = route[route.size() - 1]; 1088 | 1089 | Inode cur_dir = iload(root_dir_no); 1090 | for (unsigned int i = 0; i < route.size() - 1; i++) 1091 | { 1092 | cur_dir = _ffind(cur_dir, route[i].data()); 1093 | } 1094 | 1095 | if ((cur_dir.i_mode & (3 << 13)) != DIR_FILE) 1096 | { 1097 | throw("当前路径非目录文件\n"); 1098 | } 1099 | 1100 | if (fname == "." || fname == "..") 1101 | { 1102 | throw("不能对本目录或上级目录执行删除操作\n"); 1103 | } 1104 | 1105 | int file_mode; 1106 | if (uid == cur_dir.i_uid) 1107 | { 1108 | file_mode = 6; 1109 | } 1110 | else if (gid == cur_dir.i_gid) 1111 | { 1112 | file_mode = 3; 1113 | } 1114 | else 1115 | { 1116 | file_mode = 0; 1117 | } 1118 | if (((cur_dir.i_mode >> file_mode) & 2) == 0 && uid != 0) 1119 | { 1120 | throw("权限不足:缺少写权限\n"); 1121 | } 1122 | 1123 | DirItem* dir_list = new DirItem[cur_dir.i_size / spb.dir_item_size]{ 0 }; 1124 | _fread(cur_dir, (char*)dir_list, 0, cur_dir.i_size); 1125 | int fno = -1; 1126 | int pos = -1; 1127 | for (unsigned int i = 0; i < int(cur_dir.i_size / spb.dir_item_size); i++) 1128 | { 1129 | if (string(dir_list[i].item_name) == fname) 1130 | { 1131 | fno = dir_list[i].inode_no; 1132 | pos = i; 1133 | break; 1134 | } 1135 | } 1136 | if (pos == -1) 1137 | { 1138 | throw("找不到该目录\n"); 1139 | } 1140 | Inode finode = iload(fno); 1141 | if ((finode.i_mode & (3 << 13)) != DIR_FILE) 1142 | { 1143 | throw("该文件是非目录文件,不能用ddelete删除\n"); 1144 | } 1145 | // 删除目录 1146 | _ddeleteall(finode); 1147 | ifree(finode); 1148 | // 更新目录 1149 | unsigned int old_size = cur_dir.i_size; 1150 | _fdelete(cur_dir); 1151 | cur_dir.i_nlink--; 1152 | for (unsigned int i = pos; i < old_size / spb.dir_item_size - 1; i++) 1153 | { 1154 | dir_list[i] = dir_list[i + 1]; 1155 | } 1156 | _fwrite(cur_dir, (const char*)dir_list, 0, old_size - spb.dir_item_size); 1157 | delete[] dir_list; 1158 | isave(cur_dir); 1159 | return 0; 1160 | } 1161 | int FS::chmod(const char* dir, int mode, short uid, short gid) 1162 | { 1163 | Inode cur_dir = iload(root_dir_no); 1164 | vector route = splitstr(dir, "/"); 1165 | for (unsigned int i = 0; i < route.size(); i++) 1166 | { 1167 | cur_dir = _ffind(cur_dir, route[i].data()); 1168 | } 1169 | if (uid != cur_dir.i_uid && uid != 0) { 1170 | throw("权限不足\n"); 1171 | } 1172 | cur_dir.i_mode = (cur_dir.i_mode >> 9 << 9) | mode; //修改权限 1173 | isave(cur_dir); 1174 | return 0; 1175 | } 1176 | vector FS::list(const char* dir, short uid, short gid) 1177 | { 1178 | vectorret_list; 1179 | Inode cur_dir = iload(root_dir_no); 1180 | vector route = splitstr(dir, "/"); 1181 | for (unsigned int i = 0; i < route.size(); i++) 1182 | { 1183 | cur_dir = _ffind(cur_dir, route[i].data()); 1184 | } 1185 | if ((cur_dir.i_mode & (3 << 13)) != DIR_FILE) 1186 | { 1187 | throw("当前路径非目录文件\n"); 1188 | } 1189 | 1190 | int file_mode; 1191 | if (uid == cur_dir.i_uid) 1192 | { 1193 | file_mode = 6; 1194 | } 1195 | else if (gid == cur_dir.i_gid) 1196 | { 1197 | file_mode = 3; 1198 | } 1199 | else 1200 | { 1201 | file_mode = 0; 1202 | } 1203 | 1204 | if (((cur_dir.i_mode >> file_mode) & 4) == 0 && uid != 0) 1205 | { 1206 | throw("权限不足:缺少读权限\n"); 1207 | } 1208 | 1209 | DirItem* dir_list = new DirItem[cur_dir.i_size / spb.dir_item_size]{ 0 }; 1210 | _fread(cur_dir, (char*)dir_list, 0, cur_dir.i_size); 1211 | for (unsigned int i = 0; i < cur_dir.i_size / spb.dir_item_size; i++) 1212 | { 1213 | Inode sub_inode = iload(dir_list[i].inode_no); 1214 | 1215 | string mode; 1216 | if (((sub_inode.i_mode >> 13) & 3) == 0) 1217 | { 1218 | mode += "-"; 1219 | } 1220 | else if (((sub_inode.i_mode >> 13) & 3) == 1) 1221 | { 1222 | mode += "c"; 1223 | } 1224 | else if (((sub_inode.i_mode >> 13) & 3) == 2) 1225 | { 1226 | mode += "d"; 1227 | } 1228 | else if (((sub_inode.i_mode >> 13) & 3) == 3) 1229 | { 1230 | mode += "b"; 1231 | } 1232 | for (int t = 8; t >= 0; t--) 1233 | { 1234 | if (((sub_inode.i_mode >> t) & 1) == 1) 1235 | { 1236 | if (t % 3 == 2) 1237 | { 1238 | mode += "r"; 1239 | } 1240 | else if (t % 3 == 1) 1241 | { 1242 | mode += "w"; 1243 | } 1244 | else if (t % 3 == 0) 1245 | { 1246 | mode += "x"; 1247 | } 1248 | } 1249 | else 1250 | { 1251 | mode += "-"; 1252 | } 1253 | } 1254 | tm stdT; //存储时间 1255 | time_t time = sub_inode.i_mtime; 1256 | localtime_s(&stdT, (const time_t*)&time); 1257 | 1258 | string uname; 1259 | string gname; 1260 | File* user; 1261 | user = fopen("/etc/users.txt"); 1262 | char* data = new char[user->f_inode->i_size + 1]{ 0 }; 1263 | fread(data, user->f_inode->i_size, 1, user); 1264 | string fsrd = data; 1265 | delete[] data; 1266 | fclose(user); 1267 | vector users; 1268 | users = splitstr(fsrd, "\n"); 1269 | for (unsigned int i = 0; i < users.size(); i++) 1270 | { 1271 | vectorumsg = splitstr(users[i], "-"); 1272 | if (stoi(umsg[2]) == sub_inode.i_uid) 1273 | { 1274 | uname = umsg[0]; 1275 | break; 1276 | } 1277 | } 1278 | 1279 | File* group; 1280 | group = fopen("/etc/groups.txt"); 1281 | char* gdata = new char[group->f_inode->i_size + 1]{ 0 }; 1282 | fread(gdata, group->f_inode->i_size, 1, group); 1283 | string gstrdata = gdata; 1284 | delete[] gdata; 1285 | fclose(group); 1286 | vector groups; 1287 | groups = splitstr(gstrdata, "\n"); 1288 | for (unsigned int j = 0; j < groups.size(); j++) 1289 | { 1290 | vectorgmsg = splitstr(groups[j], "-"); 1291 | if (stoi(gmsg[1]) == sub_inode.i_gid) 1292 | { 1293 | gname = gmsg[0]; 1294 | break; 1295 | } 1296 | } 1297 | 1298 | char buf[128]; 1299 | sprintf_s(buf, "%10s %-5d %-7s %-7s %d B\t%d.%d.%d %02d:%02d:%02d %-28s\n", mode.data(), sub_inode.i_nlink, uname.data(), gname.data(), sub_inode.i_size, 1900 + stdT.tm_year, stdT.tm_mon + 1, stdT.tm_mday, stdT.tm_hour, stdT.tm_min, stdT.tm_sec, dir_list[i].item_name); 1300 | ret_list.push_back(string(buf)); 1301 | } 1302 | delete[] dir_list; 1303 | return ret_list; 1304 | } 1305 | int FS::enter(const char* dir, short uid, short gid) 1306 | { 1307 | Inode cur_dir = iload(root_dir_no); 1308 | vector route = splitstr(dir, "/"); 1309 | for (unsigned int i = 0; i < route.size(); i++) 1310 | { 1311 | int file_mode; 1312 | if (uid == cur_dir.i_uid) 1313 | { 1314 | file_mode = 6; 1315 | } 1316 | else if (gid == cur_dir.i_gid) 1317 | { 1318 | file_mode = 3; 1319 | } 1320 | else 1321 | { 1322 | file_mode = 0; 1323 | } 1324 | if (((cur_dir.i_mode >> file_mode) & 1) == 0 && uid != 0) 1325 | { 1326 | throw("权限不足:缺少执行权限\n"); 1327 | } 1328 | cur_dir = _ffind(cur_dir, route[i].data()); 1329 | } 1330 | int file_mode; 1331 | if (uid == cur_dir.i_uid) 1332 | { 1333 | file_mode = 6; 1334 | } 1335 | else if (gid == cur_dir.i_gid) 1336 | { 1337 | file_mode = 3; 1338 | } 1339 | else 1340 | { 1341 | file_mode = 0; 1342 | } 1343 | if (((cur_dir.i_mode >> file_mode) & 1) == 0 && uid != 0) 1344 | { 1345 | throw("权限不足:缺少执行权限\n"); 1346 | } 1347 | if ((cur_dir.i_mode & (3 << 13)) != DIR_FILE) 1348 | { 1349 | throw("目标路径非目录文件\n"); 1350 | } 1351 | return 0; 1352 | } 1353 | int FS::fformat() 1354 | { 1355 | //创建新的磁盘卷 1356 | ofstream fout; 1357 | fout.open(DISK_NAME, ios::out | ios::binary); 1358 | if (!fout.is_open()) { 1359 | throw("磁盘映像输出文件流打开失败\n"); 1360 | } 1361 | fout.seekp(DISK_SIZE - 1, ios::beg); 1362 | fout.write("", sizeof(char)); 1363 | fout.close(); 1364 | //格式化superblock 1365 | spb.s_superblock_start_addr = SUPER_BLOCK_START_ADDR; 1366 | spb.s_superblock_size = 2 * BLOCK_SIZE; 1367 | spb.s_inode_start_addr = spb.s_superblock_start_addr + spb.s_superblock_size; 1368 | spb.s_inode_size = 64; 1369 | spb.s_inode_num = (1024 - 200 - 2) * BLOCK_SIZE / spb.s_inode_size; 1370 | spb.s_inode_fnum = spb.s_inode_num; 1371 | spb.s_block_start_addr = spb.s_inode_start_addr + spb.s_inode_num * spb.s_inode_size; 1372 | spb.s_block_size = BLOCK_SIZE; 1373 | spb.s_block_num = DISK_SIZE / BLOCK_SIZE - 1024; 1374 | spb.s_block_fnum = spb.s_block_num; 1375 | 1376 | spb.s_ninode = 0; 1377 | for (int i = 99; i >= 0; i--) 1378 | { 1379 | spb.s_inode[spb.s_ninode++] = i; 1380 | } 1381 | spb.s_ilock = 0; 1382 | 1383 | spb.s_nfree = 1; 1384 | memset(spb.s_free, 0, sizeof(spb.s_free)); 1385 | spb.s_free[0] = 0; 1386 | for (int i = spb.s_block_num - 1; i >= 0; i--) 1387 | { 1388 | int cur_block_address = spb.s_block_start_addr + i * spb.s_block_size; 1389 | if (spb.s_nfree == 100) 1390 | { 1391 | buffer.bwrite((const char*)&spb.s_nfree, cur_block_address, sizeof(spb.s_nfree)); 1392 | buffer.bwrite((const char*)spb.s_free, cur_block_address + int(sizeof(spb.s_nfree)), sizeof(spb.s_free)); 1393 | spb.s_nfree = 0; 1394 | memset(spb.s_free, 0, sizeof(spb.s_free)); 1395 | } 1396 | spb.s_free[spb.s_nfree++] = i; 1397 | } 1398 | 1399 | spb.file_max_size = (6 + 128 * 2 + 128 * 128 * 2) * spb.s_block_size; 1400 | spb.name_max_size = 28; 1401 | spb.dir_item_size = 32; 1402 | spb.dir_list_num = spb.s_block_size / spb.dir_item_size; 1403 | buffer.bwrite((const char*)&spb, spb.s_superblock_start_addr, sizeof(spb)); 1404 | 1405 | Inode root = ialloc(); 1406 | int block_no = balloc(); 1407 | DirItem* dir_list = new DirItem[spb.dir_list_num]{ 0 }; 1408 | strcpy_s(dir_list[0].item_name, "."); 1409 | dir_list[0].inode_no = root.i_no; 1410 | buffer.bwrite((const char*)dir_list, spb.s_block_start_addr + block_no * spb.s_block_size, spb.s_block_size); 1411 | delete[] dir_list; 1412 | 1413 | root.i_mode = IALLOC | DIR_FILE | SMALL_FILE | DIR_DEF_PERMISSION; 1414 | root.i_nlink = 1; 1415 | root.i_uid = 0; 1416 | root.i_gid = 0; 1417 | root.i_size = spb.dir_item_size; 1418 | root.i_addr[0] = block_no; 1419 | root.i_atime = unsigned int(time(NULL)); 1420 | root.i_mtime = unsigned int(time(NULL)); 1421 | isave(root); 1422 | 1423 | dcreate("/bin"); 1424 | dcreate("/etc"); 1425 | dcreate("/home"); 1426 | dcreate("/dev"); 1427 | 1428 | fcreate("/etc/users.txt"); 1429 | File* user = fopen("/etc/users.txt"); 1430 | string users_data = "root-root-0-0\n";//name-passwd-uid-gid 1431 | fwrite(users_data.data(), users_data.length(), 1, user); 1432 | fclose(user); 1433 | chmod("/etc/users.txt", 0660); 1434 | 1435 | fcreate("/etc/groups.txt"); 1436 | File* group = fopen("/etc/groups.txt"); 1437 | string groups_data = "root-0-0\n";//name-gid-uid,uid... 1438 | fwrite(groups_data.data(), groups_data.length(), 1, group); 1439 | fclose(group); 1440 | 1441 | buffer.bwrite((const char*)&spb, spb.s_superblock_start_addr, sizeof(spb)); 1442 | return 0; 1443 | } 1444 | SuperBlock FS::getSpb() 1445 | { 1446 | return spb; 1447 | } 1448 | FS::FS() 1449 | { 1450 | initialize(); 1451 | buffer.bread((char*)&spb, SUPER_BLOCK_START_ADDR, sizeof(SuperBlock)); 1452 | } 1453 | FS::~FS() 1454 | { 1455 | buffer.bwrite((const char*)&spb, spb.s_superblock_start_addr, sizeof(SuperBlock)); 1456 | } 1457 | --------------------------------------------------------------------------------