├── .gitattributes ├── .gitignore ├── fs.sln ├── fs ├── fs.vcxproj ├── fs.vcxproj.filters └── main.cpp └── readme.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | [Xx]64/ 19 | [Xx]86/ 20 | [Bb]uild/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | 143 | # TODO: Un-comment the next line if you do not want to checkin 144 | # your web deploy settings because they may include unencrypted 145 | # passwords 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | # NuGet v3's project.json files produces more ignoreable files 158 | *.nuget.props 159 | *.nuget.targets 160 | 161 | # Microsoft Azure Build Output 162 | csx/ 163 | *.build.csdef 164 | 165 | # Microsoft Azure Emulator 166 | ecf/ 167 | rcf/ 168 | 169 | # Microsoft Azure ApplicationInsights config file 170 | ApplicationInsights.config 171 | 172 | # Windows Store app package directory 173 | AppPackages/ 174 | BundleArtifacts/ 175 | 176 | # Visual Studio cache files 177 | # files ending in .cache can be ignored 178 | *.[Cc]ache 179 | # but keep track of directories ending in .cache 180 | !*.[Cc]ache/ 181 | 182 | # Others 183 | ClientBin/ 184 | [Ss]tyle[Cc]op.* 185 | ~$* 186 | *~ 187 | *.dbmdl 188 | *.dbproj.schemaview 189 | *.pfx 190 | *.publishsettings 191 | node_modules/ 192 | orleans.codegen.cs 193 | 194 | # RIA/Silverlight projects 195 | Generated_Code/ 196 | 197 | # Backup & report files from converting an old project file 198 | # to a newer Visual Studio version. Backup files are not needed, 199 | # because we have git ;-) 200 | _UpgradeReport_Files/ 201 | Backup*/ 202 | UpgradeLog*.XML 203 | UpgradeLog*.htm 204 | 205 | # SQL Server files 206 | *.mdf 207 | *.ldf 208 | 209 | # Business Intelligence projects 210 | *.rdl.data 211 | *.bim.layout 212 | *.bim_*.settings 213 | 214 | # Microsoft Fakes 215 | FakesAssemblies/ 216 | 217 | # GhostDoc plugin setting file 218 | *.GhostDoc.xml 219 | 220 | # Node.js Tools for Visual Studio 221 | .ntvs_analysis.dat 222 | 223 | # Visual Studio 6 build log 224 | *.plg 225 | 226 | # Visual Studio 6 workspace options file 227 | *.opt 228 | 229 | # Visual Studio LightSwitch build output 230 | **/*.HTMLClient/GeneratedArtifacts 231 | **/*.DesktopClient/GeneratedArtifacts 232 | **/*.DesktopClient/ModelManifest.xml 233 | **/*.Server/GeneratedArtifacts 234 | **/*.Server/ModelManifest.xml 235 | _Pvt_Extensions 236 | 237 | # LightSwitch generated files 238 | GeneratedArtifacts/ 239 | ModelManifest.xml 240 | 241 | # Paket dependency manager 242 | .paket/paket.exe 243 | 244 | # FAKE - F# Make 245 | .fake/ -------------------------------------------------------------------------------- /fs.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fs", "fs\fs.vcxproj", "{52E9824C-7532-43AA-BE3B-B2CB3C552C6B}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {52E9824C-7532-43AA-BE3B-B2CB3C552C6B}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {52E9824C-7532-43AA-BE3B-B2CB3C552C6B}.Debug|Win32.Build.0 = Debug|Win32 14 | {52E9824C-7532-43AA-BE3B-B2CB3C552C6B}.Release|Win32.ActiveCfg = Release|Win32 15 | {52E9824C-7532-43AA-BE3B-B2CB3C552C6B}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /fs/fs.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | 15 | 16 | 17 | {52E9824C-7532-43AA-BE3B-B2CB3C552C6B} 18 | Win32Proj 19 | fs 20 | 21 | 22 | 23 | Application 24 | true 25 | Unicode 26 | 27 | 28 | Application 29 | false 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | true 45 | 46 | 47 | false 48 | 49 | 50 | 51 | 52 | 53 | Level3 54 | Disabled 55 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 56 | Default 57 | 58 | 59 | Console 60 | true 61 | 62 | 63 | 64 | 65 | Level3 66 | 67 | 68 | MaxSpeed 69 | true 70 | true 71 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 72 | 73 | 74 | Console 75 | true 76 | true 77 | true 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /fs/fs.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;hpp;hxx;hm;inl;inc;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 | -------------------------------------------------------------------------------- /fs/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Randolph Han, Zhejiang University of Technologic, China 3 | * All rights reserved. 4 | * Project name:Simple File System 5 | * Programmer:Randolph Han 6 | * Finish:2016.12.10 7 | * 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include //windows中用于不回显字符 16 | //#include //Linux下用于自定义不回显字符 17 | //#include //Linux下用于自定义不回显字符 18 | #include 19 | #include 20 | #include 21 | 22 | using namespace std; 23 | /* 24 | // Linux下增加代码(自定义不回显字符) 25 | int getch() 26 | { 27 | int c = 0; 28 | struct termios org_opts, new_opts; 29 | int res = 0; 30 | //----- store old settings ----------- 31 | res = tcgetattr(STDIN_FILENO, &org_opts); 32 | assert(res == 0); 33 | //---- set new terminal parms -------- 34 | memcpy(&new_opts, &org_opts, sizeof(new_opts)); 35 | new_opts.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT | ECHOKE | ICRNL); 36 | tcsetattr(STDIN_FILENO, TCSANOW, &new_opts); 37 | c = getchar(); 38 | //------ restore old settings --------- 39 | res = tcsetattr(STDIN_FILENO, TCSANOW, &org_opts); 40 | assert(res == 0); 41 | if(c == '\n') c = '\r'; 42 | else if(c == 127) c = '\b'; 43 | return c; 44 | } 45 | */ 46 | 47 | //Constant variables. 48 | /* 49 | * The maximum number of blocks a file can use. 50 | * Used in struct inode. 51 | */ 52 | const unsigned int NADDR = 6; 53 | /* 54 | * Size of a block. 55 | */ 56 | const unsigned short BLOCK_SIZE = 512; 57 | /* 58 | * The maximum size of a file. 59 | */ 60 | const unsigned int FILE_SIZE_MAX = (NADDR - 2) * BLOCK_SIZE + BLOCK_SIZE / sizeof(int) * BLOCK_SIZE; 61 | /* 62 | * The maximum number of data blocks. 63 | */ 64 | const unsigned short BLOCK_NUM = 512; 65 | /* 66 | * Size of an inode. 67 | */ 68 | const unsigned short INODE_SIZE = 128; 69 | /* 70 | * The maximum number of inodes. 71 | */ 72 | const unsigned short INODE_NUM = 256; 73 | /* 74 | * The start position of inode chain. 75 | * First four blocks are used for loader sector(empty in this program), super block, inode bitmap and block bitmap. 76 | */ 77 | const unsigned int INODE_START = 3 * BLOCK_SIZE; 78 | /* 79 | * The start position of data blocks. 80 | */ 81 | const unsigned int DATA_START = INODE_START + INODE_NUM * INODE_SIZE; 82 | /* 83 | * The maximum number of the file system users. 84 | */ 85 | const unsigned int ACCOUNT_NUM = 10; 86 | /* 87 | * The maximum number of sub-files and sub-directories in one directory. 88 | */ 89 | const unsigned int DIRECTORY_NUM = 16; 90 | /* 91 | * The maximum length of a file name. 92 | */ 93 | const unsigned short FILE_NAME_LENGTH = 14; 94 | /* 95 | * The maximum length of a user's name. 96 | */ 97 | const unsigned short USER_NAME_LENGTH = 14; 98 | /* 99 | * The maximum length of a accouting password. 100 | */ 101 | const unsigned short USER_PASSWORD_LENGTH = 14; 102 | /* 103 | * The maximum permission of a file. 104 | */ 105 | const unsigned short MAX_PERMISSION = 511; 106 | /* 107 | * The maximum permission of a file. 108 | */ 109 | const unsigned short MAX_OWNER_PERMISSION = 448; 110 | /* 111 | * Permission 112 | */ 113 | const unsigned short ELSE_E = 1; 114 | const unsigned short ELSE_W = 1 << 1; 115 | const unsigned short ELSE_R = 1 << 2; 116 | const unsigned short GRP_E = 1 << 3; 117 | const unsigned short GRP_W = 1 << 4; 118 | const unsigned short GRP_R = 1 << 5; 119 | const unsigned short OWN_E = 1 << 6; 120 | const unsigned short OWN_W = 1 << 7; 121 | const unsigned short OWN_R = 1 << 8; 122 | //Data structures. 123 | /* 124 | * inode(128B) 125 | */ 126 | struct inode 127 | { 128 | unsigned int i_ino; //Identification of the inode. 129 | unsigned int di_addr[NADDR];//Number of data blocks where the file stored. 130 | unsigned short di_number; //Number of associated files. 131 | unsigned short di_mode; //0 stands for a directory, 1 stands for a file. 132 | unsigned short icount; //link number 133 | unsigned short permission; //file permission 134 | unsigned short di_uid; //File's user id. 135 | unsigned short di_grp; //File's group id 136 | unsigned short di_size; //File size. 137 | char time[83]; 138 | }; 139 | 140 | /* 141 | * Super block 142 | */ 143 | struct filsys 144 | { 145 | unsigned short s_num_inode; //Total number of inodes. 146 | unsigned short s_num_finode; //Total number of free inodes. 147 | unsigned short s_size_inode; //Size of an inode. 148 | 149 | unsigned short s_num_block; //Total number of blocks. 150 | unsigned short s_num_fblock; //Total number of free blocks. 151 | unsigned short s_size_block; //Size of a block. 152 | 153 | unsigned int special_stack[50]; 154 | int special_free; 155 | }; 156 | 157 | /* 158 | * Directory file(216B) 159 | */ 160 | struct directory 161 | { 162 | char fileName[20][FILE_NAME_LENGTH]; 163 | unsigned int inodeID[DIRECTORY_NUM]; 164 | }; 165 | 166 | /* 167 | * Accouting file(320B) 168 | */ 169 | struct userPsw 170 | { 171 | unsigned short userID[ACCOUNT_NUM]; 172 | char userName[ACCOUNT_NUM][USER_NAME_LENGTH]; 173 | char password[ACCOUNT_NUM][USER_PASSWORD_LENGTH]; 174 | unsigned short groupID[ACCOUNT_NUM]; 175 | }; 176 | 177 | /* 178 | * Function declaritions. 179 | */ 180 | void CommParser(inode*&); 181 | void Help(); 182 | void Sys_start(); 183 | //Globle varibles. 184 | /* 185 | * A descriptor of a file where the file system is emulated. 186 | */ 187 | FILE* fd = NULL; 188 | /* 189 | * Super block. 190 | */ 191 | filsys superBlock; 192 | /* 193 | * Bitmaps for inodes and blocks. Element 1 stands for 'uesd', 0 for 'free'. 194 | */ 195 | unsigned short inode_bitmap[INODE_NUM]; 196 | /* 197 | * Accouting information. 198 | */ 199 | userPsw users; 200 | /* 201 | * current user ID. 202 | */ 203 | unsigned short userID = ACCOUNT_NUM; 204 | /* 205 | * current user name. used in command line. 206 | */ 207 | char userName[USER_NAME_LENGTH + 6]; 208 | /* 209 | * current directory. 210 | */ 211 | directory currentDirectory; 212 | /* 213 | * current directory stack. 214 | */ 215 | char ab_dir[100][14]; 216 | unsigned short dir_pointer; 217 | 218 | //find free block 219 | void find_free_block(unsigned int &inode_number) 220 | { 221 | fseek(fd, BLOCK_SIZE, SEEK_SET); 222 | fread(&superBlock, sizeof(filsys), 1, fd); 223 | if (superBlock.special_free == 0) 224 | { 225 | if (superBlock.special_stack[0] == 0) 226 | { 227 | printf("No value block!\n"); 228 | return; 229 | } 230 | unsigned int stack[51]; 231 | 232 | for (int i = 0; i < 50; i++) 233 | { 234 | stack[i] = superBlock.special_stack[i]; 235 | } 236 | stack[50] = superBlock.special_free; 237 | fseek(fd, DATA_START + (superBlock.special_stack[0] - 50) * BLOCK_SIZE, SEEK_SET); 238 | fwrite(stack, sizeof(stack), 1, fd); 239 | 240 | fseek(fd, DATA_START + superBlock.special_stack[0] * BLOCK_SIZE, SEEK_SET); 241 | fread(stack, sizeof(stack), 1, fd); 242 | for (int i = 0; i < 50; i++) 243 | { 244 | superBlock.special_stack[i] = stack[i]; 245 | } 246 | superBlock.special_free = stack[50]; 247 | } 248 | inode_number = superBlock.special_stack[superBlock.special_free]; 249 | superBlock.special_free--; 250 | superBlock.s_num_fblock--; 251 | fseek(fd, BLOCK_SIZE, SEEK_SET); 252 | fwrite(&superBlock, sizeof(filsys), 1, fd); 253 | } 254 | 255 | //recycle block 256 | void recycle_block(unsigned int &inode_number) 257 | { 258 | fseek(fd, BLOCK_SIZE, SEEK_SET); 259 | fread(&superBlock, sizeof(filsys), 1, fd); 260 | if (superBlock.special_free == 49) 261 | { 262 | unsigned int block_num; 263 | unsigned int stack[51]; 264 | if (superBlock.special_stack[0] == 0) 265 | block_num = 499; 266 | else 267 | block_num = superBlock.special_stack[0] - 50; 268 | for (int i = 0; i < 50; i++) 269 | { 270 | stack[i] = superBlock.special_stack[i]; 271 | } 272 | stack[50] = superBlock.special_free; 273 | fseek(fd, DATA_START + block_num*BLOCK_SIZE, SEEK_SET); 274 | fwrite(stack, sizeof(stack), 1, fd); 275 | block_num -= 50; 276 | fseek(fd, DATA_START + block_num*BLOCK_SIZE, SEEK_SET); 277 | fread(stack, sizeof(stack), 1, fd); 278 | for (int i = 0; i < 50; i++) 279 | { 280 | superBlock.special_stack[i] = stack[i]; 281 | } 282 | superBlock.special_free = stack[50]; 283 | } 284 | superBlock.special_free++; 285 | superBlock.s_num_fblock++; 286 | superBlock.special_stack[superBlock.special_free] = inode_number; 287 | fseek(fd, BLOCK_SIZE, SEEK_SET); 288 | fwrite(&superBlock, sizeof(filsys), 1, fd); 289 | } 290 | 291 | /* 292 | * Formatting function of the file system, including the establishment 293 | * of superblock, inode chain, root directory, password file and so on. 294 | * 295 | * return: the function return true only the file system is initialized 296 | * successfully. 297 | */ 298 | bool Format() 299 | { 300 | /* 301 | * 1. Create a empty file to emulate the file system. 302 | */ 303 | FILE* fd = fopen("./fs.han", "wb+"); 304 | if (fd == NULL) 305 | { 306 | printf("Fail to initialize the file system!\n"); 307 | return false; 308 | } 309 | 310 | /* 311 | * 2. Initialize super block. 312 | */ 313 | filsys superBlock; 314 | superBlock.s_num_inode = INODE_NUM; 315 | superBlock.s_num_block = BLOCK_NUM + 3 + 64; //3代表0空闲块、1超级块、2Inode位示图表,64块存inode 316 | superBlock.s_size_inode = INODE_SIZE; 317 | superBlock.s_size_block = BLOCK_SIZE; 318 | //Root directory and accounting file will use some inodes and blocks. 319 | superBlock.s_num_fblock = BLOCK_NUM - 2; 320 | superBlock.s_num_finode = INODE_NUM - 2; 321 | superBlock.special_stack[0] = 99; 322 | for (int i = 1; i < 50; i++) 323 | { 324 | superBlock.special_stack[i] = 49 - i; 325 | } 326 | superBlock.special_free = 47; 327 | //Write super block into file. 328 | fseek(fd, BLOCK_SIZE, SEEK_SET); 329 | fwrite(&superBlock, sizeof(filsys), 1, fd); 330 | fseek(fd, BLOCK_SIZE, SEEK_SET); 331 | fread(&superBlock, sizeof(filsys), 1, fd); 332 | 333 | /* 334 | * 3. Initialize inode and block bitmaps. 335 | */ 336 | unsigned short inode_bitmap[INODE_NUM]; 337 | //Root directory and accounting file will use some inodes and blocks. 338 | memset(inode_bitmap, 0, INODE_NUM); 339 | inode_bitmap[0] = 1; 340 | inode_bitmap[1] = 1; 341 | //Write bitmaps into file. 342 | fseek(fd, 2 * BLOCK_SIZE, SEEK_SET); 343 | fwrite(inode_bitmap, sizeof(unsigned short) * INODE_NUM, 1, fd); 344 | 345 | //成组连接 346 | unsigned int stack[51]; 347 | for (int i = 0; i < BLOCK_NUM / 50; i++) 348 | { 349 | memset(stack, 0, sizeof(stack)); 350 | for (unsigned int j = 0; j < 50; j++) 351 | { 352 | stack[j] = (49 + i * 50) - j; 353 | } 354 | stack[0] = 49 + (i + 1) * 50; 355 | stack[50] = 49; 356 | fseek(fd, DATA_START + (49 + i * 50)*BLOCK_SIZE, SEEK_SET); 357 | fwrite(stack, sizeof(unsigned int) * 51, 1, fd); 358 | } 359 | memset(stack, 0, sizeof(stack)); 360 | for (int i = 0; i < 12; i++) 361 | { 362 | stack[i] = 511 - i; 363 | } 364 | stack[0] = 0; 365 | stack[50] = 11; 366 | fseek(fd, DATA_START + 511 * BLOCK_SIZE, SEEK_SET); 367 | fwrite(stack, sizeof(unsigned int) * 51, 1, fd); 368 | 369 | fseek(fd, DATA_START + 49 * BLOCK_SIZE, SEEK_SET); 370 | fread(stack, sizeof(unsigned int) * 51, 1, fd); 371 | fseek(fd, DATA_START + 99 * BLOCK_SIZE, SEEK_SET); 372 | fread(stack, sizeof(unsigned int) * 51, 1, fd); 373 | fseek(fd, DATA_START + 149 * BLOCK_SIZE, SEEK_SET); 374 | fread(stack, sizeof(unsigned int) * 51, 1, fd); 375 | fseek(fd, DATA_START + 199 * BLOCK_SIZE, SEEK_SET); 376 | fread(stack, sizeof(unsigned int) * 51, 1, fd); 377 | fseek(fd, DATA_START + 249 * BLOCK_SIZE, SEEK_SET); 378 | fread(stack, sizeof(unsigned int) * 51, 1, fd); 379 | fseek(fd, DATA_START + 299 * BLOCK_SIZE, SEEK_SET); 380 | fread(stack, sizeof(unsigned int) * 51, 1, fd); 381 | fseek(fd, DATA_START + 349 * BLOCK_SIZE, SEEK_SET); 382 | fread(stack, sizeof(unsigned int) * 51, 1, fd); 383 | fseek(fd, DATA_START + 399 * BLOCK_SIZE, SEEK_SET); 384 | fread(stack, sizeof(unsigned int) * 51, 1, fd); 385 | fseek(fd, DATA_START + 449 * BLOCK_SIZE, SEEK_SET); 386 | fread(stack, sizeof(unsigned int) * 51, 1, fd); 387 | fseek(fd, DATA_START + 499 * BLOCK_SIZE, SEEK_SET); 388 | fread(stack, sizeof(unsigned int) * 51, 1, fd); 389 | fseek(fd, DATA_START + 511 * BLOCK_SIZE, SEEK_SET); 390 | fread(stack, sizeof(unsigned int) * 51, 1, fd); 391 | 392 | 393 | /* 394 | * 4. Create root directory. 395 | */ 396 | //Create inode 397 | //Now root directory contain 1 accounting file. 398 | inode iroot_tmp; 399 | iroot_tmp.i_ino = 0; //Identification 400 | iroot_tmp.di_number = 2; //Associations: itself and accouting file 401 | iroot_tmp.di_mode = 0; //0 stands for directory 402 | iroot_tmp.di_size = 0; //"For directories, the value is 0." 403 | memset(iroot_tmp.di_addr, -1, sizeof(unsigned int) * NADDR); 404 | iroot_tmp.di_addr[0] = 0; //Root directory is stored on 1st block. FFFFFF means empty. 405 | iroot_tmp.permission = MAX_OWNER_PERMISSION; 406 | iroot_tmp.di_grp = 1; 407 | iroot_tmp.di_uid = 0; //Root user id. 408 | iroot_tmp.icount = 0; 409 | time_t t = time(0); 410 | strftime(iroot_tmp.time, sizeof(iroot_tmp.time), "%Y/%m/%d %X %A %jday %z", localtime(&t)); 411 | iroot_tmp.time[64] = 0; 412 | fseek(fd, INODE_START, SEEK_SET); 413 | fwrite(&iroot_tmp, sizeof(inode), 1, fd); 414 | 415 | //Create directory file. 416 | directory droot_tmp; 417 | memset(droot_tmp.fileName, 0, sizeof(char) * DIRECTORY_NUM * FILE_NAME_LENGTH); 418 | memset(droot_tmp.inodeID, -1, sizeof(unsigned int) * DIRECTORY_NUM); 419 | strcpy(droot_tmp.fileName[0], "."); 420 | droot_tmp.inodeID[0] = 0; 421 | strcpy(droot_tmp.fileName[1], ".."); 422 | droot_tmp.inodeID[1] = 0; 423 | //A sub directory for accounting files 424 | strcpy(droot_tmp.fileName[2], "pw"); 425 | droot_tmp.inodeID[2] = 1; 426 | 427 | //Write 428 | fseek(fd, DATA_START, SEEK_SET); 429 | fwrite(&droot_tmp, sizeof(directory), 1, fd); 430 | 431 | /* 432 | * 5. Create accouting file. 433 | */ 434 | //Create inode 435 | inode iaccouting_tmp; 436 | iaccouting_tmp.i_ino = 1; //Identification 437 | iaccouting_tmp.di_number = 1; //Associations 438 | iaccouting_tmp.di_mode = 1; //1 stands for file 439 | iaccouting_tmp.di_size = sizeof(userPsw); //File size 440 | memset(iaccouting_tmp.di_addr, -1, sizeof(unsigned int) * NADDR); 441 | iaccouting_tmp.di_addr[0] = 1; //Root directory is stored on 1st block. 442 | iaccouting_tmp.di_uid = 0; //Root user id. 443 | iaccouting_tmp.di_grp = 1; 444 | iaccouting_tmp.permission = 320; 445 | iaccouting_tmp.icount = 0; 446 | t = time(0); 447 | strftime(iaccouting_tmp.time, sizeof(iaccouting_tmp.time), "%Y/%m/%d %X %A %jday %z", localtime(&t)); 448 | iaccouting_tmp.time[64] = 0; 449 | fseek(fd, INODE_START + INODE_SIZE, SEEK_SET); 450 | fwrite(&iaccouting_tmp, sizeof(inode), 1, fd); 451 | 452 | //Create accouting file. 453 | userPsw paccouting_tmp; 454 | memset(paccouting_tmp.userName, 0, sizeof(char) * USER_NAME_LENGTH * ACCOUNT_NUM); 455 | memset(paccouting_tmp.password, 0, sizeof(char) * USER_PASSWORD_LENGTH * ACCOUNT_NUM); 456 | //Only default user 'admin' is registered. Default password is 'admin'. 457 | strcpy(paccouting_tmp.userName[0], "admin"); 458 | strcpy(paccouting_tmp.userName[1], "guest"); 459 | strcpy(paccouting_tmp.password[0], "admin"); 460 | strcpy(paccouting_tmp.password[1], "123456"); 461 | //0 stands for super user. Other IDs are only used to identify users. 462 | for (unsigned short i = 0; i < ACCOUNT_NUM; i++) 463 | { 464 | paccouting_tmp.userID[i] = i; 465 | } 466 | paccouting_tmp.groupID[0] = 1; 467 | paccouting_tmp.groupID[1] = 2; 468 | //Write 469 | fseek(fd, DATA_START + BLOCK_SIZE, SEEK_SET); 470 | fwrite(&paccouting_tmp, sizeof(userPsw), 1, fd); 471 | 472 | //Close file. 473 | fclose(fd); 474 | 475 | return true; 476 | }; 477 | 478 | /* 479 | * Initialization function of the file system. Open an existing file system 480 | * from 'fs.han'. 481 | * 482 | * return: the function return true only when the file system has been 483 | * formatted and is complete. 484 | */ 485 | bool Mount() 486 | { 487 | /* 488 | * 1. Open the emulation file where the file system is installed. 489 | */ 490 | fd = fopen("./fs.han", "rb+"); 491 | if (fd == NULL) 492 | { 493 | printf("Error: File system not found!\n"); 494 | return false; 495 | } 496 | 497 | /* 498 | * 2. Read superblock, bitmaps, accouting file, current directory (root) 499 | */ 500 | //Read superblock 501 | fseek(fd, BLOCK_SIZE, SEEK_SET); 502 | fread(&superBlock, sizeof(superBlock), 1, fd); 503 | 504 | //Read inode bitmap 505 | fseek(fd, 2 * BLOCK_SIZE, SEEK_SET); 506 | fread(inode_bitmap, sizeof(unsigned short) * INODE_NUM, 1, fd); 507 | 508 | //Read current directory, namely root directory 509 | fseek(fd, DATA_START, SEEK_SET); 510 | fread(¤tDirectory, sizeof(directory), 1, fd); 511 | 512 | //Read accouting file 513 | fseek(fd, DATA_START + BLOCK_SIZE, SEEK_SET); 514 | fread(&users, sizeof(userPsw), 1, fd); 515 | 516 | return true; 517 | }; 518 | 519 | /* 520 | * Log in function. Update user information by checking log in inputs. 521 | * 522 | * return: the function return true only when log in process succeed. 523 | */ 524 | bool Login(const char* user, const char* password) 525 | { 526 | //parameters check 527 | if (user == NULL || password == NULL) 528 | { 529 | printf("Error: User name or password illegal!\n\n"); 530 | return false; 531 | } 532 | if (strlen(user) > USER_NAME_LENGTH || strlen(password) > USER_PASSWORD_LENGTH) 533 | { 534 | printf("Error: User name or password illegal!\n"); 535 | return false; 536 | } 537 | 538 | //have logged in? 539 | if (userID != ACCOUNT_NUM) 540 | { 541 | printf("Login failed: User has been logged in. Please log out first.\n"); 542 | return false; 543 | } 544 | 545 | //search the user in accouting file 546 | for (int i = 0; i < ACCOUNT_NUM; i++) 547 | { 548 | if (strcmp(users.userName[i], user) == 0) 549 | { 550 | //find the user and check password 551 | if (strcmp(users.password[i], password) == 0) 552 | { 553 | //Login successfully 554 | printf("Login successfully.\n"); 555 | userID = users.userID[i]; 556 | //make user's name, root user is special 557 | memset(userName, 0, USER_NAME_LENGTH + 6); 558 | if (userID == 0) 559 | { 560 | strcat(userName, "root "); 561 | strcat(userName, users.userName[i]); 562 | strcat(userName, "$"); 563 | } 564 | else 565 | { 566 | strcat(userName, users.userName[i]); 567 | strcat(userName, "#"); 568 | } 569 | 570 | return true; 571 | } 572 | else 573 | { 574 | //Password wrong 575 | printf("Login failed: Wrong password.\n"); 576 | return false; 577 | } 578 | } 579 | } 580 | 581 | //User not found 582 | printf("Login failed: User not found.\n"); 583 | return false; 584 | 585 | }; 586 | 587 | /* 588 | * Log out function. Remove user's states. 589 | */ 590 | void Logout() 591 | { 592 | //remove user's states 593 | userID = ACCOUNT_NUM; 594 | memset(&users, 0, sizeof(users)); 595 | memset(userName, 0, 6 + USER_NAME_LENGTH); 596 | Mount(); 597 | }; 598 | 599 | /* 600 | * Create a new empty file with the specific file name. 601 | * 602 | * return: the function return true only when the new file is successfully 603 | * created. 604 | */ 605 | bool CreateFile(const char* filename) 606 | { 607 | //parameter check 608 | if (filename == NULL || strlen(filename) > FILE_NAME_LENGTH) 609 | { 610 | printf("Error: Illegal file name.\n"); 611 | return false; 612 | } 613 | 614 | /* 615 | * 1. Check whether free inodes and blocks are used up. 616 | */ 617 | if (superBlock.s_num_fblock <= 0 || superBlock.s_num_finode <= 0) 618 | { 619 | printf("File creation error: No valid spaces.\n"); 620 | return false; 621 | } 622 | //Find new inode number and new block address 623 | int new_ino = 0; 624 | unsigned int new_block_addr = -1; 625 | for (; new_ino < INODE_NUM; new_ino++) 626 | { 627 | if (inode_bitmap[new_ino] == 0) 628 | { 629 | break; 630 | } 631 | } 632 | 633 | /* 634 | * 2. Check whether file name has been used in current directory. 635 | */ 636 | for (int i = 0; i < DIRECTORY_NUM; i++) 637 | { 638 | if (strcmp(currentDirectory.fileName[i], filename) == 0) 639 | { 640 | inode* tmp_file_inode = new inode; 641 | int tmp_file_ino = currentDirectory.inodeID[i]; 642 | fseek(fd, INODE_START + tmp_file_ino * INODE_SIZE, SEEK_SET); 643 | fread(tmp_file_inode, sizeof(inode), 1, fd); 644 | if (tmp_file_inode->di_mode == 0) continue; 645 | else { 646 | printf("File creation error: File name '%s' has been used.\n", currentDirectory.fileName[i]); 647 | return false; 648 | } 649 | } 650 | } 651 | 652 | /* 653 | * 3. Check whether current directory contains too many items already. 654 | */ 655 | int itemCounter = 0; 656 | for (int i = 0; i < DIRECTORY_NUM; i++) 657 | { 658 | if (strlen(currentDirectory.fileName[i]) > 0) 659 | { 660 | itemCounter++; 661 | } 662 | } 663 | if (itemCounter >= DIRECTORY_NUM) 664 | { 665 | printf("File creation error: Too many files or directories in current path.\n"); 666 | return false; 667 | } 668 | 669 | /* 670 | * 4. Create new inode. 671 | */ 672 | //Create inode 673 | inode ifile_tmp; 674 | ifile_tmp.i_ino = new_ino; //Identification 675 | ifile_tmp.di_number = 1; //Associations 676 | ifile_tmp.di_mode = 1; //1 stands for file 677 | ifile_tmp.di_size = 0; //New file is empty 678 | memset(ifile_tmp.di_addr, -1, sizeof(unsigned int) * NADDR); 679 | ifile_tmp.di_uid = userID; //Current user id. 680 | ifile_tmp.di_grp = users.groupID[userID];//Current user group id 681 | ifile_tmp.permission = MAX_PERMISSION; 682 | ifile_tmp.icount = 0; 683 | time_t t = time(0); 684 | strftime(ifile_tmp.time, sizeof(ifile_tmp.time), "%Y/%m/%d %X %A %jday %z", localtime(&t)); 685 | ifile_tmp.time[64]; 686 | fseek(fd, INODE_START + new_ino * INODE_SIZE, SEEK_SET); 687 | fwrite(&ifile_tmp, sizeof(inode), 1, fd); 688 | 689 | /* 690 | * 5. Update bitmaps. 691 | */ 692 | //Update bitmaps 693 | inode_bitmap[new_ino] = 1; 694 | fseek(fd, 2 * BLOCK_SIZE, SEEK_SET); 695 | fwrite(inode_bitmap, sizeof(unsigned short) * INODE_NUM, 1, fd); 696 | 697 | /* 698 | * 6. Update directory. 699 | */ 700 | //Fetch current directory's inode 701 | //Inode position of current directory 702 | int pos_directory_inode = 0; 703 | pos_directory_inode = currentDirectory.inodeID[0]; //"." 704 | inode tmp_directory_inode; 705 | fseek(fd, INODE_START + pos_directory_inode * INODE_SIZE, SEEK_SET); 706 | fread(&tmp_directory_inode, sizeof(inode), 1, fd); 707 | 708 | //Add to current directory item 709 | for (int i = 2; i < DIRECTORY_NUM; i++) 710 | { 711 | if (strlen(currentDirectory.fileName[i]) == 0) 712 | { 713 | strcat(currentDirectory.fileName[i], filename); 714 | currentDirectory.inodeID[i] = new_ino; 715 | break; 716 | } 717 | } 718 | //write 719 | fseek(fd, DATA_START + tmp_directory_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET); 720 | fwrite(¤tDirectory, sizeof(directory), 1, fd); 721 | 722 | //Update associations 723 | directory tmp_directory = currentDirectory; 724 | int tmp_pos_directory_inode = pos_directory_inode; 725 | while (true) 726 | { 727 | //Update association 728 | tmp_directory_inode.di_number++; 729 | fseek(fd, INODE_START + tmp_pos_directory_inode * INODE_SIZE, SEEK_SET); 730 | fwrite(&tmp_directory_inode, sizeof(inode), 1, fd); 731 | //If reach the root directory, finish updating. 732 | if (tmp_directory.inodeID[1] == tmp_directory.inodeID[0]) 733 | { 734 | break; 735 | } 736 | //Fetch father directory 737 | tmp_pos_directory_inode = tmp_directory.inodeID[1]; //".." 738 | fseek(fd, INODE_START + tmp_pos_directory_inode * INODE_SIZE, SEEK_SET); 739 | fread(&tmp_directory_inode, sizeof(inode), 1, fd); 740 | fseek(fd, DATA_START + tmp_directory_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET); 741 | fread(&tmp_directory, sizeof(directory), 1, fd); 742 | } 743 | 744 | /* 745 | * 7. Update super block. 746 | */ 747 | //superBlock.s_num_fblock--; 748 | superBlock.s_num_finode--; 749 | fseek(fd, BLOCK_SIZE, SEEK_SET); 750 | fwrite(&superBlock, sizeof(filsys), 1, fd); 751 | 752 | return true; 753 | }; 754 | 755 | /* 756 | * Delete a file. 757 | * 758 | * return: the function returns true only delete the file successfully. 759 | */ 760 | bool DeleteFile(const char* filename) 761 | { 762 | //parameter check 763 | if (filename == NULL || strlen(filename) > FILE_NAME_LENGTH) 764 | { 765 | printf("Error: Illegal file name.\n"); 766 | return false; 767 | } 768 | 769 | /* 770 | * 1. Check whether the file exists in current directory. 771 | */ 772 | int pos_in_directory = -1, tmp_file_ino; 773 | inode tmp_file_inode; 774 | do { 775 | pos_in_directory++; 776 | for (; pos_in_directory < DIRECTORY_NUM; pos_in_directory++) 777 | { 778 | if (strcmp(currentDirectory.fileName[pos_in_directory], filename) == 0) 779 | { 780 | break; 781 | } 782 | } 783 | if (pos_in_directory == DIRECTORY_NUM) 784 | { 785 | printf("Delete error: File not found.\n"); 786 | return false; 787 | } 788 | 789 | /* 790 | * 2. Fetch inode and check whether it's a directory. 791 | */ 792 | //Fetch inode 793 | tmp_file_ino = currentDirectory.inodeID[pos_in_directory]; 794 | fseek(fd, INODE_START + tmp_file_ino * INODE_SIZE, SEEK_SET); 795 | fread(&tmp_file_inode, sizeof(inode), 1, fd); 796 | //Directory check 797 | } while (tmp_file_inode.di_mode == 0); //is a directory, roll back and continue to search the file 798 | 799 | //Access check 800 | 801 | if (userID == tmp_file_inode.di_uid) 802 | { 803 | if (!(tmp_file_inode.permission & OWN_E)) { 804 | printf("Delete error: Access deny.\n"); 805 | return -1; 806 | } 807 | } 808 | else if (users.groupID[userID] == tmp_file_inode.di_grp) { 809 | if (!(tmp_file_inode.permission & GRP_E)) { 810 | printf("Delete error: Access deny.\n"); 811 | return -1; 812 | } 813 | } 814 | else { 815 | if (!(tmp_file_inode.permission & ELSE_E)) { 816 | printf("Delete error: Access deny.\n"); 817 | return -1; 818 | } 819 | } 820 | /* 821 | * 3. Start deleting. Fill the inode's original space with 0. 822 | */ 823 | if (tmp_file_inode.icount > 0) { 824 | tmp_file_inode.icount--; 825 | fseek(fd, INODE_START + tmp_file_inode.i_ino * INODE_SIZE, SEEK_SET); 826 | fwrite(&tmp_file_inode, sizeof(inode), 1, fd); 827 | /* 828 | * Update directories 829 | */ 830 | //Fetch current directory inode 831 | int pos_directory_inode = currentDirectory.inodeID[0]; //"." 832 | inode tmp_directory_inode; 833 | fseek(fd, INODE_START + pos_directory_inode * INODE_SIZE, SEEK_SET); 834 | fread(&tmp_directory_inode, sizeof(inode), 1, fd); 835 | 836 | //Update current directory item 837 | memset(currentDirectory.fileName[pos_in_directory], 0, FILE_NAME_LENGTH); 838 | currentDirectory.inodeID[pos_in_directory] = -1; 839 | fseek(fd, DATA_START + tmp_directory_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET); 840 | fwrite(¤tDirectory, sizeof(directory), 1, fd); 841 | 842 | //Update associations 843 | directory tmp_directory = currentDirectory; 844 | int tmp_pos_directory_inode = pos_directory_inode; 845 | while (true) 846 | { 847 | //Update association 848 | tmp_directory_inode.di_number--; 849 | fseek(fd, INODE_START + tmp_pos_directory_inode * INODE_SIZE, SEEK_SET); 850 | fwrite(&tmp_directory_inode, sizeof(inode), 1, fd); 851 | //If reach the root directory, finish updating. 852 | if (tmp_directory.inodeID[1] == tmp_directory.inodeID[0]) 853 | { 854 | break; 855 | } 856 | //Fetch father directory 857 | tmp_pos_directory_inode = tmp_directory.inodeID[1]; //".." 858 | fseek(fd, INODE_START + tmp_pos_directory_inode * INODE_SIZE, SEEK_SET); 859 | fread(&tmp_directory_inode, sizeof(inode), 1, fd); 860 | fseek(fd, DATA_START + tmp_directory_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET); 861 | fread(&tmp_directory, sizeof(directory), 1, fd); 862 | } 863 | return true; 864 | } 865 | //Fill original space 866 | int tmp_fill[sizeof(inode)]; 867 | memset(tmp_fill, 0, sizeof(inode)); 868 | fseek(fd, INODE_START + tmp_file_ino * INODE_SIZE, SEEK_SET); 869 | fwrite(&tmp_fill, sizeof(inode), 1, fd); 870 | 871 | /* 872 | * 4. Update bitmaps 873 | */ 874 | //inode bitmap 875 | inode_bitmap[tmp_file_ino] = 0; 876 | fseek(fd, 2 * BLOCK_SIZE, SEEK_SET); 877 | fwrite(&inode_bitmap, sizeof(unsigned short) * INODE_NUM, 1, fd); 878 | //block bitmap 879 | 880 | for (int i = 0; i < NADDR - 2; i++) 881 | { 882 | if(tmp_file_inode.di_addr[i] != -1) 883 | recycle_block(tmp_file_inode.di_addr[i]); 884 | else break; 885 | } 886 | if (tmp_file_inode.di_addr[NADDR - 2] != -1) { 887 | unsigned int f1[128]; 888 | fseek(fd, DATA_START + tmp_file_inode.di_addr[NADDR - 2] * BLOCK_SIZE, SEEK_SET); 889 | fread(f1, sizeof(f1), 1, fd); 890 | for (int k = 0; k < 128; k++) { 891 | recycle_block(f1[k]); 892 | } 893 | recycle_block(tmp_file_inode.di_addr[NADDR - 2]); 894 | } 895 | 896 | /* 897 | * 5. Update directories 898 | */ 899 | //Fetch current directory inode 900 | int pos_directory_inode = currentDirectory.inodeID[0]; //"." 901 | inode tmp_directory_inode; 902 | fseek(fd, INODE_START + pos_directory_inode * INODE_SIZE, SEEK_SET); 903 | fread(&tmp_directory_inode, sizeof(inode), 1, fd); 904 | 905 | //Update current directory item 906 | memset(currentDirectory.fileName[pos_in_directory], 0, FILE_NAME_LENGTH); 907 | currentDirectory.inodeID[pos_in_directory] = -1; 908 | fseek(fd, DATA_START + tmp_directory_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET); 909 | fwrite(¤tDirectory, sizeof(directory), 1, fd); 910 | 911 | //Update associations 912 | directory tmp_directory = currentDirectory; 913 | int tmp_pos_directory_inode = pos_directory_inode; 914 | while (true) 915 | { 916 | //Update association 917 | tmp_directory_inode.di_number--; 918 | fseek(fd, INODE_START + tmp_pos_directory_inode * INODE_SIZE, SEEK_SET); 919 | fwrite(&tmp_directory_inode, sizeof(inode), 1, fd); 920 | //If reach the root directory, finish updating. 921 | if (tmp_directory.inodeID[1] == tmp_directory.inodeID[0]) 922 | { 923 | break; 924 | } 925 | //Fetch father directory 926 | tmp_pos_directory_inode = tmp_directory.inodeID[1]; //".." 927 | fseek(fd, INODE_START + tmp_pos_directory_inode * INODE_SIZE, SEEK_SET); 928 | fread(&tmp_directory_inode, sizeof(inode), 1, fd); 929 | fseek(fd, DATA_START + tmp_directory_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET); 930 | fread(&tmp_directory, sizeof(directory), 1, fd); 931 | } 932 | 933 | /* 934 | * 6. Update super block 935 | */ 936 | //superBlock.s_num_fblock += tmp_file_inode.di_size / BLOCK_SIZE + 1; 937 | superBlock.s_num_finode++; 938 | fseek(fd, BLOCK_SIZE, SEEK_SET); 939 | fwrite(&superBlock, sizeof(filsys), 1, fd); 940 | 941 | return true; 942 | } 943 | 944 | /* 945 | * Open the specific file under current directory. 946 | * 947 | * return: the function returns a pointer of the file's inode if the file is 948 | * successfully opened and NULL otherwise. 949 | */ 950 | inode* OpenFile(const char* filename) 951 | { 952 | //parameter check 953 | if (filename == NULL || strlen(filename) > FILE_NAME_LENGTH) 954 | { 955 | printf("Error: Illegal file name.\n"); 956 | return NULL; 957 | } 958 | 959 | /* 960 | * 1. Check whether the file exists in current directory. 961 | */ 962 | int pos_in_directory = -1; 963 | inode* tmp_file_inode = new inode; 964 | do { 965 | pos_in_directory++; 966 | for (; pos_in_directory < DIRECTORY_NUM; pos_in_directory++) 967 | { 968 | if (strcmp(currentDirectory.fileName[pos_in_directory], filename) == 0) 969 | { 970 | break; 971 | } 972 | } 973 | if (pos_in_directory == DIRECTORY_NUM) 974 | { 975 | printf("Open file error: File not found.\n"); 976 | return NULL; 977 | } 978 | 979 | /* 980 | * 2. Fetch inode and check whether it's a directory. 981 | */ 982 | //Fetch inode 983 | int tmp_file_ino = currentDirectory.inodeID[pos_in_directory]; 984 | fseek(fd, INODE_START + tmp_file_ino * INODE_SIZE, SEEK_SET); 985 | fread(tmp_file_inode, sizeof(inode), 1, fd); 986 | //Directory check 987 | } while (tmp_file_inode->di_mode == 0); 988 | 989 | return tmp_file_inode; 990 | }; 991 | 992 | /* 993 | * Append a string "content" to the specific file. 994 | * 995 | * return: the function returns the number of bytes it has writen or -1 when 996 | * some error occur. 997 | */ 998 | int Write(inode& ifile, const char* content) 999 | { 1000 | //parameter check 1001 | if (content == NULL) 1002 | { 1003 | printf("Error: Illegal file name.\n"); 1004 | return -1; 1005 | } 1006 | //Access check 1007 | if (userID == ifile.di_uid) 1008 | { 1009 | if (!(ifile.permission & OWN_W)) { 1010 | printf("Write error: Access deny.\n"); 1011 | return -1; 1012 | } 1013 | } 1014 | else if (users.groupID[userID] == ifile.di_grp) { 1015 | if (!(ifile.permission & GRP_W)) { 1016 | printf("Write error: Access deny.\n"); 1017 | return -1; 1018 | } 1019 | } 1020 | else { 1021 | if (!(ifile.permission & ELSE_W)) { 1022 | printf("Write error: Access deny.\n"); 1023 | return -1; 1024 | } 1025 | } 1026 | 1027 | /* 1028 | * 1. Check whether the expected file will be out of length. 1029 | */ 1030 | int len_content = strlen(content); 1031 | unsigned int new_file_length = len_content + ifile.di_size; 1032 | if (new_file_length >= FILE_SIZE_MAX) 1033 | { 1034 | printf("Write error: File over length.\n"); 1035 | return -1; 1036 | } 1037 | 1038 | /* 1039 | * 2. Get the number of needed blocks and check is there any enough free spaces. 1040 | */ 1041 | //Get the number of needed blocks 1042 | unsigned int block_num; 1043 | if (ifile.di_addr[0] == -1)block_num = -1; 1044 | else 1045 | { 1046 | for (int i = 0; i < NADDR - 2; i++) 1047 | { 1048 | if (ifile.di_addr[i] != -1) 1049 | block_num = ifile.di_addr[i]; 1050 | else break; 1051 | } 1052 | int f1[128]; 1053 | fseek(fd, DATA_START + ifile.di_addr[NADDR - 2] * BLOCK_SIZE, SEEK_SET); 1054 | int num; 1055 | if (ifile.di_size%BLOCK_SIZE == 0) 1056 | num = ifile.di_size / BLOCK_SIZE; 1057 | else num = ifile.di_size / BLOCK_SIZE + 1; 1058 | if (num > 4 && num <=132) 1059 | { 1060 | fseek(fd, DATA_START + ifile.di_addr[NADDR - 2] * BLOCK_SIZE, SEEK_SET); 1061 | fread(f1, sizeof(f1), 1, fd); 1062 | block_num = f1[num - 4]; 1063 | } 1064 | 1065 | } 1066 | int free_space_firstBlock = BLOCK_SIZE - ifile.di_size % BLOCK_SIZE; 1067 | unsigned int num_block_needed; 1068 | if (len_content - free_space_firstBlock > 0) 1069 | { 1070 | num_block_needed = (len_content - free_space_firstBlock) / BLOCK_SIZE + 1; 1071 | } 1072 | else 1073 | { 1074 | num_block_needed = 0; 1075 | } 1076 | //Check is there any enough free spaces 1077 | if (num_block_needed > superBlock.s_num_fblock) 1078 | { 1079 | printf("Write error: No enough space available.\n"); 1080 | return -1; 1081 | } 1082 | 1083 | /* 1084 | * 3. Write first block. 1085 | */ 1086 | if (ifile.di_addr[0] == -1) 1087 | { 1088 | find_free_block(block_num); 1089 | ifile.di_addr[0] = block_num; 1090 | fseek(fd, DATA_START + block_num * BLOCK_SIZE, SEEK_SET); 1091 | } 1092 | else 1093 | fseek(fd, DATA_START + block_num * BLOCK_SIZE + ifile.di_size % BLOCK_SIZE, SEEK_SET); 1094 | char data[BLOCK_SIZE]; 1095 | if (num_block_needed == 0) 1096 | { 1097 | fwrite(content, len_content, 1, fd); 1098 | fseek(fd, DATA_START + block_num * BLOCK_SIZE, SEEK_SET); 1099 | fread(data, sizeof(data), 1, fd); 1100 | ifile.di_size += len_content; 1101 | } 1102 | else 1103 | { 1104 | fwrite(content, free_space_firstBlock, 1, fd); 1105 | fseek(fd, DATA_START + block_num * BLOCK_SIZE, SEEK_SET); 1106 | fread(data, sizeof(data), 1, fd); 1107 | ifile.di_size += free_space_firstBlock; 1108 | } 1109 | 1110 | /* 1111 | * 4. Write the other blocks. Update file information in inode and block bitmap in the meanwhile. 1112 | */ 1113 | char write_buf[BLOCK_SIZE]; 1114 | unsigned int new_block_addr = -1; 1115 | unsigned int content_write_pos = free_space_firstBlock; 1116 | //Loop and write each blocks 1117 | if ((len_content + ifile.di_size) / BLOCK_SIZE + ((len_content + ifile.di_size) % BLOCK_SIZE == 0 ? 0 : 1) <= NADDR - 2) { 1118 | //direct addressing 1119 | for (int i = 0; i < num_block_needed; i++) 1120 | { 1121 | find_free_block(new_block_addr); 1122 | if (new_block_addr == -1)return -1; 1123 | for (int j = 0; j < NADDR - 2; j++) 1124 | { 1125 | if (ifile.di_addr[j] == -1) 1126 | { 1127 | ifile.di_addr[j] = new_block_addr; 1128 | break; 1129 | } 1130 | } 1131 | memset(write_buf, 0, BLOCK_SIZE); 1132 | //Copy from content to write buffer 1133 | unsigned int tmp_counter = 0; 1134 | for (; tmp_counter < BLOCK_SIZE; tmp_counter++) 1135 | { 1136 | if (content[content_write_pos + tmp_counter] == '\0') 1137 | break; 1138 | write_buf[tmp_counter] = content[content_write_pos + tmp_counter]; 1139 | } 1140 | content_write_pos += tmp_counter; 1141 | //Write 1142 | fseek(fd, DATA_START + new_block_addr * BLOCK_SIZE, SEEK_SET); 1143 | fwrite(write_buf, tmp_counter, 1, fd); 1144 | fseek(fd, DATA_START + new_block_addr * BLOCK_SIZE, SEEK_SET); 1145 | fread(data, sizeof(data), 1, fd); 1146 | //Update inode information: blocks address and file size 1147 | ifile.di_size += tmp_counter; 1148 | } 1149 | } 1150 | else if ((len_content+ifile.di_size)/BLOCK_SIZE+((len_content + ifile.di_size) % BLOCK_SIZE == 0 ? 0 : 1)> NADDR - 2) { 1151 | //direct addressing 1152 | for (int i = 0; i < NADDR - 2; i++) 1153 | { 1154 | if (ifile.di_addr[i] != -1)continue; 1155 | 1156 | memset(write_buf, 0, BLOCK_SIZE); 1157 | new_block_addr = -1; 1158 | 1159 | find_free_block(new_block_addr); 1160 | if (new_block_addr == -1)return -1; 1161 | ifile.di_addr[i] = new_block_addr; 1162 | //Copy from content to write buffer 1163 | unsigned int tmp_counter = 0; 1164 | for (; tmp_counter < BLOCK_SIZE; tmp_counter++) 1165 | { 1166 | if (content[content_write_pos + tmp_counter] == '\0') { 1167 | break; 1168 | } 1169 | write_buf[tmp_counter] = content[content_write_pos + tmp_counter]; 1170 | } 1171 | content_write_pos += tmp_counter; 1172 | //Write 1173 | fseek(fd, DATA_START + new_block_addr * BLOCK_SIZE, SEEK_SET); 1174 | fwrite(write_buf, tmp_counter, 1, fd); 1175 | 1176 | //Update inode information: blocks address and file size 1177 | ifile.di_size += tmp_counter; 1178 | } 1179 | //first indirect addressing 1180 | int cnt = 0; 1181 | unsigned int f1[BLOCK_SIZE / sizeof(unsigned int)] = { 0 }; 1182 | 1183 | new_block_addr = -1; 1184 | find_free_block(new_block_addr); 1185 | if (new_block_addr == -1)return -1; 1186 | ifile.di_addr[NADDR - 2] = new_block_addr; 1187 | for (int i = 0;i < BLOCK_SIZE / sizeof(unsigned int);i++) 1188 | { 1189 | new_block_addr = -1; 1190 | find_free_block(new_block_addr); 1191 | if (new_block_addr == -1)return -1; 1192 | else 1193 | f1[i] = new_block_addr; 1194 | } 1195 | fseek(fd, DATA_START + ifile.di_addr[4] * BLOCK_SIZE, SEEK_SET); 1196 | fwrite(f1, sizeof(f1), 1, fd); 1197 | bool flag = 0; 1198 | for (int j = 0; j < BLOCK_SIZE / sizeof(int); j++) { 1199 | fseek(fd, DATA_START + f1[j] * BLOCK_SIZE, SEEK_SET); 1200 | //Copy from content to write buffer 1201 | unsigned int tmp_counter = 0; 1202 | for (; tmp_counter < BLOCK_SIZE; tmp_counter++) 1203 | { 1204 | if (content[content_write_pos + tmp_counter] == '\0') { 1205 | //tmp_counter--; 1206 | flag = 1; 1207 | break; 1208 | } 1209 | write_buf[tmp_counter] = content[content_write_pos + tmp_counter]; 1210 | } 1211 | content_write_pos += tmp_counter; 1212 | fwrite(write_buf, tmp_counter, 1, fd); 1213 | ifile.di_size += tmp_counter; 1214 | if (flag == 1) break; 1215 | } 1216 | } 1217 | time_t t = time(0); 1218 | strftime(ifile.time, sizeof(ifile.time), "%Y/%m/%d %X %A %jday %z", localtime(&t)); 1219 | ifile.time[64] = 0; 1220 | //Write inode 1221 | fseek(fd, INODE_START + ifile.i_ino * INODE_SIZE, SEEK_SET); 1222 | fwrite(&ifile, sizeof(inode), 1, fd); 1223 | 1224 | /* 1225 | * 5. Update super block. 1226 | */ 1227 | //superBlock.s_num_fblock -= num_block_needed; 1228 | fseek(fd, BLOCK_SIZE, SEEK_SET); 1229 | fwrite(&superBlock, sizeof(superBlock), 1, fd); 1230 | 1231 | return len_content; 1232 | }; 1233 | 1234 | /* 1235 | * Print the string "content" in the specific file. 1236 | * 1237 | * return: none 1238 | * 1239 | */ 1240 | void PrintFile(inode& ifile) 1241 | { 1242 | //Access check 1243 | if (userID == ifile.di_uid) 1244 | { 1245 | if (!(ifile.permission & OWN_R)) { 1246 | printf("Read error: Access deny.\n"); 1247 | return; 1248 | } 1249 | } 1250 | else if (users.groupID[userID] == ifile.di_grp) { 1251 | if (!(ifile.permission & GRP_R)) { 1252 | printf("Read error: Access deny.\n"); 1253 | return; 1254 | } 1255 | } 1256 | else { 1257 | if (!(ifile.permission & ELSE_R)) { 1258 | printf("Read error: Access deny.\n"); 1259 | return; 1260 | } 1261 | } 1262 | int block_num = ifile.di_size / BLOCK_SIZE + 1; 1263 | int print_line_num = 0; //16 bytes per line. 1264 | //Read file from data blocks 1265 | char stack[BLOCK_SIZE]; 1266 | if (block_num <= NADDR - 2) 1267 | { 1268 | for (int i = 0; i < block_num; i++) 1269 | { 1270 | fseek(fd, DATA_START + ifile.di_addr[i] * BLOCK_SIZE, SEEK_SET); 1271 | fread(stack, sizeof(stack), 1, fd); 1272 | for (int j = 0; j < BLOCK_SIZE; j++) 1273 | { 1274 | if (stack[j] == '\0')break; 1275 | if (j % 16 == 0) 1276 | { 1277 | printf("\n"); 1278 | printf("%d\t", ++print_line_num); 1279 | } 1280 | printf("%c", stack[j]); 1281 | } 1282 | } 1283 | //int i = 0; 1284 | } 1285 | else if (block_num > NADDR - 2) { 1286 | //direct addressing 1287 | for (int i = 0; i < NADDR - 2; i++) 1288 | { 1289 | fseek(fd, DATA_START + ifile.di_addr[i] * BLOCK_SIZE, SEEK_SET); 1290 | fread(stack, sizeof(stack), 1, fd); 1291 | for (int j = 0; j < BLOCK_SIZE; j++) 1292 | { 1293 | if (stack[j] == '\0')break; 1294 | if (j % 16 == 0) 1295 | { 1296 | printf("\n"); 1297 | printf("%d\t", ++print_line_num); 1298 | } 1299 | printf("%c", stack[j]); 1300 | } 1301 | } 1302 | 1303 | //first indirect addressing 1304 | unsigned int f1[BLOCK_SIZE / sizeof(unsigned int)] = { 0 }; 1305 | fseek(fd, DATA_START + ifile.di_addr[NADDR - 2] * BLOCK_SIZE, SEEK_SET); 1306 | fread(f1, sizeof(f1), 1, fd); 1307 | for (int i = 0; i < block_num - (NADDR - 2); i++) { 1308 | fseek(fd, DATA_START + f1[i] * BLOCK_SIZE, SEEK_SET); 1309 | fread(stack, sizeof(stack), 1, fd); 1310 | for (int j = 0; j < BLOCK_SIZE; j++) 1311 | { 1312 | if (stack[j] == '\0')break; 1313 | if (j % 16 == 0) 1314 | { 1315 | printf("\n"); 1316 | printf("%d\t", ++print_line_num); 1317 | } 1318 | printf("%c", stack[j]); 1319 | } 1320 | } 1321 | } 1322 | printf("\n\n\n"); 1323 | }; 1324 | 1325 | /* 1326 | * Create a new drirectory only with "." and ".." items. 1327 | * 1328 | * return: the function returns true only when the new directory is 1329 | * created successfully. 1330 | */ 1331 | bool MakeDir(const char* dirname) 1332 | { 1333 | //parameter check 1334 | if (dirname == NULL || strlen(dirname) > FILE_NAME_LENGTH) 1335 | { 1336 | printf("Error: Illegal directory name.\n"); 1337 | return false; 1338 | } 1339 | 1340 | /* 1341 | * 1. Check whether free inodes and blocks are used up. 1342 | */ 1343 | if (superBlock.s_num_fblock <= 0 || superBlock.s_num_finode <= 0) 1344 | { 1345 | printf("File creation error: No valid spaces.\n"); 1346 | return false; 1347 | } 1348 | //Find new inode number and new block address 1349 | int new_ino = 0; 1350 | unsigned int new_block_addr = 0; 1351 | for (; new_ino < INODE_NUM; new_ino++) 1352 | { 1353 | if (inode_bitmap[new_ino] == 0) 1354 | { 1355 | break; 1356 | } 1357 | } 1358 | find_free_block(new_block_addr); 1359 | if (new_block_addr == -1) return false; 1360 | if (new_ino == INODE_NUM || new_block_addr == BLOCK_NUM) 1361 | { 1362 | printf("File creation error: No valid spaces.\n"); 1363 | return false; 1364 | } 1365 | 1366 | /* 1367 | * 2. Check whether directory name has been used in current directory. 1368 | */ 1369 | for (int i = 0; i < DIRECTORY_NUM; i++) 1370 | { 1371 | if (strcmp(currentDirectory.fileName[i], dirname) == 0) 1372 | { 1373 | inode* tmp_file_inode = new inode; 1374 | int tmp_file_ino = currentDirectory.inodeID[i]; 1375 | fseek(fd, INODE_START + tmp_file_ino * INODE_SIZE, SEEK_SET); 1376 | fread(tmp_file_inode, sizeof(inode), 1, fd); 1377 | if (tmp_file_inode->di_mode == 1) continue; 1378 | else { 1379 | printf("File creation error: Directory name '%s' has been used.\n", currentDirectory.fileName[i]); 1380 | return false; 1381 | } 1382 | } 1383 | } 1384 | 1385 | /* 1386 | * 3. Check whether current directory contains too many items already. 1387 | */ 1388 | int itemCounter = 0; 1389 | for (int i = 0; i < DIRECTORY_NUM; i++) 1390 | { 1391 | if (strlen(currentDirectory.fileName[i]) > 0) 1392 | { 1393 | itemCounter++; 1394 | } 1395 | } 1396 | if (itemCounter >= DIRECTORY_NUM) 1397 | { 1398 | printf("File creation error: Too many files or directories in current path.\n"); 1399 | return false; 1400 | } 1401 | 1402 | /* 1403 | * 4. Create new inode. 1404 | */ 1405 | //Create inode 1406 | inode idir_tmp; 1407 | idir_tmp.i_ino = new_ino; //Identification 1408 | idir_tmp.di_number = 1; //Associations 1409 | idir_tmp.di_mode = 0; //0 stands for directory 1410 | idir_tmp.di_size = sizeof(directory); //"For directories, the value is 0." 1411 | memset(idir_tmp.di_addr, -1, sizeof(unsigned int) * NADDR); 1412 | idir_tmp.di_addr[0] = new_block_addr; 1413 | idir_tmp.di_uid = userID; //Current user id. 1414 | idir_tmp.di_grp = users.groupID[userID]; 1415 | time_t t = time(0); 1416 | strftime(idir_tmp.time, sizeof(idir_tmp.time), "%Y/%m/%d %X %A %jday %z", localtime(&t)); 1417 | idir_tmp.time[64] = 0; 1418 | idir_tmp.icount = 0; 1419 | idir_tmp.permission = MAX_PERMISSION; 1420 | fseek(fd, INODE_START + new_ino * INODE_SIZE, SEEK_SET); 1421 | fwrite(&idir_tmp, sizeof(inode), 1, fd); 1422 | 1423 | /* 1424 | * 5. Create directory file. 1425 | */ 1426 | directory tmp_dir; 1427 | memset(tmp_dir.fileName, 0, sizeof(char) * DIRECTORY_NUM * FILE_NAME_LENGTH); 1428 | memset(tmp_dir.inodeID, -1, sizeof(unsigned int) * DIRECTORY_NUM); 1429 | strcpy(tmp_dir.fileName[0], "."); 1430 | tmp_dir.inodeID[0] = new_ino; 1431 | strcpy(tmp_dir.fileName[1], ".."); 1432 | tmp_dir.inodeID[1] = currentDirectory.inodeID[0]; 1433 | fseek(fd, DATA_START + new_block_addr * BLOCK_SIZE, SEEK_SET); 1434 | fwrite(&tmp_dir, sizeof(directory), 1, fd); 1435 | 1436 | /* 1437 | * 6. Update bitmaps. 1438 | */ 1439 | //Update bitmaps 1440 | inode_bitmap[new_ino] = 1; 1441 | fseek(fd, 2 * BLOCK_SIZE, SEEK_SET); 1442 | fwrite(inode_bitmap, sizeof(unsigned short) * INODE_NUM, 1, fd); 1443 | 1444 | /* 1445 | * 7. Update directory. 1446 | */ 1447 | //Fetch current directory's inode 1448 | //Inode position of current directory 1449 | int pos_directory_inode = 0; 1450 | pos_directory_inode = currentDirectory.inodeID[0]; //"." 1451 | inode tmp_directory_inode; 1452 | fseek(fd, INODE_START + pos_directory_inode * INODE_SIZE, SEEK_SET); 1453 | fread(&tmp_directory_inode, sizeof(inode), 1, fd); 1454 | 1455 | //Add to current directory item 1456 | for (int i = 2; i < DIRECTORY_NUM; i++) 1457 | { 1458 | if (strlen(currentDirectory.fileName[i]) == 0) 1459 | { 1460 | strcat(currentDirectory.fileName[i], dirname); 1461 | currentDirectory.inodeID[i] = new_ino; 1462 | break; 1463 | } 1464 | } 1465 | //write 1466 | fseek(fd, DATA_START + tmp_directory_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET); 1467 | fwrite(¤tDirectory, sizeof(directory), 1, fd); 1468 | 1469 | //Update associations 1470 | directory tmp_directory = currentDirectory; 1471 | int tmp_pos_directory_inode = pos_directory_inode; 1472 | while (true) 1473 | { 1474 | //Update association 1475 | tmp_directory_inode.di_number++; 1476 | fseek(fd, INODE_START + tmp_pos_directory_inode * INODE_SIZE, SEEK_SET); 1477 | fwrite(&tmp_directory_inode, sizeof(inode), 1, fd); 1478 | //If reach the root directory, finish updating. 1479 | if (tmp_directory.inodeID[1] == tmp_directory.inodeID[0]) 1480 | { 1481 | break; 1482 | } 1483 | //Fetch father directory 1484 | tmp_pos_directory_inode = tmp_directory.inodeID[1]; //".." 1485 | fseek(fd, INODE_START + tmp_pos_directory_inode * INODE_SIZE, SEEK_SET); 1486 | fread(&tmp_directory_inode, sizeof(inode), 1, fd); 1487 | fseek(fd, DATA_START + tmp_directory_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET); 1488 | fread(&tmp_directory, sizeof(directory), 1, fd); 1489 | } 1490 | 1491 | /* 1492 | * 8. Update super block. 1493 | */ 1494 | //superBlock.s_num_fblock--; 1495 | superBlock.s_num_finode--; 1496 | fseek(fd, BLOCK_SIZE, SEEK_SET); 1497 | fwrite(&superBlock, sizeof(filsys), 1, fd); 1498 | 1499 | return true; 1500 | }; 1501 | 1502 | /* 1503 | * Delete a drirectory as well as all files and sub-directories in it. 1504 | * 1505 | * return: the function returns true only when the directory as well 1506 | * as all files and sub-directories in it is deleted successfully. 1507 | */ 1508 | bool RemoveDir(const char* dirname) 1509 | { 1510 | //parameter check 1511 | if (dirname == NULL || strlen(dirname) > FILE_NAME_LENGTH) 1512 | { 1513 | printf("Error: Illegal directory name.\n"); 1514 | return false; 1515 | } 1516 | 1517 | /* 1518 | * 1. Check whether the directory exists in current directory. 1519 | */ 1520 | int pos_in_directory = 0; 1521 | int tmp_dir_ino; 1522 | inode tmp_dir_inode; 1523 | do { 1524 | pos_in_directory++; 1525 | for (; pos_in_directory < DIRECTORY_NUM; pos_in_directory++) 1526 | { 1527 | if (strcmp(currentDirectory.fileName[pos_in_directory], dirname) == 0) 1528 | { 1529 | break; 1530 | } 1531 | } 1532 | if (pos_in_directory == DIRECTORY_NUM) 1533 | { 1534 | printf("Delete error: Directory not found.\n"); 1535 | return false; 1536 | } 1537 | 1538 | /* 1539 | * 2. Fetch inode and check whether it's a file. 1540 | */ 1541 | //Fetch inode 1542 | tmp_dir_ino = currentDirectory.inodeID[pos_in_directory]; 1543 | fseek(fd, INODE_START + tmp_dir_ino * INODE_SIZE, SEEK_SET); 1544 | fread(&tmp_dir_inode, sizeof(inode), 1, fd); 1545 | //Directory check 1546 | } while (tmp_dir_inode.di_mode == 1); 1547 | 1548 | /* 1549 | * 3. Access check. 1550 | */ 1551 | if (userID == tmp_dir_inode.di_uid) 1552 | { 1553 | if (!(tmp_dir_inode.permission & OWN_E)) { 1554 | printf("Delete error: Access deny.\n"); 1555 | return false; 1556 | } 1557 | } 1558 | else if (users.groupID[userID] == tmp_dir_inode.di_grp) { 1559 | if (!(tmp_dir_inode.permission & GRP_E)) { 1560 | printf("Delete error: Access deny.\n"); 1561 | return false; 1562 | } 1563 | } 1564 | else { 1565 | if (!(tmp_dir_inode.permission & ELSE_E)) { 1566 | printf("Delete error: Access deny.\n"); 1567 | return false; 1568 | } 1569 | } 1570 | /* 1571 | * 4. Start deleting. Delete all sub-directories and files first. 1572 | */ 1573 | if (tmp_dir_inode.icount > 0) { 1574 | tmp_dir_inode.icount--; 1575 | fseek(fd, INODE_START + tmp_dir_inode.i_ino * INODE_SIZE, SEEK_SET); 1576 | fwrite(&tmp_dir_inode, sizeof(inode), 1, fd); 1577 | /* 1578 | * Update directories 1579 | */ 1580 | //Fetch current directory inode 1581 | int pos_directory_inode = currentDirectory.inodeID[0]; //"." 1582 | inode tmp_directory_inode; 1583 | fseek(fd, INODE_START + pos_directory_inode * INODE_SIZE, SEEK_SET); 1584 | fread(&tmp_directory_inode, sizeof(inode), 1, fd); 1585 | 1586 | //Update current directory item 1587 | memset(currentDirectory.fileName[pos_in_directory], 0, FILE_NAME_LENGTH); 1588 | currentDirectory.inodeID[pos_in_directory] = -1; 1589 | fseek(fd, DATA_START + tmp_directory_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET); 1590 | fwrite(¤tDirectory, sizeof(directory), 1, fd); 1591 | 1592 | //Update associations 1593 | directory tmp_directory = currentDirectory; 1594 | int tmp_pos_directory_inode = pos_directory_inode; 1595 | while (true) 1596 | { 1597 | //Update association 1598 | tmp_directory_inode.di_number--; 1599 | fseek(fd, INODE_START + tmp_pos_directory_inode * INODE_SIZE, SEEK_SET); 1600 | fwrite(&tmp_directory_inode, sizeof(inode), 1, fd); 1601 | //If reach the root directory, finish updating. 1602 | if (tmp_directory.inodeID[1] == tmp_directory.inodeID[0]) 1603 | { 1604 | break; 1605 | } 1606 | //Fetch father directory 1607 | tmp_pos_directory_inode = tmp_directory.inodeID[1]; //".." 1608 | fseek(fd, INODE_START + tmp_pos_directory_inode * INODE_SIZE, SEEK_SET); 1609 | fread(&tmp_directory_inode, sizeof(inode), 1, fd); 1610 | fseek(fd, DATA_START + tmp_directory_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET); 1611 | fread(&tmp_directory, sizeof(directory), 1, fd); 1612 | } 1613 | return true; 1614 | } 1615 | directory tmp_dir; 1616 | fseek(fd, DATA_START + tmp_dir_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET); 1617 | fread(&tmp_dir, sizeof(directory), 1, fd); 1618 | 1619 | //Search all sub files and directories and delete them. 1620 | inode tmp_sub_inode; 1621 | char tmp_sub_filename[FILE_NAME_LENGTH]; 1622 | memset(tmp_sub_filename, 0, FILE_NAME_LENGTH); 1623 | for (int i = 2; i < DIRECTORY_NUM; i++) 1624 | { 1625 | if (strlen(tmp_dir.fileName[i]) > 0) 1626 | { 1627 | strcpy(tmp_sub_filename, tmp_dir.fileName[i]); 1628 | //Determine whether it's a file or a directory. 1629 | fseek(fd, INODE_START + tmp_dir.inodeID[i] * INODE_SIZE, SEEK_SET); 1630 | fread(&tmp_sub_inode, sizeof(inode), 1, fd); 1631 | //Before delete sub files and directories, change current directory first and recover after deleting. 1632 | directory tmp_swp; 1633 | tmp_swp = currentDirectory; 1634 | currentDirectory = tmp_dir; 1635 | tmp_dir = tmp_swp; 1636 | //Is a file. 1637 | if (tmp_sub_inode.di_mode == 1) 1638 | { 1639 | DeleteFile(tmp_sub_filename); 1640 | } 1641 | //Is a directory. 1642 | else if (tmp_sub_inode.di_mode == 0) 1643 | { 1644 | RemoveDir(tmp_sub_filename); 1645 | } 1646 | tmp_swp = currentDirectory; 1647 | currentDirectory = tmp_dir; 1648 | tmp_dir = tmp_swp; 1649 | } 1650 | } 1651 | 1652 | /* 1653 | * 5. Start deleting itself. Fill the inode's original space with 0s. 1654 | */ 1655 | //Fill original space 1656 | int tmp_fill[sizeof(inode)]; 1657 | memset(tmp_fill, 0, sizeof(inode)); 1658 | fseek(fd, INODE_START + tmp_dir_ino * INODE_SIZE, SEEK_SET); 1659 | fwrite(&tmp_fill, sizeof(inode), 1, fd); 1660 | 1661 | /* 1662 | * 6. Update bitmaps 1663 | */ 1664 | //inode bitmap 1665 | inode_bitmap[tmp_dir_ino] = 0; 1666 | fseek(fd, 2 * BLOCK_SIZE, SEEK_SET); 1667 | fwrite(&inode_bitmap, sizeof(unsigned short) * INODE_NUM, 1, fd); 1668 | //block bitmap 1669 | for (int i = 0; i < (tmp_dir_inode.di_size / BLOCK_SIZE + 1); i++) 1670 | { 1671 | recycle_block(tmp_dir_inode.di_addr[i]); 1672 | } 1673 | 1674 | /* 1675 | * 7. Update directories 1676 | */ 1677 | //Fetch current directory inode 1678 | int pos_directory_inode = currentDirectory.inodeID[0]; //"." 1679 | inode tmp_directory_inode; 1680 | fseek(fd, INODE_START + pos_directory_inode * INODE_SIZE, SEEK_SET); 1681 | fread(&tmp_directory_inode, sizeof(inode), 1, fd); 1682 | 1683 | //Update current directory item 1684 | memset(currentDirectory.fileName[pos_in_directory], 0, FILE_NAME_LENGTH); 1685 | currentDirectory.inodeID[pos_in_directory] = -1; 1686 | fseek(fd, DATA_START + tmp_directory_inode.di_addr[0] * INODE_SIZE, SEEK_SET); 1687 | fwrite(¤tDirectory, sizeof(directory), 1, fd); 1688 | 1689 | //Update associations 1690 | directory tmp_directory = currentDirectory; 1691 | int tmp_pos_directory_inode = pos_directory_inode; 1692 | while (true) 1693 | { 1694 | //Update association 1695 | tmp_directory_inode.di_number--; 1696 | fseek(fd, INODE_START + tmp_pos_directory_inode * INODE_SIZE, SEEK_SET); 1697 | fwrite(&tmp_directory_inode, sizeof(inode), 1, fd); 1698 | //If reach the root directory, finish updating. 1699 | if (tmp_directory.inodeID[1] == tmp_directory.inodeID[0]) 1700 | { 1701 | break; 1702 | } 1703 | //Fetch father directory 1704 | tmp_pos_directory_inode = tmp_directory.inodeID[1]; //".." 1705 | fseek(fd, INODE_START + tmp_pos_directory_inode * INODE_SIZE, SEEK_SET); 1706 | fread(&tmp_directory_inode, sizeof(inode), 1, fd); 1707 | fseek(fd, DATA_START + tmp_directory_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET); 1708 | fread(&tmp_directory, sizeof(directory), 1, fd); 1709 | } 1710 | 1711 | /* 1712 | * 78 Update super block 1713 | */ 1714 | //superBlock.s_num_fblock += tmp_dir_inode.di_size / BLOCK_SIZE + 1; 1715 | superBlock.s_num_finode++; 1716 | fseek(fd, BLOCK_SIZE, SEEK_SET); 1717 | fwrite(&superBlock, sizeof(filsys), 1, fd); 1718 | 1719 | return true; 1720 | }; 1721 | 1722 | /* 1723 | * Open a directory. 1724 | * 1725 | * return: the function returns true only when the directory is 1726 | * opened successfully. 1727 | */ 1728 | bool OpenDir(const char* dirname) 1729 | { 1730 | //parameter check 1731 | if (dirname == NULL || strlen(dirname) > FILE_NAME_LENGTH) 1732 | { 1733 | printf("Error: Illegal directory name.\n"); 1734 | return false; 1735 | } 1736 | /* 1737 | * 1. Check whether the directory exists in current directory. 1738 | */ 1739 | int pos_in_directory = 0; 1740 | inode tmp_dir_inode; 1741 | int tmp_dir_ino; 1742 | do { 1743 | for (; pos_in_directory < DIRECTORY_NUM; pos_in_directory++) 1744 | { 1745 | if (strcmp(currentDirectory.fileName[pos_in_directory], dirname) == 0) 1746 | { 1747 | break; 1748 | } 1749 | } 1750 | if (pos_in_directory == DIRECTORY_NUM) 1751 | { 1752 | printf("Delete error: Directory not found.\n"); 1753 | return false; 1754 | } 1755 | 1756 | /* 1757 | * 2. Fetch inode and check whether it's a file. 1758 | */ 1759 | //Fetch inode 1760 | tmp_dir_ino = currentDirectory.inodeID[pos_in_directory]; 1761 | fseek(fd, INODE_START + tmp_dir_ino * INODE_SIZE, SEEK_SET); 1762 | fread(&tmp_dir_inode, sizeof(inode), 1, fd); 1763 | //Directory check 1764 | } while (tmp_dir_inode.di_mode == 1); 1765 | //ACCESS CHECK 1766 | if (userID == tmp_dir_inode.di_uid) 1767 | { 1768 | if (tmp_dir_inode.permission & OWN_E != OWN_E) { 1769 | printf("Open dir error: Access deny.\n"); 1770 | return NULL; 1771 | } 1772 | } 1773 | else if (users.groupID[userID] == tmp_dir_inode.di_grp) { 1774 | if (tmp_dir_inode.permission & GRP_E != GRP_E) { 1775 | printf("Open dir error: Access deny.\n"); 1776 | return NULL; 1777 | } 1778 | } 1779 | else { 1780 | if (tmp_dir_inode.permission & ELSE_E != ELSE_E) { 1781 | printf("Open dir error: Access deny.\n"); 1782 | return NULL; 1783 | } 1784 | } 1785 | /* 1786 | * 3. Update current directory. 1787 | */ 1788 | directory new_current_dir; 1789 | fseek(fd, DATA_START + tmp_dir_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET); 1790 | fread(&new_current_dir, sizeof(directory), 1, fd); 1791 | currentDirectory = new_current_dir; 1792 | if (dirname[0] == '.' && dirname[1] == 0) { 1793 | dir_pointer; 1794 | } 1795 | else if (dirname[0] == '.' && dirname[1] == '.' && dirname[2] == 0) { 1796 | if (dir_pointer != 0) dir_pointer--; 1797 | } 1798 | else { 1799 | for (int i = 0; i < 14; i++) { 1800 | ab_dir[dir_pointer][i] = dirname[i]; 1801 | } 1802 | dir_pointer++; 1803 | } 1804 | return true; 1805 | }; 1806 | 1807 | /* 1808 | * Print file and directory information under current directory. 1809 | */ 1810 | void List() 1811 | { 1812 | printf("\n name\tuser\tgroup\tinodeID\tIcount\tsize\tpermission\ttime\n"); 1813 | for (int i = 0; i < DIRECTORY_NUM; i++) 1814 | { 1815 | if (strlen(currentDirectory.fileName[i]) > 0) 1816 | { 1817 | inode tmp_inode; 1818 | fseek(fd, INODE_START + currentDirectory.inodeID[i] * INODE_SIZE, SEEK_SET); 1819 | fread(&tmp_inode, sizeof(inode), 1, fd); 1820 | 1821 | const char* tmp_type = tmp_inode.di_mode == 0 ? "d" : "-"; 1822 | const char* tmp_user = users.userName[tmp_inode.di_uid]; 1823 | const int tmp_grpID = tmp_inode.di_grp; 1824 | 1825 | printf("%10s\t%s\t%d\t%d\t%d\t%u\t%s", currentDirectory.fileName[i], tmp_user, tmp_grpID, tmp_inode.i_ino, tmp_inode.icount, tmp_inode.di_size, tmp_type); 1826 | for (int x = 8; x > 0; x--) { 1827 | if (tmp_inode.permission & (1 << x)) { 1828 | if ((x + 1) % 3 == 0) printf("r"); 1829 | else if ((x + 1) % 3 == 2) printf("w"); 1830 | else printf("x"); 1831 | } 1832 | else printf("-"); 1833 | } 1834 | if(tmp_inode.permission & 1) printf("x\t"); 1835 | else printf("-\t"); 1836 | printf("%s\n", tmp_inode.time); 1837 | } 1838 | } 1839 | 1840 | printf("\n\n"); 1841 | } 1842 | 1843 | /* 1844 | * Print absolute directory. 1845 | */ 1846 | void Ab_dir() { 1847 | for (int i = 0; i < dir_pointer; i++) 1848 | printf("%s/", ab_dir[i]); 1849 | printf("\n"); 1850 | } 1851 | 1852 | /* 1853 | * Change file permission. 1854 | */ 1855 | void Chmod(char* filename) { 1856 | printf("File or Dir?(0 stands for file, 1 for dir):"); 1857 | int tt; 1858 | scanf("%d", &tt); 1859 | //parameter check 1860 | if (filename == NULL || strlen(filename) > FILE_NAME_LENGTH) 1861 | { 1862 | printf("Error: Illegal file name.\n"); 1863 | return; 1864 | } 1865 | 1866 | /* 1867 | * 1. Check whether the file exists in current directory. 1868 | */ 1869 | int pos_in_directory = -1; 1870 | inode* tmp_file_inode = new inode; 1871 | do { 1872 | pos_in_directory++; 1873 | for (; pos_in_directory < DIRECTORY_NUM; pos_in_directory++) 1874 | { 1875 | if (strcmp(currentDirectory.fileName[pos_in_directory], filename) == 0) 1876 | { 1877 | break; 1878 | } 1879 | } 1880 | if (pos_in_directory == DIRECTORY_NUM) 1881 | { 1882 | printf("Not found.\n"); 1883 | return; 1884 | } 1885 | 1886 | /* 1887 | * 2. Fetch inode and check whether it's a directory. 1888 | */ 1889 | //Fetch inode 1890 | int tmp_file_ino = currentDirectory.inodeID[pos_in_directory]; 1891 | fseek(fd, INODE_START + tmp_file_ino * INODE_SIZE, SEEK_SET); 1892 | fread(tmp_file_inode, sizeof(inode), 1, fd); 1893 | //Directory check 1894 | } while (tmp_file_inode->di_mode == tt); 1895 | 1896 | printf("Please input 0&1 string(1 stands for having, 0 for not)\n"); 1897 | printf("Format: rwerwerwe\n"); 1898 | char str[10]; 1899 | scanf("%s", &str); 1900 | if (userID == tmp_file_inode->di_uid) 1901 | { 1902 | if (!(tmp_file_inode->permission & OWN_E)) { 1903 | printf("Open file error: Access deny.\n"); 1904 | return; 1905 | } 1906 | } 1907 | else if (users.groupID[userID] == tmp_file_inode->di_grp) { 1908 | if (!(tmp_file_inode->permission & GRP_E)) { 1909 | printf("Open file error: Access deny.\n"); 1910 | return; 1911 | } 1912 | } 1913 | else { 1914 | if (!(tmp_file_inode->permission & ELSE_E)) { 1915 | printf("Open file error: Access deny.\n"); 1916 | return; 1917 | } 1918 | } 1919 | int temp = 0; 1920 | for (int i = 0; i < 8; i++) { 1921 | if (str[i] == '1') 1922 | temp += 1 << (8 - i); 1923 | } 1924 | if (str[8] == '1') temp += 1; 1925 | tmp_file_inode->permission = temp; 1926 | fseek(fd, INODE_START + tmp_file_inode->i_ino * INODE_SIZE, SEEK_SET); 1927 | fwrite(tmp_file_inode, sizeof(inode), 1, fd); 1928 | return; 1929 | } 1930 | 1931 | /* 1932 | * Change file' owner. 1933 | */ 1934 | void Chown(char* filename) { 1935 | printf("File or Dir?(0 stands for file, 1 for dir):"); 1936 | int tt; 1937 | scanf("%d", &tt); 1938 | //parameter check 1939 | if (filename == NULL || strlen(filename) > FILE_NAME_LENGTH) 1940 | { 1941 | printf("Error: Illegal file name.\n"); 1942 | return; 1943 | } 1944 | 1945 | /* 1946 | * 1. Check whether the file exists in current directory. 1947 | */ 1948 | int pos_in_directory = -1; 1949 | inode* tmp_file_inode = new inode; 1950 | do { 1951 | pos_in_directory++; 1952 | for (; pos_in_directory < DIRECTORY_NUM; pos_in_directory++) 1953 | { 1954 | if (strcmp(currentDirectory.fileName[pos_in_directory], filename) == 0) 1955 | { 1956 | break; 1957 | } 1958 | } 1959 | if (pos_in_directory == DIRECTORY_NUM) 1960 | { 1961 | printf("Not found.\n"); 1962 | return; 1963 | } 1964 | 1965 | /* 1966 | * 2. Fetch inode and check whether it's a directory. 1967 | */ 1968 | //Fetch inode 1969 | int tmp_file_ino = currentDirectory.inodeID[pos_in_directory]; 1970 | fseek(fd, INODE_START + tmp_file_ino * INODE_SIZE, SEEK_SET); 1971 | fread(tmp_file_inode, sizeof(inode), 1, fd); 1972 | //Directory check 1973 | } while (tmp_file_inode->di_mode == tt); 1974 | 1975 | if (userID == tmp_file_inode->di_uid) 1976 | { 1977 | if (!(tmp_file_inode->permission & OWN_E)) { 1978 | printf("Open file error: Access deny.\n"); 1979 | return; 1980 | } 1981 | } 1982 | else if (users.groupID[userID] == tmp_file_inode->di_grp) { 1983 | if (!(tmp_file_inode->permission & GRP_E)) { 1984 | printf("Open file error: Access deny.\n"); 1985 | return; 1986 | } 1987 | } 1988 | else { 1989 | if (!(tmp_file_inode->permission & ELSE_E)) { 1990 | printf("Open file error: Access deny.\n"); 1991 | return; 1992 | } 1993 | } 1994 | 1995 | printf("Please input user name:"); 1996 | char str[USER_NAME_LENGTH]; 1997 | int i; 1998 | scanf("%s", str); 1999 | for (i = 0; i < ACCOUNT_NUM; i++) { 2000 | if (strcmp(users.userName[i], str) == 0) break; 2001 | } 2002 | if (i == ACCOUNT_NUM) { 2003 | printf("Error user!\n"); 2004 | return; 2005 | } 2006 | tmp_file_inode->di_uid = i; 2007 | fseek(fd, INODE_START + tmp_file_inode->i_ino * INODE_SIZE, SEEK_SET); 2008 | fwrite(tmp_file_inode, sizeof(inode), 1, fd); 2009 | return; 2010 | } 2011 | 2012 | /* 2013 | * Change file' group. 2014 | */ 2015 | void Chgrp(char* filename) { 2016 | printf("File or Dir?(0 stands for file, 1 for dir):"); 2017 | int tt; 2018 | scanf("%d", &tt); 2019 | //parameter check 2020 | if (filename == NULL || strlen(filename) > FILE_NAME_LENGTH) 2021 | { 2022 | printf("Error: Illegal file name.\n"); 2023 | return; 2024 | } 2025 | 2026 | /* 2027 | * 1. Check whether the file exists in current directory. 2028 | */ 2029 | int pos_in_directory = -1; 2030 | inode* tmp_file_inode = new inode; 2031 | do { 2032 | pos_in_directory++; 2033 | for (; pos_in_directory < DIRECTORY_NUM; pos_in_directory++) 2034 | { 2035 | if (strcmp(currentDirectory.fileName[pos_in_directory], filename) == 0) 2036 | { 2037 | break; 2038 | } 2039 | } 2040 | if (pos_in_directory == DIRECTORY_NUM) 2041 | { 2042 | printf("Not found.\n"); 2043 | return; 2044 | } 2045 | 2046 | /* 2047 | * 2. Fetch inode and check whether it's a directory. 2048 | */ 2049 | //Fetch inode 2050 | int tmp_file_ino = currentDirectory.inodeID[pos_in_directory]; 2051 | fseek(fd, INODE_START + tmp_file_ino * INODE_SIZE, SEEK_SET); 2052 | fread(tmp_file_inode, sizeof(inode), 1, fd); 2053 | //Directory check 2054 | } while (tmp_file_inode->di_mode == tt); 2055 | 2056 | if (userID == tmp_file_inode->di_uid) 2057 | { 2058 | if (!(tmp_file_inode->permission & OWN_E)) { 2059 | printf("Open file error: Access deny.\n"); 2060 | return; 2061 | } 2062 | } 2063 | else if (users.groupID[userID] == tmp_file_inode->di_grp) { 2064 | if (!(tmp_file_inode->permission & GRP_E)) { 2065 | printf("Open file error: Access deny.\n"); 2066 | return; 2067 | } 2068 | } 2069 | else { 2070 | if (!(tmp_file_inode->permission & ELSE_E)) { 2071 | printf("Open file error: Access deny.\n"); 2072 | return; 2073 | } 2074 | } 2075 | 2076 | printf("Please input group number:"); 2077 | int ttt, i; 2078 | scanf("%d", &ttt); 2079 | for (i = 0; i < ACCOUNT_NUM; i++) { 2080 | if (users.groupID[i] == ttt) break; 2081 | } 2082 | if (i == ACCOUNT_NUM) { 2083 | printf("Error user!\n"); 2084 | return; 2085 | } 2086 | tmp_file_inode->di_grp = ttt; 2087 | fseek(fd, INODE_START + tmp_file_inode->i_ino * INODE_SIZE, SEEK_SET); 2088 | fwrite(tmp_file_inode, sizeof(inode), 1, fd); 2089 | return; 2090 | } 2091 | 2092 | /* 2093 | * Change password. 2094 | */ 2095 | void Passwd() { 2096 | printf("Please input old password:"); 2097 | char str[USER_PASSWORD_LENGTH]; 2098 | scanf("%s", str); 2099 | str[USER_PASSWORD_LENGTH] = 0; 2100 | if (strcmp(users.password[userID], str) == 0) { 2101 | printf("Please input a new password:"); 2102 | scanf("%s", str); 2103 | if (strcmp(users.password[userID], str) == 0) { 2104 | printf("Password doesn't change!\n"); 2105 | } 2106 | else { 2107 | strcpy(users.password[userID], str); 2108 | //Write 2109 | fseek(fd, DATA_START + BLOCK_SIZE, SEEK_SET); 2110 | fwrite(&users, sizeof(users), 1, fd); 2111 | printf("Success\n"); 2112 | } 2113 | } 2114 | else { 2115 | printf("Password Error!!!\n"); 2116 | } 2117 | } 2118 | 2119 | /* 2120 | * User Management. 2121 | */ 2122 | void User_management() { 2123 | if (userID != 0) { 2124 | printf("Only administrator can manage users!\n"); 2125 | return; 2126 | } 2127 | printf("Welcome to user management!\n"); 2128 | char c, d; 2129 | scanf("%c", &c); 2130 | while (c != '0') { 2131 | printf("\n1.View 2.Insert 3.Remove 0.Save & Exit\n"); 2132 | scanf("%c", &c); 2133 | switch (c) { 2134 | case '1': 2135 | for (int i = 0; i < ACCOUNT_NUM; i++) { 2136 | if (users.userName[i][0] != 0) 2137 | printf("%d\t%s\t%d\n", users.userID[i], users.userName[i], users.groupID[i]); 2138 | else break; 2139 | } 2140 | scanf("%c", &c); 2141 | break; 2142 | case '2': 2143 | int i; 2144 | for (i = 0; i < ACCOUNT_NUM; i++) { 2145 | if (users.userName[i][0] == 0) break; 2146 | } 2147 | if (i == ACCOUNT_NUM) { 2148 | printf("Users Full!\n"); 2149 | break; 2150 | } 2151 | printf("Please input username:"); 2152 | char str[USER_NAME_LENGTH]; 2153 | scanf("%s", str); 2154 | for (i = 0; i < ACCOUNT_NUM; i++) { 2155 | if (strcmp(users.userName[i], str) == 0) { 2156 | printf("Already has same name user!\n"); 2157 | } 2158 | if (users.userName[i][0] == 0) { 2159 | strcpy(users.userName[i], str); 2160 | printf("Please input password:"); 2161 | scanf("%s", str); 2162 | strcpy(users.password[i], str); 2163 | printf("Please input group ID:"); 2164 | int t; 2165 | scanf("%d", &t); 2166 | scanf("%c", &c); 2167 | if (t > 0) { 2168 | users.groupID[i] = t; 2169 | printf("Success!\n"); 2170 | } 2171 | else { 2172 | printf("Insert Error!\n"); 2173 | strcpy(users.userName[i], 0); 2174 | strcpy(users.password[i], 0); 2175 | } 2176 | break; 2177 | } 2178 | } 2179 | break; 2180 | case '3': 2181 | printf("Please input userID:"); 2182 | int tmp; 2183 | scanf("%d", &tmp);scanf("%c", &c); 2184 | for (int j = tmp; j < ACCOUNT_NUM - 1; j++) { 2185 | strcpy(users.userName[j], users.userName[j + 1]); 2186 | strcpy(users.password[j], users.password[j + 1]); 2187 | users.groupID[j] = users.groupID[j+1]; 2188 | } 2189 | printf("Success!\n"); 2190 | } 2191 | } 2192 | fseek(fd, DATA_START + BLOCK_SIZE, SEEK_SET); 2193 | fwrite(&users, sizeof(users), 1, fd); 2194 | } 2195 | 2196 | /* 2197 | * Rename file/dir. 2198 | */ 2199 | void Rename(char* filename) { 2200 | printf("File or Dir?(0 stands for file, 1 for dir):"); 2201 | int tt; 2202 | scanf("%d", &tt); 2203 | //parameter check 2204 | if (filename == NULL || strlen(filename) > FILE_NAME_LENGTH) 2205 | { 2206 | printf("Error: Illegal file name.\n"); 2207 | return; 2208 | } 2209 | 2210 | /* 2211 | * 1. Check whether the file exists in current directory. 2212 | */ 2213 | int pos_in_directory = -1; 2214 | inode* tmp_file_inode = new inode; 2215 | do { 2216 | pos_in_directory++; 2217 | for (; pos_in_directory < DIRECTORY_NUM; pos_in_directory++) 2218 | { 2219 | if (strcmp(currentDirectory.fileName[pos_in_directory], filename) == 0) 2220 | { 2221 | break; 2222 | } 2223 | } 2224 | if (pos_in_directory == DIRECTORY_NUM) 2225 | { 2226 | printf("Not found.\n"); 2227 | return; 2228 | } 2229 | 2230 | /* 2231 | * 2. Fetch inode and check whether it's a directory. 2232 | */ 2233 | //Fetch inode 2234 | int tmp_file_ino = currentDirectory.inodeID[pos_in_directory]; 2235 | fseek(fd, INODE_START + tmp_file_ino * INODE_SIZE, SEEK_SET); 2236 | fread(tmp_file_inode, sizeof(inode), 1, fd); 2237 | //Directory check 2238 | } while (tmp_file_inode->di_mode == tt); 2239 | 2240 | printf("Please input new file name:"); 2241 | char str[14]; 2242 | scanf("%s", str); 2243 | str[14] = 0; 2244 | for (int i = 0; i < DIRECTORY_NUM; i++) 2245 | { 2246 | if (currentDirectory.inodeID[i] == tmp_file_inode->i_ino) 2247 | { 2248 | strcpy(currentDirectory.fileName[i], str); 2249 | break; 2250 | } 2251 | } 2252 | //write 2253 | fseek(fd, DATA_START + tmp_file_inode->di_addr[0] * BLOCK_SIZE, SEEK_SET); 2254 | fwrite(¤tDirectory, sizeof(directory), 1, fd); 2255 | return; 2256 | } 2257 | 2258 | /* 2259 | * Link. 2260 | */ 2261 | bool ln(char* filename) 2262 | { 2263 | printf("File or Dir?(0 stands for file, 1 for dir):"); 2264 | int tt; 2265 | scanf("%d", &tt); 2266 | //parameter check 2267 | if (filename == NULL || strlen(filename) > FILE_NAME_LENGTH) 2268 | { 2269 | printf("Error: Illegal file name.\n"); 2270 | return false; 2271 | } 2272 | 2273 | /* 2274 | * 1. Check whether the file exists in current directory. 2275 | */ 2276 | int pos_in_directory = -1; 2277 | inode* tmp_file_inode = new inode; 2278 | do { 2279 | pos_in_directory++; 2280 | for (; pos_in_directory < DIRECTORY_NUM; pos_in_directory++) 2281 | { 2282 | if (strcmp(currentDirectory.fileName[pos_in_directory], filename) == 0) 2283 | { 2284 | break; 2285 | } 2286 | } 2287 | if (pos_in_directory == DIRECTORY_NUM) 2288 | { 2289 | printf("Not found.\n"); 2290 | return false; 2291 | } 2292 | 2293 | /* 2294 | * 2. Fetch inode and check whether it's a directory. 2295 | */ 2296 | //Fetch inode 2297 | int tmp_file_ino = currentDirectory.inodeID[pos_in_directory]; 2298 | fseek(fd, INODE_START + tmp_file_ino * INODE_SIZE, SEEK_SET); 2299 | fread(tmp_file_inode, sizeof(inode), 1, fd); 2300 | //Directory check 2301 | } while (tmp_file_inode->di_mode == tt); 2302 | 2303 | //Access check 2304 | 2305 | if (userID == tmp_file_inode->di_uid) 2306 | { 2307 | if (!(tmp_file_inode->permission & OWN_E)) { 2308 | printf("Delete error: Access deny.\n"); 2309 | return false; 2310 | } 2311 | } 2312 | else if (users.groupID[userID] == tmp_file_inode->di_grp) { 2313 | if (!(tmp_file_inode->permission & GRP_E)) { 2314 | printf("Delete error: Access deny.\n"); 2315 | return false; 2316 | } 2317 | } 2318 | else { 2319 | if (!(tmp_file_inode->permission & ELSE_E)) { 2320 | printf("Delete error: Access deny.\n"); 2321 | return false; 2322 | } 2323 | } 2324 | //get absolute path 2325 | char absolute[1024]; 2326 | int path_pos = 0; 2327 | printf("Input absolute path(end with '#'):"); 2328 | scanf("%s", absolute); 2329 | //get directory inode 2330 | char dirname[14]; 2331 | int pos_dir = 0; 2332 | bool root = false; 2333 | inode dir_inode; 2334 | directory cur_dir; 2335 | int i; 2336 | for (i = 0; i < 5; i++) 2337 | { 2338 | dirname[i] = absolute[i]; 2339 | } 2340 | dirname[i] = 0; 2341 | if (strcmp("root/", dirname) != 0) 2342 | { 2343 | printf("path error!\n"); 2344 | return false; 2345 | } 2346 | fseek(fd, INODE_START, SEEK_SET); 2347 | fread(&dir_inode, sizeof(inode), 1, fd); 2348 | for (int i = 5; absolute[i] != '#'; i++) 2349 | { 2350 | if (absolute[i] == '/') 2351 | { 2352 | dirname[pos_dir++] = 0; 2353 | pos_dir = 0; 2354 | fseek(fd, DATA_START + dir_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET); 2355 | fread(&cur_dir, sizeof(directory), 1, fd); 2356 | int i; 2357 | for (i = 0; i < DIRECTORY_NUM; i++) 2358 | { 2359 | if (strcmp(cur_dir.fileName[i], dirname) == 0) 2360 | { 2361 | fseek(fd, INODE_START + cur_dir.inodeID[i] * INODE_SIZE, SEEK_SET); 2362 | fread(&dir_inode, sizeof(inode), 1, fd); 2363 | if (dir_inode.di_mode == 0)break; 2364 | } 2365 | } 2366 | if (i == DIRECTORY_NUM) 2367 | { 2368 | printf("path error!\n"); 2369 | return false; 2370 | } 2371 | } 2372 | else 2373 | dirname[pos_dir++] = absolute[i]; 2374 | } 2375 | //update this directory 2376 | fseek(fd, DATA_START + dir_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET); 2377 | fread(&cur_dir, sizeof(directory), 1, fd); 2378 | for (i = 0; i < DIRECTORY_NUM; i++) 2379 | { 2380 | if (strlen(cur_dir.fileName[i]) == 0) 2381 | { 2382 | strcat(cur_dir.fileName[i], filename); 2383 | cur_dir.inodeID[i] = tmp_file_inode->i_ino; 2384 | break; 2385 | } 2386 | } 2387 | if (i == DIRECTORY_NUM) 2388 | { 2389 | printf("No value iterms!\n"); 2390 | return false; 2391 | } 2392 | fseek(fd, DATA_START + dir_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET); 2393 | fwrite(&cur_dir, sizeof(directory), 1, fd); 2394 | dir_inode.di_number++; 2395 | tmp_file_inode->icount++; 2396 | fseek(fd, INODE_START + tmp_file_inode->i_ino*INODE_SIZE, SEEK_SET); 2397 | fwrite(tmp_file_inode, sizeof(inode), 1, fd); 2398 | return true; 2399 | } 2400 | 2401 | /* 2402 | * File copy. 2403 | */ 2404 | bool Copy(char* filename, inode*& currentInode) { 2405 | currentInode = OpenFile(filename); 2406 | int block_num = currentInode->di_size / BLOCK_SIZE + 1; 2407 | //Read file from data blocks 2408 | char stack[BLOCK_SIZE]; 2409 | char str[100000]; 2410 | int cnt = 0; 2411 | if (block_num <= NADDR - 2) 2412 | { 2413 | for (int i = 0; i < block_num; i++) 2414 | { 2415 | if (currentInode->di_addr[i] == -1) break; 2416 | fseek(fd, DATA_START + currentInode->di_addr[i] * BLOCK_SIZE, SEEK_SET); 2417 | fread(stack, sizeof(stack), 1, fd); 2418 | for (int j = 0; j < BLOCK_SIZE; j++) 2419 | { 2420 | if (stack[j] == '\0') { 2421 | str[cnt] = 0; 2422 | break; 2423 | } 2424 | str[cnt++] = stack[j]; 2425 | } 2426 | } 2427 | //int i = 0; 2428 | } 2429 | else if (block_num > NADDR - 2) { 2430 | //direct addressing 2431 | for (int i = 0; i < NADDR - 2; i++) 2432 | { 2433 | fseek(fd, DATA_START + currentInode->di_addr[i] * BLOCK_SIZE, SEEK_SET); 2434 | fread(stack, sizeof(stack), 1, fd); 2435 | for (int j = 0; j < BLOCK_SIZE; j++) 2436 | { 2437 | if (stack[j] == '\0') { 2438 | str[cnt] = 0; 2439 | break; 2440 | } 2441 | str[cnt++] = stack[j]; 2442 | } 2443 | } 2444 | 2445 | //first indirect addressing 2446 | unsigned int f1[BLOCK_SIZE / sizeof(unsigned int)] = { 0 }; 2447 | fseek(fd, DATA_START + currentInode->di_addr[NADDR - 2] * BLOCK_SIZE, SEEK_SET); 2448 | fread(f1, sizeof(f1), 1, fd); 2449 | for (int i = 0; i < block_num - (NADDR - 2); i++) { 2450 | fseek(fd, DATA_START + f1[i] * BLOCK_SIZE, SEEK_SET); 2451 | fread(stack, sizeof(stack), 1, fd); 2452 | for (int j = 0; j < BLOCK_SIZE; j++) 2453 | { 2454 | if (stack[j] == '\0') { 2455 | str[cnt] = 0; 2456 | break; 2457 | } 2458 | str[cnt++] = stack[j]; 2459 | } 2460 | } 2461 | } 2462 | 2463 | int pos_in_directory = -1; 2464 | inode* tmp_file_inode = new inode; 2465 | do { 2466 | pos_in_directory++; 2467 | for (; pos_in_directory < DIRECTORY_NUM; pos_in_directory++) 2468 | { 2469 | if (strcmp(currentDirectory.fileName[pos_in_directory], filename) == 0) 2470 | { 2471 | break; 2472 | } 2473 | } 2474 | if (pos_in_directory == DIRECTORY_NUM) 2475 | { 2476 | printf("Not found.\n"); 2477 | return false; 2478 | } 2479 | 2480 | /* 2481 | * 2. Fetch inode and check whether it's a directory. 2482 | */ 2483 | //Fetch inode 2484 | int tmp_file_ino = currentDirectory.inodeID[pos_in_directory]; 2485 | fseek(fd, INODE_START + tmp_file_ino * INODE_SIZE, SEEK_SET); 2486 | fread(tmp_file_inode, sizeof(inode), 1, fd); 2487 | //Directory check 2488 | } while (tmp_file_inode->di_mode == 0); 2489 | 2490 | //Access check 2491 | 2492 | if (userID == tmp_file_inode->di_uid) 2493 | { 2494 | if (!(tmp_file_inode->permission & OWN_E)) { 2495 | printf("Delete error: Access deny.\n"); 2496 | return false; 2497 | } 2498 | } 2499 | else if (users.groupID[userID] == tmp_file_inode->di_grp) { 2500 | if (!(tmp_file_inode->permission & GRP_E)) { 2501 | printf("Delete error: Access deny.\n"); 2502 | return false; 2503 | } 2504 | } 2505 | else { 2506 | if (!(tmp_file_inode->permission & ELSE_E)) { 2507 | printf("Delete error: Access deny.\n"); 2508 | return false; 2509 | } 2510 | } 2511 | //get absolute path 2512 | char absolute[1024]; 2513 | int path_pos = 0; 2514 | printf("Input absolute path(end with '#'):"); 2515 | scanf("%s", absolute); 2516 | //get directory inode 2517 | char dirname[14]; 2518 | int pos_dir = 0; 2519 | bool root = false; 2520 | inode dir_inode; 2521 | directory cur_dir; 2522 | int i; 2523 | for (i = 0; i < 5; i++) 2524 | { 2525 | dirname[i] = absolute[i]; 2526 | } 2527 | dirname[i] = 0; 2528 | if (strcmp("root/", dirname) != 0) 2529 | { 2530 | printf("path error!\n"); 2531 | return false; 2532 | } 2533 | fseek(fd, INODE_START, SEEK_SET); 2534 | fread(&dir_inode, sizeof(inode), 1, fd); 2535 | for (int i = 5; absolute[i] != '#'; i++) 2536 | { 2537 | if (absolute[i] == '/') 2538 | { 2539 | dirname[pos_dir++] = 0; 2540 | pos_dir = 0; 2541 | fseek(fd, DATA_START + dir_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET); 2542 | fread(&cur_dir, sizeof(directory), 1, fd); 2543 | int i; 2544 | for (i = 0; i < DIRECTORY_NUM; i++) 2545 | { 2546 | if (strcmp(cur_dir.fileName[i], dirname) == 0) 2547 | { 2548 | fseek(fd, INODE_START + cur_dir.inodeID[i] * INODE_SIZE, SEEK_SET); 2549 | fread(&dir_inode, sizeof(inode), 1, fd); 2550 | if (dir_inode.di_mode == 0)break; 2551 | } 2552 | } 2553 | if (i == DIRECTORY_NUM) 2554 | { 2555 | printf("path error!\n"); 2556 | return false; 2557 | } 2558 | } 2559 | else 2560 | dirname[pos_dir++] = absolute[i]; 2561 | } 2562 | //update this directory 2563 | fseek(fd, DATA_START + dir_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET); 2564 | fread(&cur_dir, sizeof(directory), 1, fd); 2565 | for (i = 0; i < DIRECTORY_NUM; i++) 2566 | { 2567 | if (strlen(cur_dir.fileName[i]) == 0) 2568 | { 2569 | strcat(cur_dir.fileName[i], filename); 2570 | int new_ino = 0; 2571 | for (; new_ino < INODE_NUM; new_ino++) 2572 | { 2573 | if (inode_bitmap[new_ino] == 0) 2574 | { 2575 | break; 2576 | } 2577 | } 2578 | inode ifile_tmp; 2579 | ifile_tmp.i_ino = new_ino; //Identification 2580 | ifile_tmp.icount = 0; 2581 | ifile_tmp.di_uid = tmp_file_inode->di_uid; 2582 | ifile_tmp.di_grp = tmp_file_inode->di_grp; 2583 | ifile_tmp.di_mode = tmp_file_inode->di_mode; 2584 | memset(ifile_tmp.di_addr, -1, sizeof(unsigned int) * NADDR); 2585 | ifile_tmp.di_size = 0; 2586 | ifile_tmp.permission = tmp_file_inode->permission; 2587 | time_t t = time(0); 2588 | strftime(ifile_tmp.time, sizeof(ifile_tmp.time), "%Y/%m/%d %X %A %jday %z", localtime(&t)); 2589 | cur_dir.inodeID[i] = new_ino; 2590 | Write(ifile_tmp, str); 2591 | //Update bitmaps 2592 | inode_bitmap[new_ino] = 1; 2593 | fseek(fd, 2 * BLOCK_SIZE, SEEK_SET); 2594 | fwrite(inode_bitmap, sizeof(unsigned short) * INODE_NUM, 1, fd); 2595 | superBlock.s_num_finode--; 2596 | fseek(fd, BLOCK_SIZE, SEEK_SET); 2597 | fwrite(&superBlock, sizeof(filsys), 1, fd); 2598 | break; 2599 | } 2600 | } 2601 | if (i == DIRECTORY_NUM) 2602 | { 2603 | printf("No value iterms!\n"); 2604 | return false; 2605 | } 2606 | fseek(fd, DATA_START + dir_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET); 2607 | fwrite(&cur_dir, sizeof(directory), 1, fd); 2608 | dir_inode.di_number++; 2609 | fseek(fd, INODE_START + tmp_file_inode->i_ino*INODE_SIZE, SEEK_SET); 2610 | fwrite(tmp_file_inode, sizeof(inode), 1, fd); 2611 | return true; 2612 | } 2613 | 2614 | int main() 2615 | { 2616 | memset(ab_dir, 0, sizeof(ab_dir)); 2617 | dir_pointer = 0; 2618 | //Check file system has been formatted or not. 2619 | FILE* fs_test = fopen("fs.han", "r"); 2620 | if (fs_test == NULL) 2621 | { 2622 | printf("File system not found... Format file system first...\n\n"); 2623 | Format(); 2624 | } 2625 | Sys_start(); 2626 | ab_dir[dir_pointer][0] = 'r';ab_dir[dir_pointer][1] = 'o';ab_dir[dir_pointer][2] = 'o';ab_dir[dir_pointer][3] = 't';ab_dir[dir_pointer][4] = '\0'; 2627 | dir_pointer++; 2628 | //First log in 2629 | char tmp_userName[USER_NAME_LENGTH]; 2630 | char tmp_userPassword[USER_PASSWORD_LENGTH * 5]; 2631 | 2632 | do { 2633 | memset(tmp_userName, 0, USER_NAME_LENGTH); 2634 | memset(tmp_userPassword, 0, USER_PASSWORD_LENGTH * 5); 2635 | 2636 | printf("User log in\n\n"); 2637 | printf("User name:\t"); 2638 | scanf("%s", tmp_userName); 2639 | printf("Password:\t"); 2640 | char c; 2641 | scanf("%c", &c); 2642 | int i = 0; 2643 | while (1) { 2644 | char ch; 2645 | ch = getch(); 2646 | if (ch == '\b') { 2647 | if (i != 0) { 2648 | printf("\b \b"); 2649 | i--; 2650 | } 2651 | else { 2652 | tmp_userPassword[i] = '\0'; 2653 | } 2654 | } 2655 | else if (ch == '\r') { 2656 | tmp_userPassword[i] = '\0'; 2657 | printf("\n\n"); 2658 | break; 2659 | } 2660 | else { 2661 | putchar('*'); 2662 | tmp_userPassword[i++] = ch; 2663 | } 2664 | } 2665 | 2666 | //scanf("%s", tmp_userPassword); 2667 | } while (Login(tmp_userName, tmp_userPassword) != true); 2668 | 2669 | //User's mode of file system 2670 | inode* currentInode = new inode; 2671 | 2672 | CommParser(currentInode); 2673 | 2674 | return 0; 2675 | } 2676 | //system start 2677 | void Sys_start() { 2678 | //Install file system 2679 | Mount(); 2680 | 2681 | printf("**************************************************************\n"); 2682 | printf("* *\n"); 2683 | printf("* ** ** *\n"); 2684 | printf("* ** ** *\n"); 2685 | printf("* ** ** *\n"); 2686 | printf("* ** ** *\n"); 2687 | printf("* ** ** *** * ** ** ** *\n"); 2688 | printf("* ** ** * * * ** ** *\n"); 2689 | printf("* ** ** * * * ** ** ** *\n"); 2690 | printf("* ** ** * * * ** ** ** *\n"); 2691 | printf("* ** ** * * * ** ** *\n"); 2692 | printf("* ** ** * * * ** ** ** *\n"); 2693 | printf("* ** ** * * * ** ** ** *\n"); 2694 | printf("* ** ** * * * ** ** ** *\n"); 2695 | printf("* *************** * *** ** ** ** *\n"); 2696 | printf("* *\n"); 2697 | printf("**************************************************************\n"); 2698 | } 2699 | /* 2700 | * Recieve commands from console and call functions accordingly. 2701 | * 2702 | * para cuurentInode: a global inode used for 'open' and 'write' 2703 | */ 2704 | void CommParser(inode*& currentInode) 2705 | { 2706 | char para1[11]; 2707 | char para2[1024]; 2708 | bool flag = false; 2709 | //Recieve commands 2710 | while (true) 2711 | { 2712 | unsigned int f1[BLOCK_SIZE / sizeof(unsigned int)] = { 0 }; 2713 | fseek(fd, DATA_START + 8 * BLOCK_SIZE, SEEK_SET); 2714 | fread(f1, sizeof(f1), 1, fd); 2715 | memset(para1, 0, 11); 2716 | memset(para2, 0, 1024); 2717 | 2718 | printf("%s>", userName); 2719 | scanf("%s", para1); 2720 | para1[10] = 0; //security protection 2721 | 2722 | //Choose function 2723 | //Print current directory 2724 | if (strcmp("ls", para1) == 0) 2725 | { 2726 | flag = false; 2727 | List(); 2728 | } 2729 | else if (strcmp("cp", para1) == 0) { 2730 | flag = false; 2731 | scanf("%s", para2); 2732 | para2[1023] = 0; //security protection 2733 | Copy(para2, currentInode); 2734 | } 2735 | else if (strcmp("mv", para1) == 0) { 2736 | flag = false; 2737 | scanf("%s", para2); 2738 | para2[1023] = 0; //security protection 2739 | Rename(para2); 2740 | } 2741 | else if (strcmp("pwd", para1) == 0) { 2742 | flag = false; 2743 | Ab_dir(); 2744 | } 2745 | else if (strcmp("passwd", para1) == 0) { 2746 | flag = false; 2747 | Passwd(); 2748 | } 2749 | else if (strcmp("chmod", para1) == 0) { 2750 | flag = false; 2751 | scanf("%s", para2); 2752 | para2[1023] = 0; //security protection 2753 | 2754 | Chmod(para2); 2755 | } 2756 | else if (strcmp("chown", para1) == 0) { 2757 | flag = false; 2758 | scanf("%s", para2); 2759 | para2[1023] = 0; //security protection 2760 | 2761 | Chown(para2); 2762 | } 2763 | else if (strcmp("chgrp", para1) == 0) { 2764 | flag = false; 2765 | scanf("%s", para2); 2766 | para2[1023] = 0; //security protection 2767 | 2768 | Chgrp(para2); 2769 | } 2770 | else if (strcmp("info", para1) == 0) { 2771 | printf("System Info:\nTotal Block:%d\nFree Block:%d\nTotal Inode:%d\nFree Inode:%d\n\n", superBlock.s_num_block, superBlock.s_num_fblock, superBlock.s_num_inode, superBlock.s_num_finode); 2772 | for (int i = 0; i < 50; i++) 2773 | { 2774 | if (i>superBlock.special_free)printf("-1\t"); 2775 | else printf("%d\t", superBlock.special_stack[i]); 2776 | if (i % 10 == 9)printf("\n"); 2777 | } 2778 | printf("\n\n"); 2779 | } 2780 | //Create file 2781 | else if (strcmp("create", para1) == 0) 2782 | { 2783 | flag = false; 2784 | scanf("%s", para2); 2785 | para2[1023] = 0; //security protection 2786 | 2787 | CreateFile(para2); 2788 | } 2789 | //Delete file 2790 | else if (strcmp("rm", para1) == 0) 2791 | { 2792 | flag = false; 2793 | scanf("%s", para2); 2794 | para2[1023] = 0; //security protection 2795 | 2796 | DeleteFile(para2); 2797 | } 2798 | //Open file 2799 | else if (strcmp("open", para1) == 0){ 2800 | flag = true; 2801 | scanf("%s", para2); 2802 | para2[1023] = 0; //security protection 2803 | 2804 | currentInode = OpenFile(para2); 2805 | } 2806 | //Write file 2807 | else if (strcmp("write", para1) == 0 && flag){ 2808 | scanf("%s", para2); 2809 | para2[1023] = 0; //security protection 2810 | 2811 | Write(*currentInode, para2); 2812 | } 2813 | //Read file 2814 | else if (strcmp("cat", para1) == 0 && flag) { 2815 | PrintFile(*currentInode); 2816 | } 2817 | //Open a directory 2818 | else if (strcmp("cd", para1) == 0){ 2819 | flag = false; 2820 | scanf("%s", para2); 2821 | para2[1023] = 0; //security protection 2822 | 2823 | OpenDir(para2); 2824 | } 2825 | //Create dirctory 2826 | else if (strcmp("mkdir", para1) == 0){ 2827 | flag = false; 2828 | scanf("%s", para2); 2829 | para2[1023] = 0; //security protection 2830 | 2831 | MakeDir(para2); 2832 | } 2833 | //Delete directory 2834 | else if (strcmp("rmdir", para1) == 0){ 2835 | flag = false; 2836 | scanf("%s", para2); 2837 | para2[1023] = 0; //security protection 2838 | 2839 | RemoveDir(para2); 2840 | } 2841 | //Log out 2842 | else if (strcmp("logout", para1) == 0){ 2843 | flag = false; 2844 | Logout(); 2845 | char tmp_userName[USER_NAME_LENGTH], tmp_userPassword[USER_PASSWORD_LENGTH * 5]; 2846 | do { 2847 | memset(tmp_userName, 0, USER_NAME_LENGTH); 2848 | memset(tmp_userPassword, 0, USER_PASSWORD_LENGTH * 5); 2849 | 2850 | printf("User log in\n\n"); 2851 | printf("User name:\t"); 2852 | scanf("%s", tmp_userName); 2853 | printf("Password:\t"); 2854 | char c; 2855 | scanf("%c", &c); 2856 | int i = 0; 2857 | while (1) { 2858 | char ch; 2859 | ch = getch(); 2860 | if (ch == '\b') { 2861 | if (i != 0) { 2862 | printf("\b \b"); 2863 | i--; 2864 | } 2865 | else { 2866 | tmp_userPassword[i] = '\0'; 2867 | } 2868 | } 2869 | else if (ch == '\r') { 2870 | tmp_userPassword[i] = '\0'; 2871 | printf("\n\n"); 2872 | break; 2873 | } 2874 | else { 2875 | putchar('*'); 2876 | tmp_userPassword[i++] = ch; 2877 | } 2878 | } 2879 | 2880 | //scanf("%s", tmp_userPassword); 2881 | } while (Login(tmp_userName, tmp_userPassword) != true); 2882 | 2883 | //User's mode of file system 2884 | inode* currentInode = new inode; 2885 | } 2886 | else if (strcmp("ln", para1) == 0) 2887 | { 2888 | flag = false; 2889 | scanf("%s", para2); 2890 | para2[1023] = 0; //security protection 2891 | 2892 | ln(para2); 2893 | } 2894 | //Log in 2895 | else if (strcmp("su", para1) == 0){ 2896 | Logout(); 2897 | flag = false; 2898 | char para3[USER_PASSWORD_LENGTH * 5]; 2899 | memset(para3, 0, USER_PASSWORD_LENGTH + 1); 2900 | 2901 | scanf("%s", para2); 2902 | para2[1023] = 0; //security protection 2903 | //scanf("%s", para3); 2904 | printf("password: "); 2905 | char c; 2906 | scanf("%c", &c); 2907 | int i = 0; 2908 | while (1) { 2909 | char ch; 2910 | ch = getch(); 2911 | if (ch == '\b') { 2912 | if (i != 0) { 2913 | printf("\b \b"); 2914 | i--; 2915 | } 2916 | } 2917 | else if (ch == '\r') { 2918 | para3[i] = '\0'; 2919 | printf("\n\n"); 2920 | break; 2921 | } 2922 | else { 2923 | putchar('*'); 2924 | para3[i++] = ch; 2925 | } 2926 | } 2927 | para3[USER_PASSWORD_LENGTH] = 0; //security protection 2928 | 2929 | Login(para2, para3); 2930 | } 2931 | else if (strcmp("Muser", para1) == 0) { 2932 | flag = false; 2933 | User_management(); 2934 | } 2935 | //Exit 2936 | else if (strcmp("exit", para1) == 0){ 2937 | flag = false; 2938 | break; 2939 | } 2940 | //Error or help 2941 | else{ 2942 | flag = false; 2943 | Help(); 2944 | } 2945 | } 2946 | }; 2947 | 2948 | /* 2949 | * Print all commands help information when 'help' is 2950 | * called or input error occurs. 2951 | */ 2952 | void Help(){ 2953 | printf("System command:\n"); 2954 | printf("\t01.Exit system....................................(exit)\n"); 2955 | printf("\t02.Show help information..........................(help)\n"); 2956 | printf("\t03.Show current directory..........................(pwd)\n"); 2957 | printf("\t04.File list of current directory...................(ls)\n"); 2958 | printf("\t05.Enter the specified directory..........(cd + dirname)\n"); 2959 | printf("\t06.Return last directory.........................(cd ..)\n"); 2960 | printf("\t07.Create a new directory..............(mkdir + dirname)\n"); 2961 | printf("\t08.Delete the directory................(rmdir + dirname)\n"); 2962 | printf("\t09.Create a new file....................(create + fname)\n"); 2963 | printf("\t10.Open a file............................(open + fname)\n"); 2964 | printf("\t11.Read the file...................................(cat)\n"); 2965 | printf("\t12.Write the file....................(write + )\n"); 2966 | printf("\t13.Copy a file..............................(cp + fname)\n"); 2967 | printf("\t14.Delete a file............................(rm + fname)\n"); 2968 | printf("\t15.System information view........................(info)\n"); 2969 | printf("\t16.Close the current user.......................(logout)\n"); 2970 | printf("\t17.Change the current user...............(su + username)\n"); 2971 | printf("\t18.Change the mode of a file.............(chmod + fname)\n"); 2972 | printf("\t19.Change the user of a file.............(chown + fname)\n"); 2973 | printf("\t20.Change the group of a file............(chgrp + fname)\n"); 2974 | printf("\t21.Rename a file............................(mv + fname)\n"); 2975 | printf("\t22.link.....................................(ln + fname)\n"); 2976 | printf("\t23.Change password..............................(passwd) \n"); 2977 | printf("\t24.User Management Menu..........................(Muser)\n"); 2978 | }; 2979 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 浙江工业大学操作系统大型实验————模拟Unix文件系统 2 |

