Skip to content

Commit bdc5398

Browse files
committed
Add more minix
1 parent 8f51c98 commit bdc5398

File tree

5 files changed

+254
-27
lines changed

5 files changed

+254
-27
lines changed

software/scripts/minixfs/bitmap.py

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,62 @@
1+
from dataclasses import dataclass
2+
3+
4+
@dataclass
15
class BitMap:
2-
def __init__(self, bits_count: int, need_size: int):
6+
data: list[int]
7+
8+
@classmethod
9+
def create(cls, bits_count: int, need_size: int) -> "BitMap":
310
bits_in_byte = 8
411

512
need_bytes = bits_count // bits_in_byte
6-
data = (b"\x00" * need_bytes)
13+
data = [0x00] * need_bytes
714

815
need_bytes_rem = bits_count % bits_in_byte
916
if need_bytes_rem:
10-
data += (0xFF << need_bytes_rem) & 0xFF
17+
data += [(0xFF << need_bytes_rem) & 0xFF]
1118
need_bytes += 1
1219

13-
if need_bytes > need_size:
14-
raise Exception(f'Need more bytes to create bitmap then size requested')
20+
assert need_bytes <= need_size
1521

1622
add_bytes = need_size - need_bytes
17-
data += (b"\xFF" * add_bytes)
23+
if add_bytes != 0:
24+
data += [0xFF] * add_bytes
1825

1926
assert len(data) == need_size
2027

21-
self.data = data
28+
return cls(data=data)
2229

23-
def get_bytes(self) -> bytes:
30+
def get_data(self) -> list[int]:
2431
return self.data
32+
33+
def get_free_bit(self) -> int | None:
34+
bits_in_byte = 8
35+
36+
assert len(self.data) != 0
37+
38+
for cur_byte_idx, cur_byte in enumerate(self.data):
39+
if cur_byte != 0xFF:
40+
for n_bit in range(0, bits_in_byte):
41+
if (cur_byte & (0x01 << n_bit)) == 0:
42+
return n_bit + (bits_in_byte * cur_byte_idx)
43+
44+
return None
45+
46+
def aquire_bit(self, num: int):
47+
bits_in_byte = 8
48+
byte_pos = num // bits_in_byte
49+
bit_pos = num % bits_in_byte
50+
51+
self.data[byte_pos] |= 0x01 << bit_pos
52+
53+
def release_bit(self, num: int):
54+
bits_in_byte = 8
55+
byte_pos = num // bits_in_byte
56+
bit_pos = num % bits_in_byte
57+
58+
self.data[byte_pos] &= ~(0x01 << bit_pos)
59+
60+
@classmethod
61+
def load(cls, data: list[int]) -> "BitMap":
62+
return cls(data=data)

software/scripts/minixfs/dirent.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import struct
2+
from dataclasses import dataclass
3+
from enum import IntEnum, IntFlag
4+
5+
# B = uint8, H = uint16, L = uint32
6+
D_STRUCT = struct.Struct(
7+
"<" # little-endian
8+
"H" # inode
9+
"30B" # name
10+
)
11+
12+
NAME_SIZE = 30
13+
TOTAL_SIZE = 32
14+
15+
16+
@dataclass
17+
class Dirent:
18+
inode: int
19+
name: list[int]
20+
21+
def pack(self) -> bytes:
22+
assert isinstance(self.name, list)
23+
assert len(self.name) <= NAME_SIZE
24+
25+
raw = D_STRUCT.pack(
26+
self.inode,
27+
*self.name,
28+
)
29+
30+
assert len(raw) == TOTAL_SIZE
31+
32+
return raw
33+
34+
@classmethod
35+
def load(cls, data: list[int]) -> "Dirent":
36+
buf = bytes(data)
37+
assert len(buf) == TOTAL_SIZE
38+
39+
fields = D_STRUCT.unpack_from(buf, 0)
40+
return cls(*fields)

