@@ -2,6 +2,11 @@ const std = @import("std");
2
2
const dim = @import ("../../dim.zig" );
3
3
const common = @import ("common.zig" );
4
4
5
+ const fatfs = @import ("zfat" );
6
+
7
+ const block_size = 512 ;
8
+ const max_path_len = 8192 ; // this should be enough
9
+
5
10
const FAT = @This ();
6
11
7
12
format_as : FatType ,
@@ -50,13 +55,191 @@ const Appender = struct {
50
55
};
51
56
52
57
fn render (self : * FAT , stream : * dim.BinaryStream ) dim.Content.RenderError ! void {
53
- _ = self ;
54
- _ = stream ;
58
+ var bsd : BinaryStreamDisk = .{ .stream = stream };
59
+
60
+ const min_size , const max_size = self .format_as .get_size_limits ();
61
+
62
+ if (stream .length < min_size ) {
63
+ // TODO(fqu): Report fatal erro!
64
+ std .log .err ("cannot format {} bytes with {s}: min required size is {}" , .{
65
+ @as (dim .DiskSize , @enumFromInt (stream .length )),
66
+ @tagName (self .format_as ),
67
+ @as (dim .DiskSize , @enumFromInt (min_size )),
68
+ });
69
+ return ;
70
+ }
71
+
72
+ if (stream .length > max_size ) {
73
+ // TODO(fqu): Report warning
74
+ std .log .warn ("will not use all available space: available space is {}, but maximum size for {s} is {}" , .{
75
+ @as (dim .DiskSize , @enumFromInt (stream .length )),
76
+ @tagName (self .format_as ),
77
+ @as (dim .DiskSize , @enumFromInt (min_size )),
78
+ });
79
+ }
80
+
81
+ var filesystem : fatfs.FileSystem = undefined ;
82
+
83
+ fatfs .disks [0 ] = & bsd .disk ;
84
+ defer fatfs .disks [0 ] = null ;
85
+
86
+ var workspace : [8192 ]u8 = undefined ;
87
+ fatfs .mkfs ("0:" , .{
88
+ .filesystem = self .format_as .get_zfat_type (),
89
+ .fats = .two ,
90
+ .sector_align = 0 , // default/auto
91
+ .rootdir_size = 512 , // randomly chosen, might need adjustment
92
+ .use_partitions = false ,
93
+ }, & workspace ) catch | err | switch (err ) {
94
+ error .OutOfMemory = > return error .OutOfMemory ,
95
+ error .WriteProtected = > @panic ("bug in zfat" ),
96
+ error .InvalidParameter = > @panic ("bug in zfat disk wrapper" ),
97
+ error .DiskErr = > return error .IoError ,
98
+ error .NotReady = > @panic ("bug in zfat disk wrapper" ),
99
+ error .InvalidDrive = > @panic ("bug in AtomicOps" ),
100
+ error .MkfsAborted = > return error .IoError ,
101
+ };
102
+
103
+ const ops = self .ops .items ;
104
+ if (ops .len > 0 ) {
105
+ filesystem .mount ("0:" , true ) catch | err | switch (err ) {
106
+ error .NotEnabled = > @panic ("bug in zfat" ),
107
+ error .DiskErr = > return error .IoError ,
108
+ error .NotReady = > @panic ("bug in zfat disk wrapper" ),
109
+ error .InvalidDrive = > @panic ("bug in AtomicOps" ),
110
+ error .NoFilesystem = > @panic ("bug in zfat" ),
111
+ };
112
+
113
+ const wrapper = AtomicOps {};
114
+
115
+ for (ops ) | op | {
116
+ try op .execute (wrapper );
117
+ }
118
+ }
55
119
}
56
120
57
121
const FatType = enum {
58
122
fat12 ,
59
123
fat16 ,
60
124
fat32 ,
61
- exfat ,
125
+ // exfat,
126
+
127
+ fn get_zfat_type (fat : FatType ) fatfs.DiskFormat {
128
+ return switch (fat ) {
129
+ .fat12 = > .fat ,
130
+ .fat16 = > .fat ,
131
+ .fat32 = > .fat32 ,
132
+ // .exfat => .exfat,
133
+ };
134
+ }
135
+
136
+ fn get_size_limits (fat : FatType ) struct { u64 , u64 } {
137
+ // see https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system#Size_limits
138
+ return switch (fat ) {
139
+ .fat12 = > .{ 512 , 133_824_512 }, // 512 B ... 127 MB
140
+ .fat16 = > .{ 2_091_520 , 2_147_090_432 }, // 2042.5 kB ... 2047 MB
141
+ .fat32 = > .{ 33_548_800 , 1_099_511_578_624 }, // 32762.5 kB ... 1024 GB
142
+ };
143
+ }
144
+ };
145
+
146
+ const AtomicOps = struct {
147
+ pub fn mkdir (ops : AtomicOps , path : []const u8 ) ! void {
148
+ _ = ops ;
149
+
150
+ var path_buffer : [max_path_len :0 ]u8 = undefined ;
151
+ var fba : std.heap.FixedBufferAllocator = .init (& path_buffer );
152
+
153
+ const joined = try std .mem .concatWithSentinel (fba .allocator (), u8 , &.{ "0:/" , path }, 0 );
154
+ fatfs .mkdir (joined ) catch | err | switch (err ) {
155
+ error .Exist = > {}, // this is good
156
+ else = > | e | return e ,
157
+ };
158
+ }
159
+
160
+ pub fn mkfile (ops : AtomicOps , path : []const u8 , host_file : std.fs.File ) ! void {
161
+ _ = ops ;
162
+
163
+ var path_buffer : [max_path_len :0 ]u8 = undefined ;
164
+ if (path .len > path_buffer .len )
165
+ return error .InvalidPath ;
166
+ @memcpy (path_buffer [0.. path .len ], path );
167
+ path_buffer [path .len ] = 0 ;
168
+
169
+ const path_z = path_buffer [0.. path .len :0 ];
170
+
171
+ const stat = try host_file .stat ();
172
+
173
+ const size = std .math .cast (u32 , stat .size ) orelse return error .FileTooBig ;
174
+
175
+ _ = size ;
176
+
177
+ var fs_file = try fatfs .File .create (path_z );
178
+ defer fs_file .close ();
179
+
180
+ var fifo : std .fifo .LinearFifo (u8 , .{ .Static = 8192 }) = .init ();
181
+ try fifo .pump (
182
+ host_file .reader (),
183
+ fs_file .writer (),
184
+ );
185
+ }
186
+ };
187
+
188
+ const BinaryStreamDisk = struct {
189
+ disk : fatfs.Disk = .{
190
+ .getStatusFn = disk_getStatus ,
191
+ .initializeFn = disk_initialize ,
192
+ .readFn = disk_read ,
193
+ .writeFn = disk_write ,
194
+ .ioctlFn = disk_ioctl ,
195
+ },
196
+ stream : * dim.BinaryStream ,
197
+
198
+ fn disk_getStatus (intf : * fatfs.Disk ) fatfs.Disk.Status {
199
+ _ = intf ;
200
+ return .{
201
+ .initialized = true ,
202
+ .disk_present = true ,
203
+ .write_protected = false ,
204
+ };
205
+ }
206
+
207
+ fn disk_initialize (intf : * fatfs.Disk ) fatfs.Disk.Error ! fatfs.Disk.Status {
208
+ return disk_getStatus (intf );
209
+ }
210
+
211
+ fn disk_read (intf : * fatfs.Disk , buff : [* ]u8 , sector : fatfs.LBA , count : c_uint ) fatfs.Disk.Error ! void {
212
+ const bsd : * BinaryStreamDisk = @fieldParentPtr ("disk" , intf );
213
+
214
+ bsd .stream .read (block_size * sector , buff [0 .. count * block_size ]) catch return error .IoError ;
215
+ }
216
+
217
+ fn disk_write (intf : * fatfs.Disk , buff : [* ]const u8 , sector : fatfs.LBA , count : c_uint ) fatfs.Disk.Error ! void {
218
+ const bsd : * BinaryStreamDisk = @fieldParentPtr ("disk" , intf );
219
+
220
+ bsd .stream .write (block_size * sector , buff [0 .. count * block_size ]) catch return error .IoError ;
221
+ }
222
+
223
+ fn disk_ioctl (intf : * fatfs.Disk , cmd : fatfs.IoCtl , buff : [* ]u8 ) fatfs.Disk.Error ! void {
224
+ const bsd : * BinaryStreamDisk = @fieldParentPtr ("disk" , intf );
225
+
226
+ switch (cmd ) {
227
+ .sync = > {},
228
+
229
+ .get_sector_count = > {
230
+ const size : * fatfs.LBA = @ptrCast (@alignCast (buff ));
231
+ size .* = @intCast (bsd .stream .length / block_size );
232
+ },
233
+ .get_sector_size = > {
234
+ const size : * fatfs.WORD = @ptrCast (@alignCast (buff ));
235
+ size .* = block_size ;
236
+ },
237
+ .get_block_size = > {
238
+ const size : * fatfs.DWORD = @ptrCast (@alignCast (buff ));
239
+ size .* = 1 ;
240
+ },
241
+
242
+ else = > return error .InvalidParameter ,
243
+ }
244
+ }
62
245
};
0 commit comments