-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfat.c
More file actions
1683 lines (1380 loc) · 54.2 KB
/
fat.c
File metadata and controls
1683 lines (1380 loc) · 54.2 KB
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
/******************************************************************************/
/* */
/* Project : FAT12/16 File System */
/* File : fat.c */
/* Author : Kyoungmoon Sun(msg2me@msn.com) */
/* Company : Dankook Univ. Embedded System Lab. */
/* Notes : FAT File System core */
/* Date : 2008/7/2 */
/* */
/******************************************************************************/
#include "fat.h"
#include "clusterlist.h"
#define MIN( a, b ) ( ( a ) < ( b ) ? ( a ) : ( b ) )
#define MAX( a, b ) ( ( a ) > ( b ) ? ( a ) : ( b ) )
#define NO_MORE_CLUSER() WARNING( "No more clusters are remained\n" );
unsigned char toupper( unsigned char ch );
int isalpha( unsigned char ch );
int isdigit( unsigned char ch );
/* calculate the 'sectors per cluster' by some conditions */
DWORD get_sector_per_clusterN( DWORD diskTable[][2], UINT64 diskSize, UINT32 bytesPerSector )
{
int i = 0;
do
{
if( ( ( UINT64 )( diskTable[i][0] * 512 ) ) >= diskSize )
return diskTable[i][1] / ( bytesPerSector / 512 );
}
while( diskTable[i++][0] < 0xFFFFFFFF );
return 0;
}
DWORD get_sector_per_cluster16( UINT64 diskSize, UINT32 bytesPerSector )
{
DWORD diskTableFAT16[][2] =
{
{ 8400, 0 },
{ 32680, 2 },
{ 262144, 4 },
{ 524288, 8 },
{ 1048576, 16 },
/* The entries after this point are not used unless FAT16 is forced */
{ 2097152, 32 },
{ 4194304, 64 },
{ 0xFFFFFFFF, 0 }
};
return get_sector_per_clusterN( diskTableFAT16, diskSize, bytesPerSector );
}
DWORD get_sector_per_cluster32( UINT64 diskSize, UINT32 bytesPerSector )
{
DWORD diskTableFAT32[][2] =
{
{ 66600, 0 },
{ 532480, 1 },
{ 16777216, 8 },
{ 33554432, 16 },
{ 67108864, 32 },
{ 0xFFFFFFFF, 64 }
};
return get_sector_per_clusterN( diskTableFAT32, diskSize, bytesPerSector );
}
// 클러스터 하나 당 섹터가 몇개인지
DWORD get_sector_per_cluster( BYTE FATType, UINT64 diskSize, UINT32 bytesPerSector )
{
// fat 타입에 따라
switch( FATType )
{
case 0: /* FAT12 */
return 1;
case 1: /* FAT16 */
return get_sector_per_cluster16( diskSize, bytesPerSector );
case 2: /* FAT32 */
return get_sector_per_cluster32( diskSize, bytesPerSector );
}
return 0;
}
// fat크기 구해서 bpb에 setting
/* fills the field FATSize16 and FATSize32 of the FAT_BPB */
void fill_fat_size( FAT_BPB* bpb, BYTE FATType )
{
UINT32 diskSize = ( bpb->totalSectors32 == 0 ? bpb->totalSectors : bpb->totalSectors32 );
UINT32 rootDirSectors = ( ( bpb->rootEntryCount * 32 ) + (bpb->bytesPerSector - 1) ) / bpb->bytesPerSector;
UINT32 tmpVal1 = diskSize - ( bpb->reservedSectorCount + rootDirSectors );
UINT32 tmpVal2 = ( 256 * bpb->sectorsPerCluster ) + bpb->numberOfFATs;
UINT32 FATSize;
if( FATType == FAT32 )
tmpVal2 = tmpVal2 / 2;
FATSize = ( tmpVal1 + ( tmpVal2 - 1 ) ) / tmpVal2;
if( FATType == 32 )
{
bpb->FATSize16 = 0;
bpb->BPB32.FATSize32 = FATSize;
}
else
bpb->FATSize16 = ( WORD )( FATSize & 0xFFFF );
}
// FAT 버전에 따라서 BPB에 디스크의 모든 하드웨어적인 정보 등을 등록
// 파일시스템 버전에 따라서 부트 파라미터 블록의 내용이 달라지기 때문에
// 커널에서 사용자에게 원하는 파일시스템을 입력받고 그에맞는 내용으로 채워서 디스크에 써줌
int fill_bpb( FAT_BPB* bpb, BYTE FATType, SECTOR numberOfSectors, UINT32 bytesPerSector )
{
QWORD diskSize = numberOfSectors * bytesPerSector;
/*typedef struct
{
BYTE driveNumber;
BYTE reserved1;
BYTE bootSignature;
DWORD volumeID;
BYTE volumeLabel[11];
BYTE filesystemType[8];
} FAT_BOOTSECTOR;*/
FAT_BOOTSECTOR* bs; // 드라이브, 볼륨 정보
BYTE filesystemType[][8] = { "FAT12 ", "FAT16 ", "FAT32 " };
UINT32 sectorsPerCluster;
// 2보다 큰건 없음, 에러
if( FATType > 2 )
return FAT_ERROR;
// #define ZeroMemory( a, b ) memset( a, 0, b )
// void* memset(void*ptr, int value, size_t num); >> ptr(포인터)부터 num(바이트)만큼 value로 채움
ZeroMemory( bpb, sizeof( FAT_BPB ) ); // bpb부터 FAT_BPB의 크기만큼 0으로 채움 -> FAT_BPB구조체인 bpb가 0으로 채워짐
// Jump Boot Code = Boot Code로 점프하기 위한 코드
bpb->jmpBoot[0] = 0xEB;
bpb->jmpBoot[1] = 0x00; /* ?? */
bpb->jmpBoot[2] = 0x90;
// OEM : original equipment manufacturer
memcpy( bpb->OEMName, "MSWIN4.1", 8 );
// 타입에 맞는 cluster 당 sector 개수
sectorsPerCluster = get_sector_per_cluster( FATType, diskSize, bytesPerSector );
if( sectorsPerCluster == 0 )
{
WARNING( "The number of sector is out of range\n" );
return -1;
}
// 여러가지 디스크의 하드웨어적인 정보를 setting
bpb->bytesPerSector = bytesPerSector;
bpb->sectorsPerCluster = sectorsPerCluster;
bpb->reservedSectorCount = ( FATType == FAT32 ? 32 : 1 );
bpb->numberOfFATs = 1;
bpb->rootEntryCount = ( FATType == FAT32 ? 0 : 512 );
bpb->totalSectors = ( numberOfSectors < 0x10000 ? ( UINT16 ) numberOfSectors : 0 );
bpb->media = 0xF8;
fill_fat_size( bpb, FATType ); // fat 크기 구해서 bpb에 넣어주는 함수
bpb->sectorsPerTrack = 0;
bpb->numberOfHeads = 0;
bpb->totalSectors32 = ( numberOfSectors >= 0x10000 ? numberOfSectors : 0 );
// FAT32에만 들어가는것들 처리
if( FATType == FAT32 )
{
bpb->BPB32.extFlags = 0x0081; /* active FAT : 1, only one FAT is active */
bpb->BPB32.FSVersion = 0;
// bpb->BPB32.rootCluster = 2;
// FSInfo : FSInfo가 위치하는 sector offset. 일반적으로 pbr 바로 뒤에 위치하므로 1의 값을 가짐
bpb->BPB32.FSInfo = 1;
// backupBootSector : BPB의 Backup 영역이 존재하는 sector offset. 일반적으로 0의 값을 가짐
bpb->BPB32.backupBootSectors = 6;
bpb->BPB32.backupBootSectors = 0;
// reserved : 예약된 영역. 무조건 0으로 설정
ZeroMemory( bpb->BPB32.reserved, 12 );
}
if( FATType == FAT32 )
bs = &bpb->BPB32.bs;
else
bs = &bpb->bs;
if( FATType == FAT12 )
bs->driveNumber = 0x00;
else
bs->driveNumber = 0x80;
// Reserved : 예약된 영역으로 항상 0으로 채워진다.
// Reserved1 : Windows NT 계열에서 사용하려고 만든 예약된 영역이며 0으로 채워져 있다.
// Boot Signature : 확장 부트 서명으로 0x29라는 값이 들어간다(이후에 3가지 항목이 더 존재함을 의미)
// Volume ID : 볼륨의 시리얼 번호
// Volume Label : 볼륨 레이블을 적어준다
// File System Type : 항상 FAT32로 적혀있다.
bs->reserved1 = 0;
bs->bootSignature = 0x29;
bs->volumeID = 0;
memcpy( bs->volumeLabel, VOLUME_LABEL, 11 );
memcpy( bs->filesystemType, filesystemType[FATType], 8 );
return FAT_SUCCESS;
}
int get_fat_type( FAT_BPB* bpb )
{
UINT32 totalSectors, dataSector, rootSector, countOfClusters, FATSize;
rootSector = ( ( bpb->rootEntryCount * 32 ) + ( bpb->bytesPerSector - 1 ) ) / bpb->bytesPerSector;
if( bpb->FATSize16 != 0 )
FATSize = bpb->FATSize16;
else
FATSize = bpb->BPB32.FATSize32;
if( bpb->totalSectors != 0 )
totalSectors = bpb->totalSectors;
else
totalSectors = bpb->totalSectors32;
dataSector = totalSectors - ( bpb->reservedSectorCount + ( bpb->numberOfFATs * FATSize ) + rootSector );
countOfClusters = dataSector / bpb->sectorsPerCluster;
if( countOfClusters < 4085 )
return FAT12;
else if( countOfClusters < 65525 )
return FAT16;
else
return FAT32;
return FAT_ERROR;
}
FAT_ENTRY_LOCATION get_entry_location( const FAT_DIR_ENTRY* entry )
{
FAT_ENTRY_LOCATION location;
location.cluster = GET_FIRST_CLUSTER( *entry );
location.sector = 0;
location.number = 0;
return location;
}
/* fills the reserved fields of FAT */
int fill_reserved_fat( FAT_BPB* bpb, BYTE* sector )
{
BYTE FATType;
DWORD* shutErrBit12;
WORD* shutBit16;
WORD* errBit16;
DWORD* shutBit32;
DWORD* errBit32;
FATType = get_fat_type( bpb );
if( FATType == FAT12 )
{
shutErrBit12 = ( DWORD* )sector;
*shutErrBit12 = 0xFF0 << 20;
*shutErrBit12 |= ( ( DWORD )bpb->media & 0x0F ) << 20;
*shutErrBit12 |= MS_EOC12 << 8;
}
else if( FATType == FAT16 )
{
shutBit16 = ( WORD* )sector;
errBit16 = ( WORD* )sector + sizeof( WORD );
*shutBit16 = 0xFFF0 | bpb->media;
*errBit16 = MS_EOC16;
}
else
{
shutBit32 = ( DWORD* )sector;
errBit32 = ( DWORD* )sector + sizeof( DWORD );
*shutBit32 = 0x0FFFFFF0 | bpb->media;
*errBit32 = MS_EOC32;
}
return FAT_SUCCESS;
}
// FAT 테이블 영역을 초기화하는 함수
int clear_fat( DISK_OPERATIONS* disk, FAT_BPB* bpb )
{
UINT32 i, end;
UINT32 FATSize;
SECTOR fatSector;
// sector array의 역할은 sector단위 read, write를 위한 응용프로그램에서의(실제로는 커널) sector크기의 버퍼
BYTE sector[MAX_SECTOR_SIZE];
// sector부터 sector 크기만큼을 0으로 채움
ZeroMemory( sector, sizeof( sector ) );
// bpb->reservedSectorCount는 주어진 디스크에서 앞에서부터 0번으로 시작하여
// 몇번 섹터까지 메타데이터를 위한 섹터로 사용이 되었고,
// 그래서 지금 몇번째 섹터에 메타데이터가 들어갈 수 있는지를 의미함
// -> FAT영역이 이곳에 저장됨
fatSector = bpb->reservedSectorCount;
// FATSize16 : FAT영역의 섹터 수를 저장한는 부분으로, FAT32에서는 0으로 채워진다.
// FATSize32 : FAT영역의 섹터 수를 의미하는데 이 수는 FAT#1과 FAT#2의 합산이 아닌 한 개의 FAT영역의 섹터 수를 의미함
if( bpb->FATSize16 != 0 )
FATSize = bpb->FATSize16;
else
FATSize = bpb->BPB32.FATSize32;
// numberofFATs : 해당 볼륨에 존재하는 FAT영역의 개수 --> end는 결국 그 FAT파일시스템의 끝 섹터번호 가리킴
end = fatSector + ( FATSize * bpb->numberOfFATs );
// 이 부분부터 이 함수의 끝까지 FAT영역을 초기화하는 코드
/* (FAT 테이블을 위해 사용될 공간은 모두 0으로 초기화되어 사용가능 상태를 나타내야 한다.)
단, 클러스터 0,1에 대응하는 FAT링크의 경우 FAT버전에 따라 특별한 값을 가지게 되고
그 부분을 제외한 나머지만 0으로 초기화해야하기 때문에 0으로 초기화시킨 섹터버퍼를
fill_reserved_fat으로 넘겨서 처리, 그리고 나머지 FAT영역의 섹터들은 모두 0으로 아래 for문에서 처리한다.*/
fill_reserved_fat( bpb, sector );
// fatSector번 섹터에 sector배열 내용 씀
disk->write_sector( disk, fatSector, sector );
// 섹터를 섹터크기만큼 0으로 채움
ZeroMemory( sector, sizeof( sector ) );
// 이 for문 안에서 나머지 FAT영역의 섹터들을 0으로 채움
for( i = fatSector + 1; i < end; i++ )
disk->write_sector( disk, i, sector );
return FAT_SUCCESS;
}
// 루트 디렉터리 생성하는 함수
int create_root( DISK_OPERATIONS* disk, FAT_BPB* bpb )
{
BYTE sector[MAX_SECTOR_SIZE]; // sector버퍼
SECTOR rootSector = 0;
FAT_DIR_ENTRY* entry;
// sector버퍼 0으로 초기화
ZeroMemory( sector, MAX_SECTOR_SIZE );
entry = ( FAT_DIR_ENTRY* )sector;
// FAT_DIR_ENTRY의 name과 attribute를 채우는 코드
// name : 파일, 디렉터리의 이름
// attribute : 해당 디렉터리 엔트리의 용도를 기록하는 항목
// VOLUME_LABEL 11바이트만큼을 entry의 name에 복사
memcpy( entry->name, VOLUME_LABEL, 11 );
// attribute = 0x08
entry->attribute = ATTR_VOLUME_ID;
/* Mark as no more directory is in here */
entry++;
// 디렉터리의 끝을 나타냄
entry->name[0] = DIR_ENTRY_NO_MORE;
// 루트 디렉터리 엔트리를 몇번 섹터에 위치시킬지 정하고, 그 위치의 섹터에 write하는 과정
// (위치하게 되는곳이 fat의 버전마다 다름)
if( get_fat_type( bpb ) == FAT32 )
{
/* Not implemented yet */
}
else
// bpb->FATSize16은 FAT16버전에서 FAT하나를 위해서 필요한 섹터가 몇개인지를 나타냄
// 결국 아래코드는 Reserved영역과 FAT영역까지의 섹터수를 합해서 다음 사용가능한 섹터수를 구하는 코드
rootSector = bpb->reservedSectorCount + ( bpb->numberOfFATs * bpb->FATSize16 );
// 그 섹터에 sector버퍼의 내용 씀
disk->write_sector( disk, rootSector, sector );
return FAT_SUCCESS;
}
// FAT영역 내에서의 cluster번호 offset정보(볼륨에서의 sector, sector내에서의 offset)
int get_fat_sector( FAT_FILESYSTEM* fs, SECTOR cluster, SECTOR* fatSector, DWORD* fatEntryOffset )
{
DWORD fatOffset;
switch( fs->FATType )
{
case FAT32:
fatOffset = cluster * 4;
break;
case FAT16:
fatOffset = cluster * 2;
break;
case FAT12:
fatOffset = cluster + ( cluster / 2 );
break;
default:
WARNING( "Illegal file system type\n" );
fatOffset = 0;
break;
}
// 몇 번째 sector인지
*fatSector = fs->bpb.reservedSectorCount + ( fatOffset / fs->bpb.bytesPerSector );
// sector 내에서의 오프셋?
*fatEntryOffset = fatOffset % fs->bpb.bytesPerSector;
return FAT_SUCCESS;
}
// cluster가 존재하는 fat영역 내의 sector를 읽음
// offset을 수정해서 sector를 읽었을 경우 이를 알리기 위해 1을 리턴???????????
int prepare_fat_sector( FAT_FILESYSTEM* fs, SECTOR cluster, SECTOR* fatSector, DWORD* fatEntryOffset, BYTE* sector )
{
get_fat_sector( fs, cluster, fatSector, fatEntryOffset );
fs->disk->read_sector( fs->disk, *fatSector, sector );
if( fs->FATType == FAT12 && *fatEntryOffset == fs->bpb.bytesPerSector - 1 )
{
fs->disk->read_sector( fs->disk, *fatSector + 1, §or[fs->bpb.bytesPerSector] );
return 1;
}
return 0;
}
/* Read a FAT entry from FAT Table */
// FAT 영역에서 cluster 번호에 해당하는 정보를 읽어옴(엔트리)
DWORD get_fat( FAT_FILESYSTEM* fs, SECTOR cluster )
{
BYTE sector[MAX_SECTOR_SIZE * 2];
SECTOR fatSector;
DWORD fatEntryOffset;
// cluster가 존재하는 fat영역 내의 sector를 읽음
// sector에 해당 섹터 데이터가 들어감
prepare_fat_sector( fs, cluster, &fatSector, &fatEntryOffset, sector );
// 해당 sector에서 cluster의 정보(entry)를 읽음
// FAT버전에 따라서 FAT table entry의 크기가 다르기 때문에 하나의 entry를 추출해서 return하는 방식은 모두 다름
switch( fs->FATType )
{
case FAT32:
return ( *( ( DWORD* )§or[fatEntryOffset] ) ) & 0xFFFFFFF;
case FAT16:
return ( DWORD )( *( ( WORD *)§or[fatEntryOffset] ) );
case FAT12:
if( cluster & 1 ) /* Cluster number is ODD */
return ( DWORD )( *( ( WORD *)§or[fatEntryOffset] ) >> 4 );
else /* Cluster number is EVEN */
return ( DWORD )( *( ( WORD *)§or[fatEntryOffset] ) & 0xFFF );
}
return FAT_ERROR;
}
/* Write a FAT entry to FAT Table */
// FAT 영역에 cluster 정보 추가(첫 cluster에 파일 끝을 나타내는 value setting)
int set_fat( FAT_FILESYSTEM* fs, SECTOR cluster, DWORD value )
{
BYTE sector[MAX_SECTOR_SIZE * 2];
SECTOR fatSector;
DWORD fatEntryOffset;
int result;
// cluster가 존재하는 fat영역 내의 sector를 읽음
result = prepare_fat_sector( fs, cluster, &fatSector, &fatEntryOffset, sector );
switch( fs->FATType )
{
case FAT32:
value &= 0x0FFFFFFF;
*( ( DWORD* )§or[fatEntryOffset] ) &= 0xF0000000;
*( ( DWORD* )§or[fatEntryOffset] ) |= value;
break;
case FAT16:
*( ( WORD* )§or[fatEntryOffset] ) = ( WORD )value;
break;
case FAT12:
if( cluster & 1 )
{
value <<= 4;
*( ( WORD* )§or[fatEntryOffset] ) &= 0x000F;
}
else
{
value &= 0x0FFF;
*( ( WORD* )§or[fatEntryOffset] ) &= 0xF000;
}
*( ( WORD* )§or[fatEntryOffset] ) |= ( WORD )value;
break;
}
// fatSector번 섹터에 sector버퍼의 내용 씀
fs->disk->write_sector( fs->disk, fatSector, sector );
if( result )
fs->disk->write_sector( fs->disk, fatSector + 1, §or[fs->bpb.bytesPerSector] );
return FAT_SUCCESS;
}
/******************************************************************************/
/* Format disk as a specified file system */
/******************************************************************************/
// BPB, FAT, Root directory영역을 모두 초기화한다. 디스크가 정상적으로 사용될 수 있도록 필요한 정보 등록하고 초기화한다.
int fat_format( DISK_OPERATIONS* disk, BYTE FATType )
{
FAT_BPB bpb; // 부트 파라미터 블록(BIOS parameter block)
// bpb를 채워주는 함수, 성공하면 FAT_SUCCESS리턴해줌
if( fill_bpb( &bpb, FATType, disk->numberOfSectors, disk->bytesPerSector ) != FAT_SUCCESS ) // bpb 초기화
return FAT_ERROR;
// disk의 0번섹터에 BPB내용 써줌
disk->write_sector( disk, 0, &bpb );
// 출력
PRINTF( "bytes per sector : %u\n", bpb.bytesPerSector );
PRINTF( "sectors per cluster : %u\n", bpb.sectorsPerCluster );
PRINTF( "number of FATs : %u\n", bpb.numberOfFATs );
PRINTF( "root entry count : %u\n", bpb.rootEntryCount );
PRINTF( "total sectors : %u\n", ( bpb.totalSectors ? bpb.totalSectors : bpb.totalSectors32 ) );
PRINTF( "\n" );
// FAT 테이블 초기화
clear_fat( disk, &bpb );
// root 디렉터리 생성 + 초기화
create_root( disk, &bpb );
return FAT_SUCCESS;
}
int validate_bpb( FAT_BPB* bpb )
{
int FATType;
if( !( bpb->jmpBoot[0] == 0xEB && bpb->jmpBoot[2] == 0x90 ) &&
!( bpb->jmpBoot[0] == 0xE9 ) )
return FAT_ERROR;
FATType = get_fat_type( bpb );
if( FATType < 0 )
return FAT_ERROR;
return FAT_SUCCESS;
}
/* when FAT type is FAT12 or FAT16 */
int read_root_sector( FAT_FILESYSTEM* fs, SECTOR sectorNumber, BYTE* sector )
{
SECTOR rootSector;
rootSector = fs->bpb.reservedSectorCount + ( fs->bpb.numberOfFATs * fs->bpb.FATSize16 );
return fs->disk->read_sector( fs->disk, rootSector + sectorNumber, sector );
}
int write_root_sector( FAT_FILESYSTEM* fs, SECTOR sectorNumber, const BYTE* sector )
{
SECTOR rootSector;
rootSector = fs->bpb.reservedSectorCount + ( fs->bpb.numberOfFATs * fs->bpb.FATSize16 );
return fs->disk->write_sector( fs->disk, rootSector + sectorNumber, sector );
}
/* Translate logical cluster and sector numbers to a physical sector number */
SECTOR calc_physical_sector( FAT_FILESYSTEM* fs, SECTOR clusterNumber, SECTOR sectorNumber )
{
SECTOR firstDataSector;
SECTOR firstSectorOfCluster;
SECTOR rootDirSectors;
rootDirSectors = ( ( fs->bpb.rootEntryCount * 32 ) + ( fs->bpb.bytesPerSector - 1 ) ) / fs->bpb.bytesPerSector ;
firstDataSector = fs->bpb.reservedSectorCount + ( fs->bpb.numberOfFATs * fs->FATSize ) + rootDirSectors;
firstSectorOfCluster = ( ( clusterNumber - 2 ) * fs->bpb.sectorsPerCluster ) + firstDataSector;
return firstSectorOfCluster + sectorNumber;
}
int read_data_sector( FAT_FILESYSTEM* fs, SECTOR clusterNumber, SECTOR sectorNumber, BYTE* sector )
{
return fs->disk->read_sector( fs->disk, calc_physical_sector( fs, clusterNumber, sectorNumber ), sector );
}
int write_data_sector( FAT_FILESYSTEM* fs, SECTOR clusterNumber, SECTOR sectorNumber, const BYTE* sector )
{
return fs->disk->write_sector( fs->disk, calc_physical_sector( fs, clusterNumber, sectorNumber ), sector );
}
/* search free clusters from FAT and add to free cluster list */
int search_free_clusters( FAT_FILESYSTEM* fs )
{
UINT32 totalSectors, dataSector, rootSector, countOfClusters, FATSize;
UINT32 i, cluster;
rootSector = ( ( fs->bpb.rootEntryCount * 32 ) + ( fs->bpb.bytesPerSector - 1 ) ) / fs->bpb.bytesPerSector;
if( fs->bpb.FATSize16 != 0 )
FATSize = fs->bpb.FATSize16;
else
FATSize = fs->bpb.BPB32.FATSize32;
if( fs->bpb.totalSectors != 0 )
totalSectors = fs->bpb.totalSectors;
else
totalSectors = fs->bpb.totalSectors32;
dataSector = totalSectors - ( fs->bpb.reservedSectorCount + ( fs->bpb.numberOfFATs * FATSize ) + rootSector );
countOfClusters = dataSector / fs->bpb.sectorsPerCluster;
for( i = 2; i < countOfClusters; i++ )
{
cluster = get_fat( fs, i );
if( cluster == FREE_CLUSTER )
add_free_cluster( fs, i );
}
return FAT_SUCCESS;
}
// root 전달인자에 루트 디렉터리 정보가 저장되는 함수
int fat_read_superblock( FAT_FILESYSTEM* fs, FAT_NODE* root )
{
INT result;
BYTE sector[MAX_SECTOR_SIZE]; // 섹터버퍼
// 전달인자 검사
if( fs == NULL || fs->disk == NULL )
{
WARNING( "DISK_OPERATIONS : %p\nFAT_FILESYSTEM : %p\n", fs, fs->disk );
return FAT_ERROR;
}
// disk의 첫번째 sector(BPB가 저장되어있는 sector)를 읽어서 fs->bpb에 저장
if( fs->disk->read_sector( fs->disk, 0, &fs->bpb ) )
return FAT_ERROR;
// super block 유효검사 (bpb)
result = validate_bpb( &fs->bpb );
if( result )
{
WARNING( "BPB validation is failed\n" );
return FAT_ERROR;
}
fs->FATType = get_fat_type( &fs->bpb );
// FAT타입 유효검사 : FAT12, 16, 32
if( fs->FATType > FAT32 )
return FAT_ERROR;
// root directory sector 읽어서 섹터버퍼에 저장
if( read_root_sector( fs, 0, sector ) )
return FAT_ERROR;
// 전달받은 root디렉터리 노드정보 setting
ZeroMemory( root, sizeof( FAT_NODE ) );
memcpy( &root->entry, sector, sizeof( FAT_DIR_ENTRY ) );
root->fs = fs;
// FAT 파일시스템의 경우 FAT 테이블에서 EOC(end of cluster)를 나타내는 비트열이 모두 다른데
// 이것이 버전에 맞게 설정되었는지 확인하는 코드
// 0,1번째 cluster는 나머지 cluster와는 다르게 파일할당에 사용되지 않고 특별한 목적으로 이용됨
// 따라서 FAT Table에서 해당하는 부분은 EOC로 체크되어있음. 따라서 이 부분을 이용함
// fs영역에서 해당 cluster에 해당하는 정보 읽어옴
fs->EOCMark = get_fat( fs, 1 );
// 버전에 따라 확인
if( fs->FATType == 2 )
{
if( fs->EOCMark & SHUT_BIT_MASK32 )
WARNING( "disk drive did not dismount correctly\n" );
if( fs->EOCMark & ERR_BIT_MASK32 )
WARNING( "disk drive has error\n" );
}
else
{
if( fs->FATType == 1)
{
if( fs->EOCMark & SHUT_BIT_MASK16 )
PRINTF( "disk drive did not dismounted\n" );
if( fs->EOCMark & ERR_BIT_MASK16 )
PRINTF( "disk drive has error\n" );
}
}
/* FAT버전에 따라서 FATsize를 저장하기 위한 멤버가 다름
FAT32인 경우 bpb.FATSize16을 0으로 하고 FATSize32에 값을 기록함
FAT16, 12의 경우 bpb.FATSize16만 사용한다
bpb에 있는 데이터를 fs구조체 멤버(fs->FATSize)에 복사하고 나면
FAT버전에 관계없이 fs->FATSize로 사용할 수 있음*/
if( fs->bpb.FATSize16 != 0 )
fs->FATSize = fs->bpb.FATSize16;
else
fs->FATSize = fs->bpb.BPB32.FATSize32;
// fs구조체가 가리키는 freeClusterList를 0으로 초기화
init_cluster_list( &fs->freeClusterList );
// free cluster를 찾고 freeClusterList에 추가
search_free_clusters( fs );
// 전달받은 root의 entry의 name에 0x20(공백) 11바이트 채움
memset( root->entry.name, 0x20, 11 );
return FAT_SUCCESS;
}
/******************************************************************************/
/* On unmount file system */
/******************************************************************************/
void fat_umount( FAT_FILESYSTEM* fs )
{
// free cluster_list 해제
release_cluster_list( &fs->freeClusterList );
}
// sector단위에 저장되어있는 dir_entry들을 읽음
int read_dir_from_sector( FAT_FILESYSTEM* fs, FAT_ENTRY_LOCATION* location, BYTE* sector, FAT_NODE_ADD adder, void* list )
{
UINT i, entriesPerSector;
FAT_DIR_ENTRY* dir;
FAT_NODE node;
// sector 당 entry개수
entriesPerSector = fs->bpb.bytesPerSector / sizeof( FAT_DIR_ENTRY );
// sector를 dir_entry 배열로 관리
dir = ( FAT_DIR_ENTRY* )sector;
// sector의 모든 directory entry 순회
for( i = 0; i < entriesPerSector; i++ )
{
if( dir->name[0] == DIR_ENTRY_FREE )
;
// 더이상 엔트리 없으면 break
else if( dir->name[0] == DIR_ENTRY_NO_MORE )
break;
else if( !( dir->attribute & ATTR_VOLUME_ID ) )
{
node.fs = fs;
node.location = *location; // cluster, sector정보
node.location.number = i; // number에는 지금sector에서 현재 엔트리 offset
node.entry = *dir; // 해당 순서의 디렉터리 엔트리
adder( list, &node ); // fat_node를 shell_entry로해서 list에 추가
}
dir++; // 디렉터리 엔트리 증가
}
// 다 돌았으면 0리턴
// 다 못돌았으면 (DIR_ENTRY_NO_MORE인 경우) -1리턴
return ( i == entriesPerSector ? 0 : -1 );
}
DWORD get_MS_EOC( BYTE FATType )
{
switch( FATType )
{
case FAT12:
return MS_EOC12;
case FAT16:
return MS_EOC16;
case FAT32:
return MS_EOC32;
}
WARNING( "Incorrect FATType(%u)\n", FATType );
return -1;
}
int is_EOC( BYTE FATType, SECTOR clusterNumber )
{
switch( FATType )
{
case FAT12:
if( EOC12 <= ( clusterNumber & 0xFFF ) )
return -1;
break;
case FAT16:
if( EOC16 <= ( clusterNumber & 0xFFFF ) )
return -1;
break;
case FAT32:
if( EOC32 <= ( clusterNumber & 0x0FFFFFFF ) )
return -1;
break;
default:
WARNING( "Incorrect FATType(%u)\n", FATType );
}
return 0;
}
/******************************************************************************/
/* Read all entries in the current directory */
/******************************************************************************/
// 디렉터리 안에 있는 모든 entry 읽음
int fat_read_dir( FAT_NODE* dir, FAT_NODE_ADD adder, void* list )
{
BYTE sector[MAX_SECTOR_SIZE]; // 섹터버퍼
SECTOR i, j, rootEntryCount;
FAT_ENTRY_LOCATION location;
// 전달받은 fat_node의 entry가 루트 디렉터리일때
if( IS_POINT_ROOT_ENTRY( dir->entry ) && ( dir->fs->FATType == FAT12 || dir->fs->FATType == FAT16 ) )
{
// FAT32가 아닌경우 rootEntryCount를 bpb에 있는것 그대로(루트 디렉터리가 수용하는 엔트리 개수)
if( dir->fs->FATType != FAT32 )
rootEntryCount = dir->fs->bpb.rootEntryCount;
// 루트 디렉터리의 모든 엔트리 순회
for( i = 0; i < rootEntryCount; i++ )
{
// i번째 섹터를 sector버퍼에 읽어옴
read_root_sector( dir->fs, i, sector );
location.cluster = 0; // 클러스터 위치는 0으로 고정
location.sector = i; // 섹터만 변경
location.number = 0;
// 한 섹터에서 dir_entry를 읽어서 리스트에 넣었줌
// 다 돌았으면(sector에 들어갈 수 있는 dir_entry 개수만큼) 0리턴 -> 다음 sector도 봐야함
// 다 안돌았으면(dir_entry가 더이상 없으면) -1리턴 -> break;, for문 탈출
if( read_dir_from_sector( dir->fs, &location, sector, adder, list ) )
break;
}
}
// 루트 디렉터리가 아닐 때(일반)
else
{
// dir_entry가 시작되는 cluster 위치
i = GET_FIRST_CLUSTER( dir->entry );
do
{
// cluster 하나의 섹터를 모두 순회
for( j = 0; j < dir->fs->bpb.sectorsPerCluster; j++ )
{
// j번째 섹터를 sector버퍼에 읽어옴
read_data_sector( dir->fs, i, j, sector );
location.cluster = i;
location.sector = j;
location.number = 0;
// 한 섹터에서 dir_entry를 읽어서 리스트에 넣었줌
// 다 돌았으면(sector에 들어갈 수 있는 dir_entry 개수만큼) 0리턴 -> 다음 sector도 봐야함
// 다 안돌았으면(dir_entry가 더이상 없으면) -1리턴 -> break;, for문 탈출
if( read_dir_from_sector( dir->fs, &location, sector, adder, list ) )
break;
}
// 다음 cluster로 이동
i = get_fat( dir->fs, i );
} while( !is_EOC( dir->fs->FATType, i ) && i != 0 );
}
return FAT_SUCCESS;
}
int add_free_cluster( FAT_FILESYSTEM* fs, SECTOR cluster )
{
return push_cluster( &fs->freeClusterList, cluster );
}
SECTOR alloc_free_cluster( FAT_FILESYSTEM* fs )
{
SECTOR cluster;
if( pop_cluster( &fs->freeClusterList, &cluster ) == FAT_ERROR )
return 0;
return cluster;
}
SECTOR span_cluster_chain( FAT_FILESYSTEM* fs, SECTOR clusterNumber )
{
UINT32 nextCluster;
nextCluster = alloc_free_cluster( fs );
if( nextCluster )
{
set_fat( fs, clusterNumber, nextCluster );
set_fat( fs, nextCluster, get_MS_EOC( fs->FATType ) );
}
return nextCluster;
}
// begin에서 last까지 formattedName을 가진 entry를 sector에서 검색해서 그 인덱스를 number에 저장하는 함수
int find_entry_at_sector( const BYTE* sector, const BYTE* formattedName, UINT32 begin, UINT32 last, UINT32* number )
{
UINT32 i;
const FAT_DIR_ENTRY* entry = ( FAT_DIR_ENTRY* )sector;
for( i = begin; i <= last; i++ )
{
if( formattedName == NULL )
{
if( entry[i].name[0] != DIR_ENTRY_FREE && entry[i].name[0] != DIR_ENTRY_NO_MORE )
{
// formattedName이 null인 경우에는 현재 사용중인 첫번째 entry를 읽어오면 됨
*number = i;
return FAT_SUCCESS;
}
}
else // formattedName이 어떤 값을 가지고 있는 경우
{
if( ( formattedName[0] == DIR_ENTRY_FREE || formattedName[0] == DIR_ENTRY_NO_MORE ) &&
( formattedName[0] == entry[i].name[0] ) )
{
*number = i;
return FAT_SUCCESS;
}
// 두 문자열이 같으면
if( memcmp( entry[i].name, formattedName, MAX_ENTRY_NAME_LENGTH ) == 0 )
{
*number = i;
return FAT_SUCCESS;
}
}
// 더이상 찾을 디렉터리가 없음
if( entry[i].name[0] == DIR_ENTRY_NO_MORE )
{
*number = i;
return -2;
}
}
// i = last+1
*number = i;
return -1;
}
// 호출문장 : find_entry_on_root(fs, first, entryName, ret);
int find_entry_on_root( FAT_FILESYSTEM* fs, const FAT_ENTRY_LOCATION* first, const BYTE* formattedName, FAT_NODE* ret )
{
BYTE sector[MAX_SECTOR_SIZE]; // sector버퍼
UINT32 i, number;
UINT32 lastSector;
UINT32 entriesPerSector, lastEntry;
INT32 begin = first->number;
INT32 result;
FAT_DIR_ENTRY* entry;
entriesPerSector = fs->bpb.bytesPerSector / sizeof( FAT_DIR_ENTRY );
lastEntry = entriesPerSector - 1;
lastSector = fs->bpb.rootEntryCount / entriesPerSector;
// root sector 영역에서 sector 단위로 변위를 주어 모든 sector 검색이 가능하게 한다
for( i = first->sector; i <= lastSector; i++ )
{
// root sector중에서 i번째 sector를 sector버퍼에 write
read_root_sector( fs, i, sector );
// 읽어온 sector의 첫번째 FAT_DIR_ENTRY를 entry에 연결
entry = ( FAT_DIR_ENTRY* )sector;
/* 아래 함수는 하나의 sector에서 찾고자 하는 formattedName을 가진 entry를 검사해서
있으면 하나의 sector를 FAT_DIR_ENTRY의 배열로 보았을 때 찾은 entry의
sector에서의 인덱스를 number에 넣어준다*/
result = find_entry_at_sector( sector, formattedName, begin, lastEntry, &number );
begin = 0;
// 못찾은 경우
if( result == -1 )
continue;
else
{
// 찾을 directory entry가 더이상 없는경우(DIR_ENTRY_NO_MORE)
if( result == -2 )
return FAT_ERROR;
else
{
// FAT_NODE* ret에서 가리키는 FAT_NODE를 찾은 entry정보로 초기화하는 코드
// formattedName으로 검색하여 찾은 FAT_DIR_ENTRY를 ret->entry에 write
memcpy( &ret->entry, &entry[number], sizeof( FAT_DIR_ENTRY ) );
// cluster위치는 고정
ret->location.cluster = 0;
// sector의 실제 위치
ret->location.sector = i;
// sector 내부에서의 실제 인덱스
ret->location.number = number;
// 파일시스템 연결
ret->fs = fs;
}