software/scripts/minixfs/inode.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import struct
2+
from dataclasses import dataclass
3+
from enum import IntEnum, IntFlag
4+
5+
6+
class FileType(IntEnum):
7+
S_IFSOCK = 0xC000
8+
S_IFLNK = 0xA000
9+
S_IFREG = 0x8000
10+
S_IFBLK = 0x6000
11+
S_IFDIR = 0x4000
12+
S_IFCHR = 0x2000
13+
S_IFIFO = 0x1000
14+
15+
16+
# B = uint8, H = uint16, L = uint32
17+
I_STRUCT = struct.Struct(
18+
"<" # little-endian
19+
"H" # i_mode
20+
"H" # i_uid
21+
"L" # i_size
22+
"L" # i_time
23+
"B" # i_gid
24+
"B" # i_nlinks
25+
"9H" # i_zone
26+
)
27+
28+
I_ZONE_COUNT: int = 9
29+
TOTAL_SIZE: int = 32
30+
31+
32+
@dataclass
33+
class Inode:
34+
i_mode: int
35+
i_uid: int
36+
i_size: int
37+
i_time: int
38+
i_gid: int
39+
i_nlinks: int
40+
i_zone: list[int]
41+
42+
def pack(self) -> list[int]:
43+
assert isinstance(self.i_zone, list)
44+
assert len(self.i_zone) == I_ZONE_COUNT
45+
46+
raw = I_STRUCT.pack(
47+
self.i_mode,
48+
self.i_uid,
49+
self.i_size,
50+
self.i_time,
51+
self.i_gid,
52+
self.i_nlinks,
53+
*self.i_zone,
54+
)
55+
56+
assert len(raw) == TOTAL_SIZE
57+
58+
return list(raw)
59+
60+
@classmethod
61+
def load(cls, data: list[int]) -> "Inode":
62+
buf = bytes(data)
63+
assert len(buf) == TOTAL_SIZE
64+
65+
fields = I_STRUCT.unpack_from(buf, 0)
66+
return cls(*fields)

software/scripts/minixfs/minixfs.py

Lines changed: 96 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
# Zonesize=1024
77
# Maxsize=268966912
88

9-
from . import superblock, bitmap
9+
from . import superblock, bitmap, inode
10+
11+
from pathlib import Path
1012

1113

1214
class MinixFS:
@@ -22,6 +24,13 @@ def __init__(self, dev: BlockDevice):
2224
self.imap_offset = self.superblock_offset + self.superblock_size
2325
self.inode_size = 32
2426

27+
def store_superblock(self, sb: superblock.SuperBlock):
28+
sb_bytes = list(sb.pack())
29+
30+
superblock_offset_lba = self.superblock_offset // self.phys_block_size
31+
superblock_size_lba = self.superblock_size // self.phys_block_size
32+
self.dev.write(superblock_offset_lba, sb_bytes, superblock_size_lba)
33+
2534
def create_superblock(self):
2635
sb = superblock.SuperBlock(
2736
s_ninodes=352,
@@ -34,13 +43,7 @@ def create_superblock(self):
3443
s_magic=superblock.SB_MAGIC_LONG_FN,
3544
s_state=0,
3645
)
37-
38-
sb_bytes = list(sb.pack())
39-
40-
superblock_offset_lba = self.superblock_offset // self.phys_block_size
41-
superblock_size_lba = self.superblock_size // self.phys_block_size
42-
self.dev.write(superblock_offset_lba, sb_bytes, superblock_size_lba)
43-
46+
self.store_superblock(sb)
4447

4548
def parse_superblock(self):
4649
superblock_offset_lba = self.superblock_offset // self.phys_block_size
@@ -54,25 +57,102 @@ def parse_superblock(self):
5457
self.zmap_size = self.sb.s_zmap_blocks * self.block_size
5558
self.inodes_offset = self.zmap_offset + self.zmap_size
5659

57-
def create_inode_bitmap(self):
58-
bm = bitmap.BitMap(self.sb.s_ninodes, self.sb.s_imap_blocks * self.block_size)
59-
bm_bytes = list(bm.get_bytes())
60+
def store_inode_bitmap(self, bm: bitmap.BitMap):
61+
bm_bytes = bm.get_data()
6062
inode_bitmap_offset_lba = self.imap_offset // self.phys_block_size
61-
inode_bitmap_size_lba = (self.sb.s_imap_blocks * self.block_size) // self.phys_block_size
63+
inode_bitmap_size_lba = (
64+
self.sb.s_imap_blocks * self.block_size
65+
) // self.phys_block_size
6266
self.dev.write(inode_bitmap_offset_lba, bm_bytes, inode_bitmap_size_lba)
6367

64-
def create_znode_bitmap(self):
65-
bm = bitmap.BitMap(self.sb.s_nzones, self.sb.s_zmap_blocks * self.block_size)
66-
bm_bytes = list(bm.get_bytes())
68+
def create_inode_bitmap(self):
69+
bm = bitmap.BitMap.create(
70+
self.sb.s_ninodes, self.sb.s_imap_blocks * self.block_size
71+
)
72+
self.store_inode_bitmap(bm)
73+
74+
def parse_inode_bitmap(self):
75+
inode_bitmap_offset_lba = self.imap_offset // self.phys_block_size
76+
inode_bitmap_size_lba = (
77+
self.sb.s_imap_blocks * self.block_size
78+
) // self.phys_block_size
79+
data = self.dev.read(inode_bitmap_offset_lba, inode_bitmap_size_lba)
80+
81+
self.inode_bitmap = bitmap.BitMap.load(data)
82+
83+
def store_znode_bitmap(self, bm: bitmap.BitMap):
84+
bm_bytes = bm.get_data()
6785
znode_bitmap_offset_lba = self.zmap_offset // self.phys_block_size
68-
znode_bitmap_size_lba = (self.sb.s_zmap_blocks * self.block_size) // self.phys_block_size
86+
znode_bitmap_size_lba = (
87+
self.sb.s_zmap_blocks * self.block_size
88+
) // self.phys_block_size
6989
self.dev.write(znode_bitmap_offset_lba, bm_bytes, znode_bitmap_size_lba)
7090

