Homework
1. Make a Virtual Floopy disk
$ dd bs=1024 count=1440 if=/dev/zero of=myfd
myfd 이름의 1.44MB 크기의 가상 플로피 디스크를 생성
dd → Disk에 Data를 쓰는 명령어
bs → Block Size
- bs = 1024 -> 1 Block이 1024 Byte
- Block은 File System Block이 아닌 dd 명령의 데이터 전송 단위
count → 기록할 Block 수
- count = 1440 → 1440 Block 쓰기
- 1440 * 1024 = 1.44MB 의미
if → 데이터를 읽을 입력 파일
/dev/zero → 읽을 때 0을 주는 특수 file
of → 출력 파일
$ mkfs -t ext2 myfd
myfd를 ext2 File System으로 Format
3. Mount
$ mkdir temp
$ mount -o loop myfd temp
temp 임시 Directory에 myfd를 mount 한다.
myfd는 실제 Disk가 아닌 Disk Image가 들어 있는 파일이므로 **-o loop** 옵션을 사용해야 한다
이 명령어는 myfd Disk를 /temp Directory에 연결하며, /temp를 통해 "myfd" disk에 access할 수 있다
4. Make some files
$ cd temp
$ echo korea > f1
이 명령어를 통해 temp Directory 안에 f1 파일을 만들 수 있다
5. Read
$ cd ..
$ umount temp
$ xxd -g1 myfd > x
umount 명령어를 통해 myfd Disk에서 변경 사항을 읽을 수 있다
"g1" 옵션은 myfd의 각 Byte를 분리하여 읽을 수 있게 한다
$ vi x
$ :1
vi 를 통해 파일을 읽을 때, 첫 줄부터 시작하고 싶다면 :1 을 입력하면 된다
6. Read Superblock
Superblock은 Offset 1024 (400h) 에서 시작한다.
- Superblock을 찾아서 현재 Disk의 총 inode의 수, 총 Block 수, magic 번호, Block Size, first data block을 읽는다.
- 모든 Multi-byte number는 little endian으로 저장.
- 실제 값 계산 위해서 Byte 순서를 거꾸로 해야 한다.
$ typedef struct
{
u32 m_inodes_count; // 0-3
u32 m_blocks_count; // 4-7
u32 m_first_data_block; // 14-17
// block location of superblock.
u32 m_log_block_size; // 18-1B. block size=1024*2^(m_log_block_size))
u16 m_magic; // 38-39
} SuperBlock;
m_inodes_count
- 0x0 ~ 0x3
- 0x000000b8
- 10진수로 계산 → 184
- 이 Disk에 총 184개의 Inode가 존재함
m_blocks_count
- 0x4 ~ 0x7
- 0x000005a0
- 10진수로 계산 → 1,440
- 이 시스템을 구성하는 Block의 수가 1,440개
- count = 1440 옵션과 동일
m_magic
- 0x38 ~ 0x39
- 0xef53
- File system EXT2
1024∗2mlogblocksize
- 0x00000000
- 10진수로 계산 → 0
- 즉, 1024∗20이므로 1024
- 한 Block의 Size는 1024 Byte
- bs = 1024 옵션과 동일
m_first_data_block
- 0x14 ~ 0x17
- 0x00000001
- 10진수로 계산 → 1
- 한 Block이 1024 Byte이므로 1024 * 1 = 1024 = 0x400이 Superblock의 위치
7. Read the Group Descriptor
- SuperBlock 다음 Block이 Group Descriptor
- 즉, Group Descriptor는 0x800에 위치
1 Block당 0x400이므로 첫번째 Block이 0x400이면 두번째 Block은 0x400 * 2 = 0x800
- Superblock이 0 Block이면 Group Descriptor는 1 Block부터 시작
- Block X의 Address →
X * Block_Size
$ typedef struct
{
u32 m_block_bitmap; // block location of DBM
u32 m_inode_bitmap; // block location of IBM
u32 m_inode_table; // block location of inode table
} GroupDescriptor;
u32 -> 4 Byte
DBM
- m_block_bitmap
- 0x00 ~ 0x03
- 0x00000008
- 10진수로 계산 → 8
- Data Block Bitmap이 위치한 Block
IBM
- m_inode_bitmap
- 0x04 ~ 0x07
- 0x00000009
- 10진수로 계산 → 9
- Inode Bitmap이 위치한 Block
Inode Table
- m_inode_table
- 0x08 ~ 0x0B
- 0x0000000a
- 10진수로 계산 → 10
- Inode Table이 위치한 Block
8. Read the DBM, IBM
- 사용 중인 Inode 번호와 Block 번호를 찾는다
- Superblock, GroupDescriptor, IBM, DBM, Inode Table 등 모든 Meta-Block 위치를 보여주는 myfd Disk의 Layout 그린다
DBM
- 8번째 Block에 위치하므로 0x400 * 8 = 0x2000
DBM은 현재 어떤 Block이 사용 중인지 0 / 1로 나타냄
- FFFF FFFF FF7F → BIN에서 11111111 11111111 11111111 11111111 11111111 01111111
- 숫자는 오른쪽부터 읽으므로 48번째 Block이 비어 있음을 의미
- 총 47개의 Block이 사용 중임을 알 수 있다
IBM
- 9번째 Block에 위치하므로 0x400 * 9 = 0x2400
IBM은 현재 어떤 Inode 번호가 사용되고 있는지를 의미함
- FF 0F → 11111111 00001111
- 숫자는 오른쪽부터 읽으므로 1번부터 12번까지 1을 가짐
- 1번부터 12번의 Inode를 사용 중임을 알 수 있다
Inode Table
- 10번째 Block에 위치하므로 0x400 * 10 = 0x2800
- 각 Inode는 128 Byte의 크기를 갖는다
- Superblock에서 m_inodes_count = 184였으므로, 총 128 * 184 = 0x5C00
- 총 184개의 Inode는 5C00만큼의 Byte를 가지므로 2400 + 5C00 = 8400으로 0x2800 ~ 0x8400까지 Inode Table의 영역이 된다
- 각 Inode를 확인하고 싶을 경우, Inode Table 영역인 5C00 % B8 = 80으로 0x80 (80h) 단위로 끊어 읽으면 된다
2번 Inode
- root Directory 파일의 Block 위치가 기록되어 있다
- 한 Inode에서, 40 ~ 100 Byte까지는 해당 Inode 번호를 갖는 파일이, Disk에서 위치하는 Block을 16진수 형태로 나타냄
- 위의 root Directory를 보면, 0x21, 즉 33번째 Block에 root Directory 파일이 저장되어 있음
- 33번째 Block의 위치인 0x8400은 Inode Table의 영역 직후이다
- f1 파일은 12번 Inode를 통해 정보 확인이 가능함
- 0x2800부터 1번 Inode를 시작하므로 12번째 Inode는 0x2800 + 0x80 * B = 0X2D80이 된다
- f1 파일은 0x2f, 즉 47번째 Block에 저장되어 있으므로 0xBC00을 확인하면 된다
- 파일에 입력한 Korea 텍스트를 확인할 수 있었다
- 33번째 Block : root Directory
- 44번째 Block : f1
9. Read the Inode Table
- root Directory 파일의 Block Location을 찾는다.
- root Directory 파일의 Byte Size / Blcok Size / Owner를 찾는다.
$ typedef struct // inode
{
u16 m_mode; // 0-1
**u16 m_uid; // 2-3**
**u32 m_size; // 4-7**
u32 m_atime; // 8-B
u32 m_ctime; // C-F
u32 m_mtime; // 10-13
u32 m_dtime; // 14-17
u16 m_gid; // 18-19
u16 m_links_count; // 1A-1B
**u32 m_blocks; // 1C-1F. shows num of data blocks for this file in units of 512 bytes**
u32 m_flags; // 20-23
u32 m_reserved1; // 24-27
**u32 m_block[15]; // block location of this file**
u32 m_generation;
u32 m_file_acl;
u32 m_dir_acl;
u32 m_faddr;
u32 m_reserved2[3];
} Inode;
u32는 4 Byte 차지
u16은 2 Byte 차지
Inode Table
Inode Table은 10번째 Block부터 시작하며 1 Block은 0x400 (= 1024 Byte)
- 즉, 0x2800에 Inode 1 번에 대한 정보가 기록되어 있다
- 각각의 Inode는 Inode Table에서 0x80 (= 128 Byte) 차지
- root Directory File은 Inode 2번에 위치하므로 0x2880 ~ 0x28FF
Inode Table의 Block Location
- Inode Struct를 참고하여, Block Location을 나타내는 m_block은 0x28 ~ 0x2C에 위치
- 2번 Inode의 위치인 0x2880을 기준으로, m_blocks[15] → 0x00000021
- 즉, root Directory File의 Location은 0x400 * 0x21 = 0x8400
Inode Table의 Byte Size
- Inode Struct를 참고하여, Byte Size를 나타내는 m_size는 0x4 ~ 0x7에 위치
- m_size → 0x00000400
- 10진수로 계산 → 1,024 Bytes
Inode Table의 Block Size
- Inode Struct를 참고하여, Block Size를 나타내는 m_blocks는 0x1C ~ 0x1F에 위치
- m_blocks → 0x00000002
- 10진수로 계산 → 2이며, 단위가 512 Bytes 이므로 1024 Bytes
Inode Table의 Owner
- Inode Struct를 참고하여, Owner를 나타내는 uid field는 0x2 ~ 0x3에 위치
- m_uid → 0x0000이므로 uid 0인 root 사용자
10. Read the root Directory File
- Member files의 개수를 찾는다.
- Member files들의 Inode 번호와 File 이름을 찾는다.
- Inode Table로 이동해서 각 Member file의 Block Location을 찾는다.
$ **typedef struct // directory
{
u32 m_inode;
u16 m_rec_len;
u08 m_name_len;
u08 m_file_type;
char m_name[255];
} DirectoryEntry;**
- rec_len씩 Directory File을 끊어보았다.
Inode Number
→ 주황색, Record Length
→ 빨간색, File name
→ 초록색
- Member File들은 총 4개가 존재하는 것을 확인했다.
각 Member File들의 Block Location은 0x2800 + 0x80 * (N - 1) → N : Inode 번호
- file .와 ..는 Inode 2인 root Directory File
lost+found의 Inode Table
- Inode Number 11 → N = 11
- Block Location : 0x2800 + 0x80 * 10 = 0x2D00
- lost+found의 Block Location은 0x00000022 * 0x400 = 0x8800
f1의 Inode Table
- Inode Number 12 → N = 12
- Block Location : 0x2800 + 0x80 * 11 = 0x2D80
- f1의 Block Location은 0x0000002f * 0x400 = 0xBC00
11. Read the Member file
lost+found directory file
Inode Number | Record Length | File name |
---|
11 (0xb) | 12 (0x2e) | . |
2 | 1012 (0x3f4) | .. |
- lost+found 파일 내부에 .와 .. 파일이 존재한다
- . 파일은 Inode 11인 자신을 나타낸다
- .. 파일은 Inode 2인 root Directory file을 나타낸다
f1
- f1은 file type 번호가 1인 Regular File로, f1의 data인 "korea"가 저장되어 있다
- f1의 file type은 1인 Regular File
$ **typedef struct // directory
{
u32 m_inode;
u16 m_rec_len;
u08 m_name_len;
u08 m_file_type;
char m_name[255];
} DirectoryEntry;**
12. Hidden files
$ ls
$ ls -a
-a 옵션을 추가하면 숨겨진 파일 (., ..)를 포함한 현재 Directory file 이 출력됨
13. Print Inode Number
$ ls -ai
-a 옵션에 i를 추가하면, 각 파일명 왼쪽에 Inode 번호가 출력됨
14. Make another file in Virtual Disk
rm
명령으로 이 파일을 삭제한다.
- 삭제한 뒤 File system의 변화를 확인한다.
- 삭제한 File system을 복구한다.
- f2를 생성하기 전의 File system X와 생성한 후의 hw14 비교
DBM
- 48번 Blcok이 사용 중으로 바뀌었다
- 0111 1111 → 1111 1111
IBM
- 13번 Inode가 사용 중을 바뀌었다
- 0000 1111 → 0001 1111
Inode Table
- 추가된 13번째 Inode의 위치인 0x2E00 (0x2800 + 0x80 * 0xC)의 기록
- f2의 Block Location은 0x00000030 * 0x400 = 0xC000
- 0xC000에 f2의 내용 "hello"가 잘 기록되었다
root Directory File
- f2가 추가된 것을 확인할 수 있다
- f1의 rec_len은 0x3D4 → 0xC로 변경되었는데, 이는 마지막 파일이 F1에서 F2로 변경되면서 F2에게 1024 Bytes에서 남은 len을 모두 할당하기 때문
f2의 정보
- Inode Number → 0xD = 13
- Record Length → 0x3C8 = 968 Bytes
- Name Length → 2 Bytes
- File type → 1 = Regular file
Mount
- mount로 temp와 연결한 뒤 f2의 Inode Number가 13임을 확인하였다
Rm
- f2를 삭제한 뒤에 다시 file system을 확인해본다
DBM, IBM
- 48번 Block과 13번 Inode가 f2 생성 전 상태인 Empty로 변경되었다
Inode Table
- node Table의 경우 f2 생성 전처럼 0으로 깨끗히 지워지진 않았다
- m_ctime (마지막 변경 시간), m_dtime (삭제한 시간), m_links_count(해당 Inode를 참조하는 링크 수)가 변경되었다
- file을 삭제하면 해당 파일의 Inode Table에 삭제된 시간, 즉 마지막 변경 시간이 기록되며 links_count가 0을 변경된다
root Directory file, Block Location
- root Directory file과 Block Location엔 여전히 f2의 내용이 그대로 남아있다
- file 내용 자체는 삭제해도 남아있으므로, file system을 editor를 통해 위에서 변경된 DBM, IBM, Inode Table의 내용을 삭제 전으로 바꿔놓을 경우 복구가 가능할 것이다
14 - 1. Make a new directory in the root directory
mkdir
명령으로 새로운 Directory d7 생성
- root Directory file의 Disk File 목록을 표시한다
- D7의 Inode Number를 확인한다
- d7 디렉토리 생성 후 file system을 확인했다
root directory file
- d7의 Inode Number는 0xD = 13
14 - 2. Show the Inode Content of d7
- d7의 Block Location을 찾는다.
- d7의 Block Content를 보인다.
- d7 내에 어떤 File이 있는지 보인다.
Inode Table
- 추가된 13번째 Inode의 Block Location은 0x2E00 (0x2800 + 0x80 * 0xC)
- d7의 Block Location은 0x400 * 0x30 = 0xC000
Block Conent
Inode Number | Name Length | File Type | Record Length | File Name |
---|
13 (0xd) | 1 | directory (2) | 12 (0x2e) | . |
2 | 2 | directory (2) | 1012 (0x3f4) | .. |
- d7 디렉토리 파일 내부에는 .와 ..이 있다.
- . 파일은 Inode Number 13인 자신이다.
- .. 파일은 Inode Number 2인 root Directory File이다
14 - 3. Run "mv f1 d7/f2"
변경된 내용을 보인다.
- f1 파일을 d7 디렉토리 하위 f2의 이름으로 옮겼다
root Directory File
Inode Table in d7
- c_time (마지막 변경 시간), m_time (마지막 수정 시간)만 변경되었다
Block Content
f2가 추가되었다
- Inode Number → 0xC : 12
- Record Length → 0x3E8 : 1000 Bytes
- Name Length → 2 Bytes
- File type → 1 = Regular file
이동 전 f1의 Inode Number 12를 그대로 가져온 것을 확인했다
15. Examine the file system in the hard disk (/dev/sda3)
- Hard Disk (/dev/sda3)의 File System을 찾아본다
SuperBlock
- SuperBlock의 Block_number = 0
- 한 Block Size : 1024*22 = 4 KB (0x1000)
- 다음 Block인 GroupDescriptor의 Block Number = 1, Block Location = 0x1000 * 1 = 0x1000
GroupDescriptor
- Inode Table의 Block Number = 0x1DE → 478
- Inode Table Location은 0x1000 * 0x1DE = 0x1DE000
Inode Table
- root Directory file의 Block Number는 0x3D9 → 985
- root Directory file의 Location은 0x1000 * 0x3D9 = 0x3D9000
root Directory File
- Directory의 Struct 중 Record Length를 계산해서 파일을 구분하였다
- File name → 초록색
- 이는 실제 root Directory에 존재하는 파일 이름이다
- 이를 ASCII 코드로 해석하면 다음 동일한 20개의 파일명을 알 수 있다
- EXT2로 포맷된 Disk 장치를 연다.
- SuperBlock, GroupDescriptor, IBM, DBM, Inode Table을 읽어오고 표시하는 프로그램을 작성한다.
- root Directory File, Inode Number, Block Location 위치에 File 이름을 표시한다.
- open(), lseek(), read() 함수 사용한다.
$ struct superblock{
int total_inode_num;
int total_block_num;
.........
};
int x; char buf[1024]; struct superblock *sb;
x=open("myfd", O_RDONLY, 00777); //open a virtual disk
lseek(x, 1024, SEEK_SET); // move the file pointer to offset 1024 where the
// superblock starts
read(x, buf, 1024); // read the superblock into buf
sb=(struct superblock *)buf; // interpret the data in buf as "struct superblock"
printf("total inode num:%x, total_block_num:%x, ...",
sb->total_inode_num, sb->total_block_num, ....);
- Block 하나의 크기는 SuperBlock에 기록된 m_log_block_size 이용
- GroupDescripter는 SuperBlock의 다음 블록임을 이용
- DBM, IBM의 시작점은 각각 GroupDescriptor의 Block_bitmap, Inode_bitmap 이용
- DBM, IBM은 첫 16 Bytes만 출력
- root directory의 Inode Table만 출력
- Inode 하나의 크기는 128 Bytes
- root directory의 Inode Number는 2번
- 즉, root directory의 Inode는 Inode Table 시작점에 128 Bytes 를 더한 값에서 시작
- root directory block에서 root directory 내부 파일의 inode 번호를 알아낸 후, 각 파일의 inode 위치로 이동하여
block 번호를 가져와야하기에 새로운 inode struct를 선언.
- root directory block은 한 블록이기에 one_block_size만큼 탐색.
- loop를 한 번 돌때마다 i에 방금 출력한 파일의 record length만큼 더함.
- 마지막 파일의 record length에 남은 block size가 모두 할당되기 때문에 빈 data가 출력되지 않음
- 포인터 x를 출력 중인 파일의 Inode로 이동
- root directory의 Inode 시작점에, 출력 중인 파일의 Inode – 2한 결과에 inode 크기 128bytes를 곱한 값을 더함.
- Block Location은 Inode Struce의 'Block' 항목, 즉 Block number에 one_block_size를 곱한 값