Zhejiang University of Technology, Simple Unix File System

3 |

-----------------------------------------------------------

4 |

实现功能

5 |

01.Exit system....................................(exit)

6 |

02.Show help information..........................(help)

7 |

03.Show current directory..........................(pwd)

8 |

04.File list of current directory...................(ls)

9 |

05.Enter the specified directory..........(cd + dirname)

10 |

06.Return last directory.........................(cd ..)

11 |

07.Create a new directory..............(mkdir + dirname)

12 |

08.Delete the directory................(rmdir + dirname)

13 |

09.Create a new file....................(create + fname)

14 |

10.Open a file............................(open + fname)

15 |

11.Read the file...................................(cat)

16 |

12.Write the file.....................(write + contents)

17 |

13.Copy a file..............................(cp + fname)

18 |

14.Delete a file............................(rm + fname)

19 |

15.System information view........................(info)

20 |

16.Close the current user.......................(logout)

21 |

17.Change the current user...............(su + username)

22 |

18.Change the mode of a file.............(chmod + fname)

23 |

19.Change the user of a file.............(chown + fname)

24 |

20.Change the group of a file............(chgrp + fname)

25 |

21.Rename a file............................(mv + fname)

26 |

22.link.....................................(ln + fname)

27 |

23.Change password..............................(passwd)

28 |

24.User Management Menu..........................(Muser)

29 |

注:该代码中cat指令与write指令与要求中有所不同,需要先对文件执行open指令后才可以读写。

30 |

空闲盘块分配采用成组链接,空闲inode节点采用位示图法。

31 | --------------------------------------------------------------------------------