forked from elliotxx/os_filesystem
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathMFS.cpp
3057 lines (2684 loc) · 76.4 KB
/
MFS.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include "MFS.h"
using namespace std;
// ---------------- 文件系统、内存分配、初始化 ----------------------
void InitSystem()
{
//打开虚拟磁盘文件
if ((fr = fopen(FILESYSNAME, "rb")) == NULL) { //只读打开虚拟磁盘文件(二进制文件)
//虚拟磁盘文件不存在,创建一个
fw = fopen(FILESYSNAME, "wb"); //只写打开虚拟磁盘文件(二进制文件)
if (fw == NULL) {
cout << "Virtual disk file open failure." << endl;
return; //打开文件失败
}
fr = fopen(FILESYSNAME, "rb"); //现在可以打开了
//初始化变量
nextUID = 0;
nextGID = 0;
isLogin = false;
strcpy(Cur_User_Name, "root");
strcpy(Cur_Group_Name, "root");
//获取主机名
memset(Cur_Host_Name, 0, sizeof(Cur_Host_Name));
DWORD k = 100;
GetComputerName(Cur_Host_Name, &k);
//根目录inode地址 ,当前目录地址和名字
Root_Dir_Addr = Inode_StartAddr; //第一个inode地址
Cur_Dir_Addr = Root_Dir_Addr;
strcpy(Cur_Dir_Name, "/");
cout << "-----------------------------------------" << endl;
cout << "The file system is being formatted......" << endl;
if (!Format()) {
cout << "Formatting failure!" << endl;
getchar();
return;
}
cout << "Format complete." << endl;
// 初始化用户,创建目录及配置文件
InitUser();
if (!Install()) {
cout << "Failed to install file system." << endl;
return;
}
}
else { //虚拟磁盘文件已存在
fread(buffer, Sum_Size, 1, fr);
//取出文件内容暂存到内容中,以写方式打开文件之后再写回文件(写方式打开回清空文件)
fw = fopen(FILESYSNAME, "wb"); //只写打开虚拟磁盘文件(二进制文件)
if (fw == NULL) {
cout << "Virtual disk file failed to open." << endl;
return; //打开文件失败
}
fwrite(buffer, Sum_Size, 1, fw);
/* 提示是否要格式化
* 因为不是第一次登陆,先略去这一步
* 下面需要手动设置变量
Ready();
system("pause");
system("cls");
*/
//初始化变量
nextUID = 0;
nextGID = 0;
isLogin = false;
strcpy(Cur_User_Name, "root");
strcpy(Cur_Group_Name, "root");
//获取主机名
memset(Cur_Host_Name, 0, sizeof(Cur_Host_Name));
DWORD k = 100;
GetComputerName(Cur_Host_Name, &k);
//根目录inode地址 ,当前目录地址和名字
Root_Dir_Addr = Inode_StartAddr; //第一个inode地址
Cur_Dir_Addr = Root_Dir_Addr;
strcpy(Cur_Dir_Name, "/");
if (!Install()) {
cout << "Failed to install file system." << endl;
return;
}
}
}
//函数实现
void Ready() //登录系统前的准备工作,变量初始化+注册+安装
{
//初始化变量
nextUID = 0;
nextGID = 0;
isLogin = false;
strcpy(Cur_User_Name, "root");
strcpy(Cur_Group_Name, "root");
//获取主机名
memset(Cur_Host_Name, 0, sizeof(Cur_Host_Name));
DWORD k = 100;
GetComputerName(Cur_Host_Name, &k);
//根目录inode地址 ,当前目录地址和名字
Root_Dir_Addr = Inode_StartAddr; //第一个inode地址
Cur_Dir_Addr = Root_Dir_Addr;
strcpy(Cur_Dir_Name, "/");
char c;
cout << "Do you want to format? [y/n] ";
while (c = getch()) {
fflush(stdin);
if (c == 'y') {
printf("\n");
cout << endl << "The file system is being formatted......" << endl;
if (!Format()) {
cout << "Format failur." << endl;
return;
}
cout << "Format complete." << endl;
break;
}
else if (c == 'n') {
printf("\n");
break;
}
}
// 初始化用户,创建目录及配置文件
InitUser();
//printf("载入文件系统……\n");
if (!Install()) {
cout << "Failed to install file system." << endl;
return;
}
//printf("载入完成\n");
}
void InitUser()
{
// 输入root密码
cout << "Please type the root password!" << endl;
bool ok = false;
char password1[100] = { 0 }, password2[100] = { 0 };
do {
cout << "First input ";
inputPassword(password1);
cout << "Second input ";
inputPassword(password2);
ok = (strcmp(password1, "") != 0 && strcmp(password1, password2) == 0);
if (!ok)
cout << "The password can not be empty, and the two entries must be equal" << endl;
else
break;
} while (!ok);
//--------------- 创建目录及配置文件 ----------------
//创建目录及配置文件
Mkdir(Root_Dir_Addr, "home"); //用户目录
Cd(Root_Dir_Addr, "home");
Mkdir(Cur_Dir_Addr, "root");
Cd(Cur_Dir_Addr, "..");
Mkdir(Cur_Dir_Addr, "etc"); //配置文件目录
Cd(Cur_Dir_Addr, "etc");
char buf[100] = { 0 };
sprintf(buf, "root:x:%d:%d\n", nextUID++, nextGID++); //增加条目,用户名:加密密码:用户ID:用户组ID
Create(Cur_Dir_Addr, "passwd", buf); //创建用户信息文件
char s_passwd[100] = { 0 };
strcpy(s_passwd, "root:");
strcat(s_passwd, password1);
strcat(s_passwd, "\n");
sprintf(buf, s_passwd); //增加条目,用户名:密码
Create(Cur_Dir_Addr, "shadow", buf); //创建用户密码文件
Chmod(Cur_Dir_Addr, "shadow", 0660); //修改权限,禁止其它用户读取该文件
sprintf(buf, "root::0:root\n"); //增加管理员用户组,用户组名:口令(一般为空,这里没有使用):组标识号:组内用户列表(用,分隔)
sprintf(buf + strlen(buf), "user::1:\n"); //增加普通用户组,组内用户列表为空
Create(Cur_Dir_Addr, "group", buf); //创建用户组信息文件
Cd(Cur_Dir_Addr, ".."); //回到根目录
}
bool Format() //格式化一个虚拟磁盘文件
{
int i, j;
//初始化超级块
superblock->s_INODE_NUM = INODE_NUM;
superblock->s_BLOCK_NUM = BLOCK_NUM;
superblock->s_SUPERBLOCK_SIZE = sizeof(SuperBlock);
superblock->s_INODE_SIZE = INODE_SIZE;
superblock->s_BLOCK_SIZE = BLOCK_SIZE;
superblock->s_free_INODE_NUM = INODE_NUM;
superblock->s_free_BLOCK_NUM = BLOCK_NUM;
superblock->s_blocks_per_group = BLOCKS_PER_GROUP;
superblock->s_free_addr = Block_StartAddr; //空闲块堆栈指针为第一块block
superblock->s_Superblock_StartAddr = Superblock_StartAddr;
superblock->s_BlockBitmap_StartAddr = BlockBitmap_StartAddr;
superblock->s_InodeBitmap_StartAddr = InodeBitmap_StartAddr;
superblock->s_Block_StartAddr = Block_StartAddr;
superblock->s_Inode_StartAddr = Inode_StartAddr;
//空闲块堆栈在后面赋值
//初始化inode位图
memset(inode_bitmap, 0, sizeof(inode_bitmap));
fseek(fw, InodeBitmap_StartAddr, SEEK_SET);
fwrite(inode_bitmap, sizeof(inode_bitmap), 1, fw);
//初始化block位图
memset(block_bitmap, 0, sizeof(block_bitmap));
fseek(fw, BlockBitmap_StartAddr, SEEK_SET);
fwrite(block_bitmap, sizeof(block_bitmap), 1, fw);
//初始化磁盘块区,根据成组链接法组织
for (i = BLOCK_NUM / BLOCKS_PER_GROUP - 1; i >= 0; i--) { //一共INODE_NUM/BLOCKS_PER_GROUP组,一组FREESTACKNUM(128)个磁盘块 ,第一个磁盘块作为索引
if (i == BLOCK_NUM / BLOCKS_PER_GROUP - 1)
superblock->s_free[0] = -1; //没有下一个空闲块了
else
superblock->s_free[0] = Block_StartAddr + (i + 1)*BLOCKS_PER_GROUP*BLOCK_SIZE; //指向下一个空闲块
for (j = 1; j<BLOCKS_PER_GROUP; j++) {
superblock->s_free[j] = Block_StartAddr + (i*BLOCKS_PER_GROUP + j)*BLOCK_SIZE;
}
fseek(fw, Block_StartAddr + i*BLOCKS_PER_GROUP*BLOCK_SIZE, SEEK_SET);
fwrite(superblock->s_free, sizeof(superblock->s_free), 1, fw); //填满这个磁盘块,512字节
}
//超级块写入到虚拟磁盘文件
fseek(fw, Superblock_StartAddr, SEEK_SET);
fwrite(superblock, sizeof(SuperBlock), 1, fw);
fflush(fw);
//读取inode位图
fseek(fr, InodeBitmap_StartAddr, SEEK_SET);
fread(inode_bitmap, sizeof(inode_bitmap), 1, fr);
//读取block位图
fseek(fr, BlockBitmap_StartAddr, SEEK_SET);
fread(block_bitmap, sizeof(block_bitmap), 1, fr);
fflush(fr);
//创建根目录 "/"
Inode cur;
//申请inode
int inoAddr = InodeAlloc();
//给这个inode申请磁盘块
int blockAddr = BockAlloc();
//在这个磁盘块里加入一个条目 "."
DirItem dirlist[16] = { 0 };
strcpy(dirlist[0].itemName, ".");
dirlist[0].inodeAddr = inoAddr;
//写回磁盘块
fseek(fw, blockAddr, SEEK_SET);
fwrite(dirlist, sizeof(dirlist), 1, fw);
//给inode赋值
cur.i_ino = 0;
cur.i_atime = time(NULL);
cur.i_ctime = time(NULL);
cur.i_mtime = time(NULL);
strcpy(cur.i_uname, Cur_User_Name);
strcpy(cur.i_gname, Cur_Group_Name);
cur.i_cnt = 1; //一个项,当前目录,"."
cur.i_dirBlock[0] = blockAddr;
for (i = 1; i<10; i++) {
cur.i_dirBlock[i] = -1;
}
cur.i_size = superblock->s_BLOCK_SIZE;
cur.i_indirBlock_1 = -1; //没使用一级间接块
cur.i_mode = MODE_DIR | DIR_DEF_PERMISSION;
//写回inode
fseek(fw, inoAddr, SEEK_SET);
fwrite(&cur, sizeof(Inode), 1, fw);
fflush(fw);
return true;
}
bool Install() //安装文件系统,将虚拟磁盘文件中的关键信息如超级块读入到内存
{
//读写虚拟磁盘文件,读取超级块,读取inode位图,block位图,读取主目录,读取etc目录,读取管理员admin目录,读取用户xiao目录,读取用户passwd文件。
//读取超级块
fseek(fr, Superblock_StartAddr, SEEK_SET);
fread(superblock, sizeof(SuperBlock), 1, fr);
//读取inode位图
fseek(fr, InodeBitmap_StartAddr, SEEK_SET);
fread(inode_bitmap, sizeof(inode_bitmap), 1, fr);
//读取block位图
fseek(fr, BlockBitmap_StartAddr, SEEK_SET);
fread(block_bitmap, sizeof(block_bitmap), 1, fr);
return true;
}
int BockAlloc() //磁盘块分配函数
{
//使用超级块中的空闲块堆栈
//计算当前栈顶
int top; //栈顶指针
if (superblock->s_free_BLOCK_NUM == 0) { //剩余空闲块数为0
cout << "No free blocks can be allocated." << endl;
return -1; //没有可分配的空闲块,返回-1
}
else { //还有剩余块
top = (superblock->s_free_BLOCK_NUM - 1) % superblock->s_blocks_per_group;
}
//将栈顶取出
//如果已是栈底,将当前块号地址返回,即为栈底块号,并将栈底指向的新空闲块堆栈覆盖原来的栈
int retAddr;
if (top == 0) {
retAddr = superblock->s_free_addr;
superblock->s_free_addr = superblock->s_free[0]; //取出下一个存有空闲块堆栈的空闲块的位置,更新空闲块堆栈指针
//取出对应空闲块内容,覆盖原来的空闲块堆栈
//取出下一个空闲块堆栈,覆盖原来的
fseek(fr, superblock->s_free_addr, SEEK_SET);
fread(superblock->s_free, sizeof(superblock->s_free), 1, fr);
fflush(fr);
superblock->s_free_BLOCK_NUM--;
}
else { //如果不为栈底,则将栈顶指向的地址返回,栈顶指针-1.
retAddr = superblock->s_free[top]; //保存返回地址
superblock->s_free[top] = -1; //清栈顶
top--; //栈顶指针-1
superblock->s_free_BLOCK_NUM--; //空闲块数-1
}
//更新超级块
fseek(fw, Superblock_StartAddr, SEEK_SET);
fwrite(superblock, sizeof(SuperBlock), 1, fw);
fflush(fw);
//更新block位图
block_bitmap[(retAddr - Block_StartAddr) / BLOCK_SIZE] = 1;
fseek(fw, (retAddr - Block_StartAddr) / BLOCK_SIZE + BlockBitmap_StartAddr, SEEK_SET); //(retAddr-Block_StartAddr)/BLOCK_SIZE为第几个空闲块
fwrite(&block_bitmap[(retAddr - Block_StartAddr) / BLOCK_SIZE], sizeof(bool), 1, fw);
fflush(fw);
return retAddr;
}
bool BlockFree(int addr) //磁盘块释放函数
{
//判断
//该地址不是磁盘块的起始地址
if ((addr - Block_StartAddr) % superblock->s_BLOCK_SIZE != 0) {
cout << "Address error, this location is not the starting position of block." << endl;
return false;
}
unsigned int bno = (addr - Block_StartAddr) / superblock->s_BLOCK_SIZE; //inode节点号
//该地址还未使用,不能释放空间
if (block_bitmap[bno] == 0) {
cout << "The block is not used and can not be released." << endl;
return false;
}
//可以释放
//计算当前栈顶
int top; //栈顶指针
if (superblock->s_free_BLOCK_NUM == superblock->s_BLOCK_NUM) { //没有非空闲的磁盘块
cout << "There is no free disk block that can not be released." << endl;
return false; //没有可分配的空闲块,返回-1
}
else { //非满
top = (superblock->s_free_BLOCK_NUM - 1) % superblock->s_blocks_per_group;
//清空block内容
char tmp[BLOCK_SIZE] = { 0 };
fseek(fw, addr, SEEK_SET);
fwrite(tmp, sizeof(tmp), 1, fw);
if (top == superblock->s_blocks_per_group - 1) { //该栈已满
//该空闲块作为新的空闲块堆栈
superblock->s_free[0] = superblock->s_free_addr; //新的空闲块堆栈第一个地址指向旧的空闲块堆栈指针
int i;
for (i = 1; i<superblock->s_blocks_per_group; i++) {
superblock->s_free[i] = -1; //清空栈元素的其它地址
}
fseek(fw, addr, SEEK_SET);
fwrite(superblock->s_free, sizeof(superblock->s_free), 1, fw); //填满这个磁盘块,512字节
}
else { //栈还未满
top++; //栈顶指针+1
superblock->s_free[top] = addr; //栈顶放上这个要释放的地址,作为新的空闲块
}
}
//更新超级块
superblock->s_free_BLOCK_NUM++; //空闲块数+1
fseek(fw, Superblock_StartAddr, SEEK_SET);
fwrite(superblock, sizeof(SuperBlock), 1, fw);
//更新block位图
block_bitmap[bno] = 0;
fseek(fw, bno + BlockBitmap_StartAddr, SEEK_SET); //(addr-Block_StartAddr)/BLOCK_SIZE为第几个空闲块
fwrite(&block_bitmap[bno], sizeof(bool), 1, fw);
fflush(fw);
return true;
}
int InodeAlloc() //分配i节点区函数,返回inode地址
{
//在inode位图中顺序查找空闲的inode,找到则返回inode地址。函数结束。
if (superblock->s_free_INODE_NUM == 0) {
cout << "No free inode can be allocated." << endl;
return -1;
}
else {
//顺序查找空闲的inode
int i;
for (i = 0; i<superblock->s_INODE_NUM; i++) {
if (inode_bitmap[i] == 0) //找到空闲inode
break;
}
//更新超级块
superblock->s_free_INODE_NUM--; //空闲inode数-1
fseek(fw, Superblock_StartAddr, SEEK_SET);
fwrite(superblock, sizeof(SuperBlock), 1, fw);
//更新inode位图
inode_bitmap[i] = 1;
fseek(fw, InodeBitmap_StartAddr + i, SEEK_SET);
fwrite(&inode_bitmap[i], sizeof(bool), 1, fw);
fflush(fw);
return Inode_StartAddr + i*superblock->s_INODE_SIZE;
}
}
bool InodeFree(int addr) //释放i结点区函数
{
//判断
if ((addr - Inode_StartAddr) % superblock->s_INODE_SIZE != 0) {
cout << "Address error, this location is not the starting position of inode." << endl;
return false;
}
unsigned short ino = (addr - Inode_StartAddr) / superblock->s_INODE_SIZE; //inode节点号
if (inode_bitmap[ino] == 0) {
cout << "The inode is not used and can not be released." << endl;
return false;
}
//清空inode内容
Inode tmp = { 0 };
fseek(fw, addr, SEEK_SET);
fwrite(&tmp, sizeof(tmp), 1, fw);
//更新超级块
superblock->s_free_INODE_NUM++;
//空闲inode数+1
fseek(fw, Superblock_StartAddr, SEEK_SET);
fwrite(superblock, sizeof(SuperBlock), 1, fw);
//更新inode位图
inode_bitmap[ino] = 0;
fseek(fw, InodeBitmap_StartAddr + ino, SEEK_SET);
fwrite(&inode_bitmap[ino], sizeof(bool), 1, fw);
fflush(fw);
return true;
}
// -------------------- 命令 -----------------------
bool Login(char username[]) //登陆界面
{
char password[100] = { 0 };
if (strlen(username) >= MAX_NAME_SIZE) {
cout << "The username is too long." << endl;
return false;
}
if (isLogin == true) {
cout << "You have already logged in." << endl;
return false;
}
// 用户名
if (strcmp(username, "") == 0) {
InputUsername(username);
// 判空
if (strcmp(username, "") == 0) {
cout << "Username can not be empty." << endl;
return false;
}
}
//输入用户密码
inputPassword(password);
// 判空
if (strcmp(password, "") == 0) {
cout << "Password can not be empty." << endl;
return false;
}
if (Check(username, password)) { //核对用户名和密码
isLogin = true;
return true;
}
else {
isLogin = false;
return false;
}
}
void Logout() //用户注销
{
if (isLogin == false) {
cout << "You have not logged in yet!" << endl;
return;
}
//回到根目录
GotoRoot();
isLogin = false;
}
bool Useradd(char username[]) //用户注册
{
if (strcmp(Cur_User_Name, "root") != 0) {
cout << "Permission denied." << endl;
return false;
}
int passwd_Inode_Addr = -1; //用户文件inode地址
int shadow_Inode_Addr = -1; //用户密码文件inode地址
int group_Inode_Addr = -1; //用户组文件inode地址
Inode passwd_Inode = { 0 }; //用户文件的inode
Inode shadow_Inode = { 0 }; //用户密码文件的inode
Inode group_Inode = { 0 }; //用户组文件inode
//原来的目录
char bak_Cur_User_Name[110];
char bak_Cur_User_Name_2[110];
char bak_Cur_User_Dir_Name[310];
int bak_Cur_Dir_Addr;
char bak_Cur_Dir_Name[310];
char bak_Cur_Group_Name[310];
Inode cur_dir_inode = { 0 }; //当前目录的inode
size_t i, j;
DirItem dirlist[16] = { 0 }; //临时目录
//保存现场,回到根目录
strcpy(bak_Cur_User_Name, Cur_User_Name);
strcpy(bak_Cur_User_Dir_Name, Cur_User_Dir_Name);
bak_Cur_Dir_Addr = Cur_Dir_Addr;
strcpy(bak_Cur_Dir_Name, Cur_Dir_Name);
//创建用户目录
GotoRoot();
Cd(Cur_Dir_Addr, "home");
//保存现场
strcpy(bak_Cur_User_Name_2, Cur_User_Name);
strcpy(bak_Cur_Group_Name, Cur_Group_Name);
//更改
strcpy(Cur_User_Name, username);
strcpy(Cur_Group_Name, "user");
if (!Mkdir(Cur_Dir_Addr, username)) {
strcpy(Cur_User_Name, bak_Cur_User_Name_2);
strcpy(Cur_Group_Name, bak_Cur_Group_Name);
//恢复现场,回到原来的目录
strcpy(Cur_User_Name, bak_Cur_User_Name);
strcpy(Cur_User_Dir_Name, bak_Cur_User_Dir_Name);
Cur_Dir_Addr = bak_Cur_Dir_Addr;
strcpy(Cur_Dir_Name, bak_Cur_Dir_Name);
cout << "Add user failure." << endl;
return false;
}
//恢复现场
strcpy(Cur_User_Name, bak_Cur_User_Name_2);
strcpy(Cur_Group_Name, bak_Cur_Group_Name);
//回到根目录
GotoRoot();
//进入用户目录
Cd(Cur_Dir_Addr, "etc");
//输入用户密码
char passwd[100] = { 0 };
inputPassword(passwd); //输入密码
//找到passwd和shadow文件inode地址,并取出,准备添加条目
//取出当前目录的inode
fseek(fr, Cur_Dir_Addr, SEEK_SET);
fread(&cur_dir_inode, sizeof(Inode), 1, fr);
//依次取出磁盘块,查找passwd文件的inode地址,和shadow文件的inode地址
for (i = 0; i<10; i++) {
if (cur_dir_inode.i_dirBlock[i] == -1) {
continue;
}
//依次取出磁盘块
fseek(fr, cur_dir_inode.i_dirBlock[i], SEEK_SET);
fread(&dirlist, sizeof(dirlist), 1, fr);
for (j = 0; j<16; j++) { //遍历目录项
if (strcmp(dirlist[j].itemName, "passwd") == 0 || //找到passwd或者shadow条目
strcmp(dirlist[j].itemName, "shadow") == 0 ||
strcmp(dirlist[j].itemName, "group") == 0) {
Inode tmp; //临时inode
//取出inode,判断是否是文件
fseek(fr, dirlist[j].inodeAddr, SEEK_SET);
fread(&tmp, sizeof(Inode), 1, fr);
if (((tmp.i_mode >> 9) & 1) == 0) {
//是文件
//判别是passwd文件还是shadow文件
if (strcmp(dirlist[j].itemName, "passwd") == 0) {
passwd_Inode_Addr = dirlist[j].inodeAddr;
passwd_Inode = tmp;
}
else if (strcmp(dirlist[j].itemName, "shadow") == 0) {
shadow_Inode_Addr = dirlist[j].inodeAddr;
shadow_Inode = tmp;
}
else if (strcmp(dirlist[j].itemName, "group") == 0) {
group_Inode_Addr = dirlist[j].inodeAddr;
group_Inode = tmp;
}
}
}
}
if (passwd_Inode_Addr != -1 && shadow_Inode_Addr != -1) //都找到了
break;
}
//查找passwd文件,看是否存在用户username
char buf[100000]; //最大100K,暂存passwd的文件内容
char buf2[600]; //暂存磁盘块内容
j = 0; //磁盘块指针
//取出passwd文件内容
for (i = 0; i<passwd_Inode.i_size; i++) {
if (i%superblock->s_BLOCK_SIZE == 0) { //超出了
//换新的磁盘块
fseek(fr, passwd_Inode.i_dirBlock[i / superblock->s_BLOCK_SIZE], SEEK_SET);
fread(&buf2, superblock->s_BLOCK_SIZE, 1, fr);
j = 0;
}
buf[i] = buf2[j++];
}
buf[i] = '\0';
if (strstr(buf, username) != NULL) {
//没找到该用户
cout << "The user has already existed." << endl;
//恢复现场,回到原来的目录
strcpy(Cur_User_Name, bak_Cur_User_Name);
strcpy(Cur_User_Dir_Name, bak_Cur_User_Dir_Name);
Cur_Dir_Addr = bak_Cur_Dir_Addr;
strcpy(Cur_Dir_Name, bak_Cur_Dir_Name);
return false;
}
//如果不存在,在passwd中创建新用户条目,修改group文件
sprintf(buf + strlen(buf), "%s:x:%d:%d\n", username, nextUID++, 1); //增加条目,用户名:加密密码:用户ID:用户组ID。用户组为普通用户组,值为1
passwd_Inode.i_size = strlen(buf);
WriteFile(passwd_Inode, passwd_Inode_Addr, buf); //将修改后的passwd写回文件中
//取出shadow文件内容
j = 0;
for (i = 0; i<shadow_Inode.i_size; i++) {
if (i%superblock->s_BLOCK_SIZE == 0) { //超出了这个磁盘块
//换新的磁盘块
fseek(fr, shadow_Inode.i_dirBlock[i / superblock->s_BLOCK_SIZE], SEEK_SET);
fread(&buf2, superblock->s_BLOCK_SIZE, 1, fr);
j = 0;
}
buf[i] = buf2[j++];
}
buf[i] = '\0';
//增加shadow条目
sprintf(buf + strlen(buf), "%s:%s\n", username, passwd); //增加条目,用户名:密码
shadow_Inode.i_size = strlen(buf);
WriteFile(shadow_Inode, shadow_Inode_Addr, buf); //将修改后的内容写回文件中
//取出group文件内容
j = 0;
for (i = 0; i<group_Inode.i_size; i++) {
if (i%superblock->s_BLOCK_SIZE == 0) { //超出了这个磁盘块
//换新的磁盘块
fseek(fr, group_Inode.i_dirBlock[i / superblock->s_BLOCK_SIZE], SEEK_SET);
fread(&buf2, superblock->s_BLOCK_SIZE, 1, fr);
j = 0;
}
buf[i] = buf2[j++];
}
buf[i] = '\0';
//增加group中普通用户列表
if (buf[strlen(buf) - 2] == ':')
sprintf(buf + strlen(buf) - 1, "%s\n", username); //增加组内用户
else
sprintf(buf + strlen(buf) - 1, ",%s\n", username); //增加组内用户
group_Inode.i_size = strlen(buf);
WriteFile(group_Inode, group_Inode_Addr, buf); //将修改后的内容写回文件中
//恢复现场,回到原来的目录
strcpy(Cur_User_Name, bak_Cur_User_Name);
strcpy(Cur_User_Dir_Name, bak_Cur_User_Dir_Name);
Cur_Dir_Addr = bak_Cur_Dir_Addr;
strcpy(Cur_Dir_Name, bak_Cur_Dir_Name);
cout << "Add user success." << endl;
return true;
}
bool Userdel(char username[]) //用户删除
{
if (strcmp(Cur_User_Name, "root") != 0) {
cout << "Permission denied." << endl;
return false;
}
if (strcmp(username, "root") == 0) {
cout << "Unable to delete root user." << endl;
return false;
}
int passwd_Inode_Addr = -1; //用户文件inode地址
int shadow_Inode_Addr = -1; //用户密码文件inode地址
int group_Inode_Addr = -1; //用户组文件inode地址
Inode passwd_Inode = { 0 }; //用户文件的inode
Inode shadow_Inode = { 0 }; //用户密码文件的inode
Inode group_Inode = { 0 }; //用户组文件inode
//原来的目录
char bak_Cur_User_Name[110];
char bak_Cur_User_Dir_Name[310];
int bak_Cur_Dir_Addr;
char bak_Cur_Dir_Name[310];
Inode cur_dir_inode = { 0 }; //当前目录的inode
size_t i, j;
DirItem dirlist[16] = { 0 }; //临时目录
//保存现场,回到根目录
strcpy(bak_Cur_User_Name, Cur_User_Name);
strcpy(bak_Cur_User_Dir_Name, Cur_User_Dir_Name);
bak_Cur_Dir_Addr = Cur_Dir_Addr;
strcpy(bak_Cur_Dir_Name, Cur_Dir_Name);
//回到根目录
GotoRoot();
//进入用户目录
Cd(Cur_Dir_Addr, "etc");
//输入用户密码
//char passwd[100] = {0};
//inputPassword(passwd); //输入密码
//找到passwd和shadow文件inode地址,并取出,准备添加条目
//取出当前目录的inode
fseek(fr, Cur_Dir_Addr, SEEK_SET);
fread(&cur_dir_inode, sizeof(Inode), 1, fr);
//依次取出磁盘块,查找passwd文件的inode地址,和shadow文件的inode地址
for (i = 0; i<10; i++) {
if (cur_dir_inode.i_dirBlock[i] == -1) {
continue;
}
//依次取出磁盘块
fseek(fr, cur_dir_inode.i_dirBlock[i], SEEK_SET);
fread(&dirlist, sizeof(dirlist), 1, fr);
for (j = 0; j<16; j++) { //遍历目录项
if (strcmp(dirlist[j].itemName, "passwd") == 0 || //找到passwd或者shadow条目
strcmp(dirlist[j].itemName, "shadow") == 0 ||
strcmp(dirlist[j].itemName, "group") == 0) {
Inode tmp = { 0 }; //临时inode
//取出inode,判断是否是文件
fseek(fr, dirlist[j].inodeAddr, SEEK_SET);
fread(&tmp, sizeof(Inode), 1, fr);
if (((tmp.i_mode >> 9) & 1) == 0) {
//是文件
//判别是passwd文件还是shadow文件
if (strcmp(dirlist[j].itemName, "passwd") == 0) {
passwd_Inode_Addr = dirlist[j].inodeAddr;
passwd_Inode = tmp;
}
else if (strcmp(dirlist[j].itemName, "shadow") == 0) {
shadow_Inode_Addr = dirlist[j].inodeAddr;
shadow_Inode = tmp;
}
else if (strcmp(dirlist[j].itemName, "group") == 0) {
group_Inode_Addr = dirlist[j].inodeAddr;
group_Inode = tmp;
}
}
}
}
if (passwd_Inode_Addr != -1 && shadow_Inode_Addr != -1) //都找到了
break;
}
//查找passwd文件,看是否存在用户username
char buf[100000]; //最大100K,暂存passwd的文件内容
char buf2[600]; //暂存磁盘块内容
j = 0; //磁盘块指针
//取出passwd文件内容
for (i = 0; i<passwd_Inode.i_size; i++) {
if (i%superblock->s_BLOCK_SIZE == 0) { //超出了
//换新的磁盘块
fseek(fr, passwd_Inode.i_dirBlock[i / superblock->s_BLOCK_SIZE], SEEK_SET);
fread(&buf2, superblock->s_BLOCK_SIZE, 1, fr);
j = 0;
}
buf[i] = buf2[j++];
}
buf[i] = '\0';
if (strstr(buf, username) == NULL) {
//没找到该用户
cout << "User does not exist." << endl;
//恢复现场,回到原来的目录
strcpy(Cur_User_Name, bak_Cur_User_Name);
strcpy(Cur_User_Dir_Name, bak_Cur_User_Dir_Name);
Cur_Dir_Addr = bak_Cur_Dir_Addr;
strcpy(Cur_Dir_Name, bak_Cur_Dir_Name);
return false;
}
//如果存在,在passwd、shadow、group中删除该用户的条目
//删除passwd条目
char *p = strstr(buf, username);
*p = '\0';
while ((*p) != '\n') //空出中间的部分
p++;
p++;
strcat(buf, p);
passwd_Inode.i_size = strlen(buf); //更新文件大小
WriteFile(passwd_Inode, passwd_Inode_Addr, buf); //将修改后的passwd写回文件中
//取出shadow文件内容
j = 0;
for (i = 0; i<shadow_Inode.i_size; i++) {
if (i%superblock->s_BLOCK_SIZE == 0) { //超出了这个磁盘块
//换新的磁盘块
fseek(fr, shadow_Inode.i_dirBlock[i / superblock->s_BLOCK_SIZE], SEEK_SET);
fread(&buf2, superblock->s_BLOCK_SIZE, 1, fr);
j = 0;
}
buf[i] = buf2[j++];
}
buf[i] = '\0';
//删除shadow条目
p = strstr(buf, username);
*p = '\0';
while ((*p) != '\n') //空出中间的部分
p++;
p++;
strcat(buf, p);
shadow_Inode.i_size = strlen(buf); //更新文件大小
WriteFile(shadow_Inode, shadow_Inode_Addr, buf); //将修改后的内容写回文件中
//取出group文件内容
j = 0;
for (i = 0; i<group_Inode.i_size; i++) {
if (i%superblock->s_BLOCK_SIZE == 0) { //超出了这个磁盘块
//换新的磁盘块
fseek(fr, group_Inode.i_dirBlock[i / superblock->s_BLOCK_SIZE], SEEK_SET);
fread(&buf2, superblock->s_BLOCK_SIZE, 1, fr);
j = 0;
}
buf[i] = buf2[j++];
}
buf[i] = '\0';
//增加group中普通用户列表
p = strstr(buf, username);
*p = '\0';
while ((*p) != '\n' && (*p) != ',') //空出中间的部分
p++;
if ((*p) == ',')
p++;
strcat(buf, p);
group_Inode.i_size = strlen(buf); //更新文件大小
WriteFile(group_Inode, group_Inode_Addr, buf); //将修改后的内容写回文件中
////恢复现场,回到原来的目录
//strcpy(Cur_User_Name, bak_Cur_User_Name);
//strcpy(Cur_User_Dir_Name, bak_Cur_User_Dir_Name);
//Cur_Dir_Addr = bak_Cur_Dir_Addr;
//strcpy(Cur_Dir_Name, bak_Cur_Dir_Name);
//删除用户目录
Cur_Dir_Addr = Root_Dir_Addr; //当前用户目录地址设为根目录地址
strcpy(Cur_Dir_Name, "/"); //当前目录设为"/"
Cd(Cur_Dir_Addr, "home");
Rmdir(Cur_Dir_Addr, username);
// 【已改】如果在root用户进入a用户目录,删掉a用户,则卡在a目录下面了
// 【已改】此处应该改为:判断当前用户目录是否为a用户的目录(不能用),是则返回根目录,否则恢复为原来的目录
// User_Dir_to_be_deleted 为应该删除的用户目录
char c, User_Dir_to_be_deleted[110] = { 0 }, cmp_Cur_Dir_Name[311];
strcpy(User_Dir_to_be_deleted, "/home/");
strcat(User_Dir_to_be_deleted, username);
strcat(User_Dir_to_be_deleted, "/");
strcpy(cmp_Cur_Dir_Name, bak_Cur_Dir_Name);
strcat(cmp_Cur_Dir_Name, "/");
for (i = 0, j = 0; j < 3; i++) {
c = cmp_Cur_Dir_Name[i];
if (c != User_Dir_to_be_deleted[i])
break;
else if (c == '/')
j++;
}
if (j != 3) {
//恢复现场,回到原来的目录
strcpy(Cur_User_Name, bak_Cur_User_Name);
strcpy(Cur_User_Dir_Name, bak_Cur_User_Dir_Name);
Cur_Dir_Addr = bak_Cur_Dir_Addr;
strcpy(Cur_Dir_Name, bak_Cur_Dir_Name);
}
else {
//GotoRoot();
//Cd(Root_Dir_Addr, "home");
//Cd(Cur_Dir_Addr, "root");
//strcpy(Cur_User_Name, "root");
//strcpy(Cur_User_Dir_Name, "root");
// 在root用户进入a用户目录,删掉a用户,则回到根目录
strcpy(Cur_User_Name, "root");
strcpy(Cur_User_Dir_Name, "root");
Cur_Dir_Addr = Root_Dir_Addr; //当前用户目录地址设为根目录地址
strcpy(Cur_Dir_Name, "/"); //当前目录设为"/"
// 删除username目录
Cd(Cur_Dir_Addr, "home");
Rmdir(Cur_Dir_Addr, username);
// 回到/home/root
Cd(Cur_Dir_Addr, "..");
}
cout << "User has deleted." << endl;
return true;
}
void Chmod(int parinoAddr, char name[], int pmode) //修改文件或目录权限
{
if (strlen(name) >= MAX_NAME_SIZE) {
cout << "The directory name is too long." << endl;
return;
}
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
cout << "Operation error." << endl;
return;
}
//取出该文件或目录inode