91+
def create_znode_bitmap(self):
92+
bm = bitmap.BitMap.create(
93+
self.sb.s_nzones, self.sb.s_zmap_blocks * self.block_size
94+
)
95+
self.store_znode_bitmap(bm)
96+
97+
def parse_znode_bitmap(self):
98+
znode_bitmap_offset_lba = self.zmap_offset // self.phys_block_size
99+
znode_bitmap_size_lba = (
100+
self.sb.s_zmap_blocks * self.block_size
101+
) // self.phys_block_size
102+
data = self.dev.read(znode_bitmap_offset_lba, znode_bitmap_size_lba)
103+
104+
self.znode_bitmap = bitmap.BitMap.load(data)
105+
106+
def store_inode(self, i: inode.Inode, pos: int):
107+
# calc block no and LBA addr where inode located
108+
inode_size_lba = 1
109+
inode_offset = self.inodes_offset + (pos * self.inode_size)
110+
inode_offset_lba = inode_offset // self.phys_block_size
111+
inode_offset_rem = inode_offset % self.phys_block_size
112+
113+
# read full disk block
114+
data = self.dev.read(inode_offset_lba, inode_size_lba)
115+
116+
# read, modify, write
117+
i_raw = i.pack()
118+
data[inode_offset_rem : inode_offset_rem + len(i_raw)] = i_raw
119+
120+
# storing byte back
121+
self.dev.write(inode_offset_lba, data, inode_size_lba)
122+
123+
def create_inode(self):
124+
free_inode_num = self.inode_bitmap.get_free_bit()
125+
self.inode_bitmap.aquire_bit(free_inode_num)
126+
self.store_inode_bitmap(self.inode_bitmap)
127+
128+
free_znode_num = self.znode_bitmap.get_free_bit()
129+
self.znode_bitmap.aquire_bit(free_znode_num)
130+
self.store_znode_bitmap(self.znode_bitmap)
131+
132+
i = inode.Inode(
133+
i_mode=int(inode.FileType.S_IFDIR) | 0o755,
134+
i_uid=0,
135+
i_size=64,
136+
i_time=0x699F6471,
137+
i_gid=0,
138+
i_nlinks=2,
139+
i_zone=[free_znode_num] + [0 for i in range(0, 8)],
140+
)
141+
self.store_inode(i, free_inode_num)
142+
143+
def create_directory(self, path: Path):
144+
self.create_inode()
145+
71146
def create(self):
72147
self.create_superblock()
73148
self.parse_superblock()
74149
self.create_inode_bitmap()
150+
self.parse_inode_bitmap()
75151
self.create_znode_bitmap()
152+
self.parse_znode_bitmap()
153+
self.create_directory(Path("."))
154+
# self.create_directory(Path(".."))
155+
# self.create_inode()
76156

77157
def mount(self):
78158
# self.cf.write(0, [0x1, 0x02, 0x03], 3)

software/scripts/minixfs/superblock.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
"H" # s_state
1818
)
1919

20+
TOTAL_SIZE: int = 1024
21+
2022

2123
@dataclass
2224
class SuperBlock:
@@ -30,8 +32,7 @@ class SuperBlock:
3032
s_magic: int
3133
s_state: int
3234

33-
def pack(self) -> bytes:
34-
total_size = 1024
35+
def pack(self) -> list[int]:
3536
raw = SB_STRUCT.pack(
3637
self.s_ninodes,
3738
self.s_nzones,
@@ -43,10 +44,12 @@ def pack(self) -> bytes:
4344
self.s_magic,
4445
self.s_state,
4546
)
46-
return raw + b"\x00" * (total_size - len(raw))
47+
return list(raw) + [0x00] * (TOTAL_SIZE - len(raw))
4748

4849
@classmethod
4950
def load(cls, data: list[int]) -> "SuperBlock":
5051
buf = bytes(data)
52+
assert len(buf) == TOTAL_SIZE
53+
5154
fields = SB_STRUCT.unpack_from(buf, 0)
5255
return cls(*fields)

0 commit comments

Comments
 (0)