Add a quick format option for mkfat32

Added open implementation

Needed to return a pointer to the file system as `@fieldParentPtr(Fat32Self, "instance", fs.instance)` doesn't work as the the pointer to `instance` is on the stack, then goes out of scope when the init is returned. So will be using free stack space.
Part of #216

Spelling, doc comments and extra test for open file


init -> create, deinit -> destroy
This commit is contained in:
DrDeano 2020-12-07 18:29:16 +00:00
parent 48e0779d84
commit d5de173fd3
No known key found for this signature in database
GPG key ID: 96188600582B9ED7
4 changed files with 419 additions and 60 deletions

View file

@ -217,7 +217,7 @@ const Fat32BuilderStep = struct {
// If there was an error, delete the image as this will be invalid // If there was an error, delete the image as this will be invalid
errdefer (std.fs.cwd().deleteFile(self.out_file_path) catch unreachable); errdefer (std.fs.cwd().deleteFile(self.out_file_path) catch unreachable);
defer image.close(); defer image.close();
try Fat32.make(self.options, image); try Fat32.make(self.options, image, false);
} }
/// ///

View file

@ -557,13 +557,16 @@ pub const Fat32 = struct {
/// ///
/// Make a FAT32 image. This will either use the default options or modified defaults from the /// Make a FAT32 image. This will either use the default options or modified defaults from the
/// user. The file will be saved to the path specified. /// user. The file will be saved to the path specified. If quick format is on, then the entire
/// stream is zeroed else the reserved and FAT sectors are zeroed.
/// ///
/// Argument: /// Argument:
/// IN options: Options - The FAT32 options that the user can provide to change the /// IN options: Options - The FAT32 options that the user can provide to change the
/// parameters of a FAT32 image. /// parameters of a FAT32 image.
/// IN stream: anytype - The stream to create a new FAT32 image. This stream must support /// IN stream: anytype - The stream to create a new FAT32 image. This stream must
/// reader(), writer() and seekableStream() interfaces. /// support reader(), writer() and seekableStream() interfaces.
/// IN quick_format: bool - Whether to completely zero the stream initially or zero just
/// the important sectors.
/// ///
/// Error: @TypeOf(stream).WriteError || @TypeOf(stream).SeekError || Error /// Error: @TypeOf(stream).WriteError || @TypeOf(stream).SeekError || Error
/// @TypeOf(stream).WriteError - If there is an error when writing. See the relevant error for the stream. /// @TypeOf(stream).WriteError - If there is an error when writing. See the relevant error for the stream.
@ -572,14 +575,19 @@ pub const Fat32 = struct {
/// Error.TooLarge - The stream size is too small. < 17.5KB. /// Error.TooLarge - The stream size is too small. < 17.5KB.
/// Error.TooSmall - The stream size is to large. > 2TB. /// Error.TooSmall - The stream size is to large. > 2TB.
/// ///
pub fn make(options: Options, stream: anytype) (ErrorSet(@TypeOf(stream)) || Error)!void { pub fn make(options: Options, stream: anytype, quick_format: bool) (ErrorSet(@TypeOf(stream)) || Error)!void {
// First set up the header // First set up the header
const fat32_header = try Fat32.createFATHeader(options); const fat32_header = try Fat32.createFATHeader(options);
// Get the total image size again. As the above has a check for the size, we don't need one here again
const image_size = std.mem.alignBackward(options.image_size, fat32_header.bytes_per_sector);
// Initialise the stream with all zeros // Initialise the stream with all zeros
try stream.seekableStream().seekTo(0);
if (quick_format) {
// Zero just the reserved and FAT sectors
try stream.writer().writeByteNTimes(0x00, (fat32_header.reserved_sectors + (fat32_header.sectors_per_fat * 2)) * fat32_header.bytes_per_sector);
} else {
const image_size = std.mem.alignBackward(options.image_size, fat32_header.bytes_per_sector);
try stream.writer().writeByteNTimes(0x00, image_size); try stream.writer().writeByteNTimes(0x00, image_size);
}
// Write the boot sector with the bootstrap code and header and the backup boot sector. // Write the boot sector with the bootstrap code and header and the backup boot sector.
try Fat32.writeBootSector(stream, fat32_header); try Fat32.writeBootSector(stream, fat32_header);

View file

@ -776,7 +776,7 @@ pub fn Fat32FS(comptime StreamType: type) type {
/// IN self: *ClusterChainIteratorSelf - Iterator self. /// IN self: *ClusterChainIteratorSelf - Iterator self.
/// ///
/// ///
pub fn deinit(self: *ClusterChainIteratorSelf) void { pub fn deinit(self: *const ClusterChainIteratorSelf) void {
self.allocator.free(self.fat); self.allocator.free(self.fat);
} }
@ -1184,6 +1184,27 @@ pub fn Fat32FS(comptime StreamType: type) type {
return node; return node;
} }
///
/// A helper function for getting the cluster from an opened directory node.
///
/// Arguments:
/// IN self: *const Fat32Self - Self, used to get the opened nodes.
/// IN dir: *const vfs.DirNode - The directory node to get the cluster for.
///
/// Return: u32
/// The cluster number for the directory node.
///
/// Error: vfs.Error
/// error.NotOpened - If directory node isn't opened.
///
fn getDirCluster(self: *Fat32Self, dir: *const vfs.DirNode) vfs.Error!u32 {
return if (std.meta.eql(dir, self.fs.getRootNode(self.fs))) self.root_node.cluster else brk: {
const parent = self.opened_files.get(@ptrCast(*const vfs.Node, dir)) orelse return vfs.Error.NotOpened;
// Cluster 0 means is the root directory cluster
break :brk if (parent.cluster == 0) self.fat_config.root_directory_cluster else parent.cluster;
};
}
/// ///
/// The helper function for opening a file/folder, no creation. /// The helper function for opening a file/folder, no creation.
/// ///
@ -1195,16 +1216,56 @@ pub fn Fat32FS(comptime StreamType: type) type {
/// Return: *vfs.Node /// Return: *vfs.Node
/// The VFS Node for the opened file/folder. /// The VFS Node for the opened file/folder.
/// ///
/// Error: Allocator.Error || ReadError || SeekError || vfs.Error /// Error: Allocator.Error || vfs.Error
/// Allocator.Error - Not enough memory for allocating memory /// Allocator.Error - Not enough memory for allocating memory
/// ReadError - Errors when reading the stream.
/// SeekError - Errors when seeking the stream.
/// vfs.Error.NoSuchFileOrDir - Error if the file/folder doesn't exist. /// vfs.Error.NoSuchFileOrDir - Error if the file/folder doesn't exist.
/// vfs.Error.Unexpected - An error occurred whilst reading the file system, this
/// can be caused by a parsing error or errors on reading
/// or seeking the underlying stream. If this occurs, then
/// the real error is printed using `log.err`.
/// ///
fn openImpl(fs: *const vfs.FileSystem, dir: *const vfs.DirNode, name: []const u8) (Allocator.Error || ReadError || SeekError || vfs.Error)!*vfs.Node { fn openImpl(fs: *const vfs.FileSystem, dir: *const vfs.DirNode, name: []const u8) (Allocator.Error || vfs.Error)!*vfs.Node {
const self = @fieldParentPtr(Fat32Self, "instance", fs.instance); const self = @fieldParentPtr(Fat32Self, "instance", fs.instance);
// TODO: Cache the files in this dir, so when opening, don't have to iterator the directory every time
// TODO: Future PR // Iterate over the directory and find the file/folder
const cluster = try self.getDirCluster(dir);
var it = EntryIterator.init(self.allocator, self.fat_config, cluster, self.stream) catch |e| switch (e) {
error.OutOfMemory => return error.OutOfMemory,
else => {
log.err("Error initialising the entry iterator. Error: {}\n", .{e});
return vfs.Error.Unexpected;
},
};
defer it.deinit();
while (it.next() catch |e| switch (e) {
error.OutOfMemory => return vfs.Error.IsAFile,
else => {
log.err("Error initialising the entry iterator. Error: {}\n", .{e});
return vfs.Error.Unexpected;
},
}) |entry| {
defer entry.deinit();
// File name compare is case insensitive
var match: bool = brk: {
if (entry.long_name) |long_name| {
if (std.ascii.eqlIgnoreCase(name, long_name)) {
break :brk true;
}
}
var short_buff: [33]u8 = undefined;
const s_end = entry.short_name.getName(short_buff[0..]);
if (std.ascii.eqlIgnoreCase(name, short_buff[0..s_end])) {
break :brk true;
}
break :brk false;
};
if (match) {
const open_type = if (entry.short_name.isDir()) vfs.OpenFlags.CREATE_DIR else vfs.OpenFlags.CREATE_FILE;
return self.createNode(entry.short_name.getCluster(), entry.short_name.size, open_type, .{});
}
}
return vfs.Error.NoSuchFileOrDir; return vfs.Error.NoSuchFileOrDir;
} }
@ -1235,18 +1296,20 @@ pub fn Fat32FS(comptime StreamType: type) type {
} }
/// ///
/// Deinitialise this file system. /// Deinitialise this file system. This frees the root node, virtual filesystem and self.
/// This asserts that there are no open files left.
/// ///
/// Arguments: /// Arguments:
/// IN self: *Fat32Self - Self to free. /// IN self: *Fat32Self - Self to free.
/// ///
pub fn deinit(self: *Fat32Self) void { pub fn destroy(self: *Fat32Self) void {
// Make sure we have closed all files // Make sure we have closed all files
// TODO: Should this deinit close any open files instead? // TODO: Should this deinit close any open files instead?
std.debug.assert(self.opened_files.count() == 0); std.debug.assert(self.opened_files.count() == 0);
self.opened_files.deinit(); self.opened_files.deinit();
self.allocator.destroy(self.root_node.node); self.allocator.destroy(self.root_node.node);
self.allocator.destroy(self.fs); self.allocator.destroy(self.fs);
self.allocator.destroy(self);
} }
/// ///
@ -1254,19 +1317,19 @@ pub fn Fat32FS(comptime StreamType: type) type {
/// ///
/// Arguments: /// Arguments:
/// IN allocator: *Allocator - Allocate memory. /// IN allocator: *Allocator - Allocate memory.
/// IN stream: StreamType - Allocate memory. /// IN stream: StreamType - The underlying stream that the filesystem will sit on.
/// ///
/// Return: *Fat32 /// Return: *Fat32
/// The pointer to a Fat32 filesystem. /// The pointer to a FAT32 filesystem.
/// ///
/// Error: Allocator.Error || ReadError || SeekError || Error /// Error: Allocator.Error || ReadError || SeekError || Fat32Self.Error
/// Allocator.Error - If there is no more memory. Any memory allocated will be freed. /// Allocator.Error - If there is no more memory. Any memory allocated will be freed.
/// ReadError - If there is an error reading from the stream. /// ReadError - If there is an error reading from the stream.
/// SeekError - If there si an error seeking the stream. /// SeekError - If there si an error seeking the stream.
/// Error - If there is an error when parsing the stream to set up a fAT32 /// Fat32Self.Error - If there is an error when parsing the stream to set up a fAT32
/// filesystem. See Error for the list of possible errors. /// filesystem. See Error for the list of possible errors.
/// ///
pub fn init(allocator: *Allocator, stream: StreamType) (Allocator.Error || ReadError || SeekError || Error)!Fat32Self { pub fn create(allocator: *Allocator, stream: StreamType) (Allocator.Error || ReadError || SeekError || Fat32Self.Error)!*Fat32Self {
log.debug("Init\n", .{}); log.debug("Init\n", .{});
defer log.debug("Done\n", .{}); defer log.debug("Done\n", .{});
// We need to get the root directory sector. For this we need to read the boot sector. // We need to get the root directory sector. For this we need to read the boot sector.
@ -1369,6 +1432,8 @@ pub fn Fat32FS(comptime StreamType: type) type {
errdefer allocator.destroy(fs); errdefer allocator.destroy(fs);
const root_node = try allocator.create(vfs.Node); const root_node = try allocator.create(vfs.Node);
errdefer allocator.destroy(root_node); errdefer allocator.destroy(root_node);
const fat32_fs = try allocator.create(Fat32Self);
errdefer allocator.destroy(fat32_fs);
// Record the relevant information // Record the relevant information
const fat_config = FATConfig{ const fat_config = FATConfig{
@ -1387,7 +1452,7 @@ pub fn Fat32FS(comptime StreamType: type) type {
.cluster_end_marker = cluster_end_marker, .cluster_end_marker = cluster_end_marker,
}; };
var fat32_fs = Fat32Self{ fat32_fs.* = .{
.fs = fs, .fs = fs,
.allocator = allocator, .allocator = allocator,
.instance = 32, .instance = 32,
@ -1420,10 +1485,11 @@ pub fn Fat32FS(comptime StreamType: type) type {
} }
}; };
} }
/// ///
/// Initialise a FAT32 filesystem. This will take a stream that conforms to the reader(), writer(), /// Initialise a FAT32 filesystem. This will take a stream that conforms to the reader(), writer(),
/// and seekableStream() interfaces. For example, FixedBufferStream or File. A pointer to this is /// and seekableStream() interfaces. For example, FixedBufferStream or File. A pointer to this is
//// allowed. This will allow the use of different devices such as Hard drives or RAM disks to have /// allowed. This will allow the use of different devices such as Hard drives or RAM disks to have
/// a FAT32 filesystem abstraction. We assume the FAT32 will be the only filesystem present and no /// a FAT32 filesystem abstraction. We assume the FAT32 will be the only filesystem present and no
/// partition schemes are present. So will expect a valid boot sector. /// partition schemes are present. So will expect a valid boot sector.
/// ///
@ -1438,15 +1504,12 @@ pub fn Fat32FS(comptime StreamType: type) type {
/// Error: Allocator.Error || Fat32FS(@TypeOf(stream)).Error /// Error: Allocator.Error || Fat32FS(@TypeOf(stream)).Error
/// Allocator.Error - If there isn't enough memory to create the filesystem. /// Allocator.Error - If there isn't enough memory to create the filesystem.
/// ///
pub fn initialiseFAT32(allocator: *Allocator, stream: anytype) (Allocator.Error || ErrorSet(@TypeOf(stream)) || Fat32FS(@TypeOf(stream)).Error)!Fat32FS(@TypeOf(stream)) { pub fn initialiseFAT32(allocator: *Allocator, stream: anytype) (Allocator.Error || ErrorSet(@TypeOf(stream)) || Fat32FS(@TypeOf(stream)).Error)!*Fat32FS(@TypeOf(stream)) {
return Fat32FS(@TypeOf(stream)).init(allocator, stream); return Fat32FS(@TypeOf(stream)).create(allocator, stream);
} }
/// The number of allocations that the init function make.
const test_init_allocations: usize = 4;
/// The test buffer for the test filesystem stream. /// The test buffer for the test filesystem stream.
var test_stream_buff: [if (builtin.is_test) 34090496 else 0]u8 = undefined; var test_stream_buff = [_]u8{0} ** if (builtin.is_test) 34090496 else 0;
/// ///
/// Read the test files and write them to the test FAT32 filesystem. /// Read the test files and write them to the test FAT32 filesystem.
@ -1462,7 +1525,7 @@ var test_stream_buff: [if (builtin.is_test) 34090496 else 0]u8 = undefined;
/// std.fs.File.OpenError - Error when opening the test files. /// std.fs.File.OpenError - Error when opening the test files.
/// std.fs.File.ReadError - Error when reading the test files. /// std.fs.File.ReadError - Error when reading the test files.
/// ///
fn testWriteTestFiles(comptime StreamType: type, fat32fs: Fat32FS(StreamType)) (Allocator.Error || ErrorSet(StreamType) || vfs.Error || std.fs.File.OpenError || std.fs.File.ReadError)!void { fn testWriteTestFiles(comptime StreamType: type, fat32fs: *Fat32FS(StreamType)) (Allocator.Error || ErrorSet(StreamType) || vfs.Error || std.fs.File.OpenError || std.fs.File.ReadError)!void {
vfs.setRoot(fat32fs.root_node.node); vfs.setRoot(fat32fs.root_node.node);
const test_path_prefix = "test/fat32"; const test_path_prefix = "test/fat32";
@ -1871,10 +1934,10 @@ test "ShortName.calcCheckSum" {
test "Fat32FS initialise test files" { test "Fat32FS initialise test files" {
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]); var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream); try mkfat32.Fat32.make(.{}, stream, true);
var test_fs = try initialiseFAT32(std.testing.allocator, stream); var test_fs = try initialiseFAT32(std.testing.allocator, stream);
defer test_fs.deinit(); defer test_fs.destroy();
// Write the test files // Write the test files
try testWriteTestFiles(@TypeOf(stream), test_fs); try testWriteTestFiles(@TypeOf(stream), test_fs);
@ -1892,10 +1955,10 @@ test "Fat32FS initialise test files" {
test "Fat32FS.getRootNode" { test "Fat32FS.getRootNode" {
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]); var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream); try mkfat32.Fat32.make(.{}, stream, true);
var test_fs = try initialiseFAT32(std.testing.allocator, stream); var test_fs = try initialiseFAT32(std.testing.allocator, stream);
defer test_fs.deinit(); defer test_fs.destroy();
expectEqual(test_fs.fs.getRootNode(test_fs.fs), &test_fs.root_node.node.Dir); expectEqual(test_fs.fs.getRootNode(test_fs.fs), &test_fs.root_node.node.Dir);
expectEqual(test_fs.root_node.cluster, 2); expectEqual(test_fs.root_node.cluster, 2);
@ -1905,10 +1968,10 @@ test "Fat32FS.getRootNode" {
test "Fat32FS.read" { test "Fat32FS.read" {
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]); var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream); try mkfat32.Fat32.make(.{}, stream, true);
var test_fs = try initialiseFAT32(std.testing.allocator, stream); var test_fs = try initialiseFAT32(std.testing.allocator, stream);
defer test_fs.deinit(); defer test_fs.destroy();
// TODO: Once the read PR is done // TODO: Once the read PR is done
} }
@ -1916,10 +1979,10 @@ test "Fat32FS.read" {
test "Fat32FS.write" { test "Fat32FS.write" {
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]); var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream); try mkfat32.Fat32.make(.{}, stream, true);
var test_fs = try initialiseFAT32(std.testing.allocator, stream); var test_fs = try initialiseFAT32(std.testing.allocator, stream);
defer test_fs.deinit(); defer test_fs.destroy();
// TODO: Once the write PR is done // TODO: Once the write PR is done
} }
@ -1927,21 +1990,60 @@ test "Fat32FS.write" {
test "Fat32FS.open - no create" { test "Fat32FS.open - no create" {
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]); var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream); try mkfat32.Fat32.make(.{}, stream, true);
var test_fs = try initialiseFAT32(std.testing.allocator, stream); var test_fs = try initialiseFAT32(std.testing.allocator, stream);
defer test_fs.deinit(); defer test_fs.destroy();
// TODO: Once the open PR is done // Temporary add hand built files to open
// Once write PR is done, then can test real files
var entry_buff = [_]u8{
// Long entry 3
0x43, 0x6E, 0x00, 0x67, 0x00, 0x6E, 0x00, 0x61, 0x00, 0x6D, 0x00, 0x0F, 0x00, 0x6E, 0x65, 0x00,
0x2E, 0x00, 0x74, 0x00, 0x78, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
// Long entry 2
0x02, 0x6E, 0x00, 0x67, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x0F, 0x00, 0x6E, 0x79, 0x00,
0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x6F, 0x00,
// Long entry 1
0x01, 0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x0F, 0x00, 0x6E, 0x6F, 0x00,
0x6E, 0x00, 0x67, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x6F, 0x00,
// Short entry
0x4C, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x7E, 0x31, 0x54, 0x58, 0x54, 0x00, 0x18, 0xA0, 0x68, 0xA9,
0xFE, 0x50, 0x00, 0x00, 0x00, 0x00, 0x6E, 0xA9, 0xFE, 0x50, 0x08, 0x00, 0x13, 0x00, 0x00, 0x00,
// Long entry 2
0x42, 0x2E, 0x00, 0x74, 0x00, 0x78, 0x00, 0x74, 0x00, 0x00, 0x00, 0x0F, 0x00, 0xE9, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
// Long entry 1
0x01, 0x72, 0x00, 0x61, 0x00, 0x6D, 0x00, 0x64, 0x00, 0x69, 0x00, 0x0F, 0x00, 0xE9, 0x73, 0x00,
0x6B, 0x00, 0x5F, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x00, 0x00, 0x74, 0x00, 0x31, 0x00,
// Short entry
0x52, 0x41, 0x4D, 0x44, 0x49, 0x53, 0x7E, 0x31, 0x54, 0x58, 0x54, 0x00, 0x18, 0x34, 0x47, 0x76,
0xF9, 0x50, 0x00, 0x00, 0x00, 0x00, 0x48, 0x76, 0xF9, 0x50, 0x03, 0x00, 0x10, 0x00, 0x00, 0x00,
};
// Goto root dir and write a long and short entry
const sector = test_fs.fat_config.clusterToSector(test_fs.root_node.cluster);
try test_fs.stream.seekableStream().seekTo(sector * test_fs.fat_config.bytes_per_sector);
try test_fs.stream.writer().writeAll(entry_buff[0..]);
vfs.setRoot(test_fs.root_node.node);
const file = try vfs.openFile("/ramdisk_test1.txt", .NO_CREATION);
defer file.close();
expect(test_fs.opened_files.contains(@ptrCast(*const vfs.Node, file)));
const opened_info = test_fs.opened_files.get(@ptrCast(*const vfs.Node, file)).?;
expectEqual(opened_info.cluster, 3);
expectEqual(opened_info.size, 16);
} }
test "Fat32FS.open - create file" { test "Fat32FS.open - create file" {
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]); var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream); try mkfat32.Fat32.make(.{}, stream, true);
var test_fs = try initialiseFAT32(std.testing.allocator, stream); var test_fs = try initialiseFAT32(std.testing.allocator, stream);
defer test_fs.deinit(); defer test_fs.destroy();
// TODO: Once the open and write PR is done // TODO: Once the open and write PR is done
} }
@ -1949,10 +2051,10 @@ test "Fat32FS.open - create file" {
test "Fat32FS.open - create directory" { test "Fat32FS.open - create directory" {
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]); var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream); try mkfat32.Fat32.make(.{}, stream, true);
var test_fs = try initialiseFAT32(std.testing.allocator, stream); var test_fs = try initialiseFAT32(std.testing.allocator, stream);
defer test_fs.deinit(); defer test_fs.destroy();
// TODO: Once the open and write PR is done // TODO: Once the open and write PR is done
} }
@ -1960,10 +2062,10 @@ test "Fat32FS.open - create directory" {
test "Fat32FS.open - create symlink" { test "Fat32FS.open - create symlink" {
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]); var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream); try mkfat32.Fat32.make(.{}, stream, true);
var test_fs = try initialiseFAT32(std.testing.allocator, stream); var test_fs = try initialiseFAT32(std.testing.allocator, stream);
defer test_fs.deinit(); defer test_fs.destroy();
// TODO: Once the open and write PR is done // TODO: Once the open and write PR is done
} }
@ -1971,16 +2073,16 @@ test "Fat32FS.open - create symlink" {
test "Fat32FS.init no error" { test "Fat32FS.init no error" {
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]); var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream); try mkfat32.Fat32.make(.{}, stream, true);
var test_fs = try initialiseFAT32(std.testing.allocator, stream); var test_fs = try initialiseFAT32(std.testing.allocator, stream);
defer test_fs.deinit(); defer test_fs.destroy();
} }
test "Fat32FS.init errors" { test "Fat32FS.init errors" {
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]); var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream); try mkfat32.Fat32.make(.{}, stream, true);
// BadMBRMagic // BadMBRMagic
test_stream_buff[510] = 0x00; test_stream_buff[510] = 0x00;
@ -2062,10 +2164,11 @@ test "Fat32FS.init errors" {
test "Fat32FS.init memory" { test "Fat32FS.init memory" {
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]); var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream); try mkfat32.Fat32.make(.{}, stream, true);
const allocations: usize = 5;
var i: usize = 0; var i: usize = 0;
while (i < test_init_allocations) : (i += 1) { while (i < allocations) : (i += 1) {
var fa = std.testing.FailingAllocator.init(std.testing.allocator, i); var fa = std.testing.FailingAllocator.init(std.testing.allocator, i);
expectError(error.OutOfMemory, initialiseFAT32(&fa.allocator, stream)); expectError(error.OutOfMemory, initialiseFAT32(&fa.allocator, stream));
@ -2075,10 +2178,10 @@ test "Fat32FS.init memory" {
test "Fat32FS.init FATConfig expected" { test "Fat32FS.init FATConfig expected" {
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]); var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream); try mkfat32.Fat32.make(.{}, stream, true);
var test_fs = try initialiseFAT32(std.testing.allocator, stream); var test_fs = try initialiseFAT32(std.testing.allocator, stream);
defer test_fs.deinit(); defer test_fs.destroy();
// This is the default config that should be produced from mkfat32.Fat32 // This is the default config that should be produced from mkfat32.Fat32
const expected = FATConfig{ const expected = FATConfig{
@ -2103,7 +2206,7 @@ test "Fat32FS.init FATConfig expected" {
test "Fat32FS.init FATConfig mix FSInfo" { test "Fat32FS.init FATConfig mix FSInfo" {
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]); var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream); try mkfat32.Fat32.make(.{}, stream, true);
// No FSInfo // No FSInfo
{ {
@ -2111,7 +2214,7 @@ test "Fat32FS.init FATConfig mix FSInfo" {
test_stream_buff[48] = 0x00; test_stream_buff[48] = 0x00;
var test_fs = try initialiseFAT32(std.testing.allocator, stream); var test_fs = try initialiseFAT32(std.testing.allocator, stream);
defer test_fs.deinit(); defer test_fs.destroy();
// This is the default config that should be produced from mkfat32.Fat32 // This is the default config that should be produced from mkfat32.Fat32
const expected = FATConfig{ const expected = FATConfig{
@ -2140,7 +2243,7 @@ test "Fat32FS.init FATConfig mix FSInfo" {
test_stream_buff[512] = 0xAA; test_stream_buff[512] = 0xAA;
var test_fs = try initialiseFAT32(std.testing.allocator, stream); var test_fs = try initialiseFAT32(std.testing.allocator, stream);
defer test_fs.deinit(); defer test_fs.destroy();
// This is the default config that should be produced from mkfat32.Fat32 // This is the default config that should be produced from mkfat32.Fat32
const expected = FATConfig{ const expected = FATConfig{
@ -2172,7 +2275,7 @@ test "Fat32FS.init FATConfig mix FSInfo" {
test_stream_buff[512 + 4 + 480 + 7] = 0xDD; test_stream_buff[512 + 4 + 480 + 7] = 0xDD;
var test_fs = try initialiseFAT32(std.testing.allocator, stream); var test_fs = try initialiseFAT32(std.testing.allocator, stream);
defer test_fs.deinit(); defer test_fs.destroy();
// This is the default config that should be produced from mkfat32.Fat32 // This is the default config that should be produced from mkfat32.Fat32
const expected = FATConfig{ const expected = FATConfig{
@ -3573,3 +3676,248 @@ test "EntryIterator.init - free on BadRead" {
var stream = &std.io.fixedBufferStream(buff_stream[0..]); var stream = &std.io.fixedBufferStream(buff_stream[0..]);
expectError(error.BadRead, Fat32FS(@TypeOf(stream)).EntryIterator.init(std.testing.allocator, fat_config, 2, stream)); expectError(error.BadRead, Fat32FS(@TypeOf(stream)).EntryIterator.init(std.testing.allocator, fat_config, 2, stream));
} }
test "Fat32FS.getDirCluster - root dir" {
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream, true);
var test_fs = try initialiseFAT32(std.testing.allocator, stream);
defer test_fs.destroy();
var test_node_1 = try test_fs.createNode(3, 16, .CREATE_FILE, .{});
defer test_node_1.File.close();
const actual = try test_fs.getDirCluster(&test_fs.root_node.node.Dir);
expectEqual(actual, 2);
}
test "Fat32FS.getDirCluster - sub dir" {
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream, true);
var test_fs = try initialiseFAT32(std.testing.allocator, stream);
defer test_fs.destroy();
var test_node_1 = try test_fs.createNode(5, 0, .CREATE_DIR, .{});
defer {
const elem = test_fs.opened_files.remove(test_node_1).?.value;
std.testing.allocator.destroy(elem);
std.testing.allocator.destroy(test_node_1);
}
const actual = try test_fs.getDirCluster(&test_node_1.Dir);
expectEqual(actual, 5);
}
test "Fat32FS.getDirCluster - not opened dir" {
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream, true);
var test_fs = try initialiseFAT32(std.testing.allocator, stream);
defer test_fs.destroy();
var test_node_1 = try test_fs.createNode(5, 0, .CREATE_DIR, .{});
const elem = test_fs.opened_files.remove(test_node_1).?.value;
std.testing.allocator.destroy(elem);
expectError(error.NotOpened, test_fs.getDirCluster(&test_node_1.Dir));
std.testing.allocator.destroy(test_node_1);
}
test "Fat32FS.openImpl - entry iterator failed init" {
// Will need to fail the 8th allocation
const allocations: usize = 8;
var fa = std.testing.FailingAllocator.init(std.testing.allocator, allocations);
const allocator = &fa.allocator;
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream, true);
var test_fs = try initialiseFAT32(allocator, stream);
defer test_fs.destroy();
var test_node_1 = try test_fs.createNode(5, 0, .CREATE_DIR, .{});
defer {
const elem = test_fs.opened_files.remove(test_node_1).?.value;
allocator.destroy(elem);
allocator.destroy(test_node_1);
}
expectError(error.OutOfMemory, Fat32FS(@TypeOf(stream)).openImpl(test_fs.fs, &test_node_1.Dir, "file.txt"));
}
test "Fat32FS.openImpl - entry iterator failed next" {
// Will need to fail the 10th allocation
const allocations: usize = 10;
var fa = std.testing.FailingAllocator.init(std.testing.allocator, allocations);
const allocator = &fa.allocator;
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream, true);
var test_fs = try initialiseFAT32(allocator, stream);
defer test_fs.destroy();
var entry_buff = [_]u8{
// Long entry 3
0x43, 0x6E, 0x00, 0x67, 0x00, 0x6E, 0x00, 0x61, 0x00, 0x6D, 0x00, 0x0F, 0x00, 0x6E, 0x65, 0x00,
0x2E, 0x00, 0x74, 0x00, 0x78, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
// Long entry 2
0x02, 0x6E, 0x00, 0x67, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x0F, 0x00, 0x6E, 0x79, 0x00,
0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x6F, 0x00,
// Long entry 1
0x01, 0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x0F, 0x00, 0x6E, 0x6F, 0x00,
0x6E, 0x00, 0x67, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x6F, 0x00,
// Short entry
0x4C, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x7E, 0x31, 0x54, 0x58, 0x54, 0x00, 0x18, 0xA0, 0x68, 0xA9,
0xFE, 0x50, 0x00, 0x00, 0x00, 0x00, 0x6E, 0xA9, 0xFE, 0x50, 0x08, 0x00, 0x13, 0x00, 0x00, 0x00,
// Long entry 2
0x42, 0x2E, 0x00, 0x74, 0x00, 0x78, 0x00, 0x74, 0x00, 0x00, 0x00, 0x0F, 0x00, 0xE9, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
// Long entry 1
0x01, 0x72, 0x00, 0x61, 0x00, 0x6D, 0x00, 0x64, 0x00, 0x69, 0x00, 0x0F, 0x00, 0xE9, 0x73, 0x00,
0x6B, 0x00, 0x5F, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x00, 0x00, 0x74, 0x00, 0x31, 0x00,
// Short entry
0x52, 0x41, 0x4D, 0x44, 0x49, 0x53, 0x7E, 0x31, 0x54, 0x58, 0x54, 0x00, 0x18, 0x34, 0x47, 0x76,
0xF9, 0x50, 0x00, 0x00, 0x00, 0x00, 0x48, 0x76, 0xF9, 0x50, 0x03, 0x00, 0x10, 0x00, 0x00, 0x00,
};
// Goto root dir and write a long and short entry
const sector = test_fs.fat_config.clusterToSector(test_fs.root_node.cluster);
try test_fs.stream.seekableStream().seekTo(sector * test_fs.fat_config.bytes_per_sector);
try test_fs.stream.writer().writeAll(entry_buff[0..]);
expectError(error.OutOfMemory, Fat32FS(@TypeOf(stream)).openImpl(test_fs.fs, &test_fs.root_node.node.Dir, "looooongloooongveryloooooongname.txt"));
}
test "Fat32FS.openImpl - entry iterator failed 2nd next" {
// Will need to fail the 11th allocation
const allocations: usize = 11;
var fa = std.testing.FailingAllocator.init(std.testing.allocator, allocations);
const allocator = &fa.allocator;
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream, true);
var test_fs = try initialiseFAT32(allocator, stream);
defer test_fs.destroy();
var entry_buff = [_]u8{
// Long entry 3
0x43, 0x6E, 0x00, 0x67, 0x00, 0x6E, 0x00, 0x61, 0x00, 0x6D, 0x00, 0x0F, 0x00, 0x6E, 0x65, 0x00,
0x2E, 0x00, 0x74, 0x00, 0x78, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
// Long entry 2
0x02, 0x6E, 0x00, 0x67, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x0F, 0x00, 0x6E, 0x79, 0x00,
0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x6F, 0x00,
// Long entry 1
0x01, 0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x0F, 0x00, 0x6E, 0x6F, 0x00,
0x6E, 0x00, 0x67, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x6F, 0x00,
// Short entry
0x4C, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x7E, 0x31, 0x54, 0x58, 0x54, 0x00, 0x18, 0xA0, 0x68, 0xA9,
0xFE, 0x50, 0x00, 0x00, 0x00, 0x00, 0x6E, 0xA9, 0xFE, 0x50, 0x08, 0x00, 0x13, 0x00, 0x00, 0x00,
// Long entry 2
0x42, 0x2E, 0x00, 0x74, 0x00, 0x78, 0x00, 0x74, 0x00, 0x00, 0x00, 0x0F, 0x00, 0xE9, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
// Long entry 1
0x01, 0x72, 0x00, 0x61, 0x00, 0x6D, 0x00, 0x64, 0x00, 0x69, 0x00, 0x0F, 0x00, 0xE9, 0x73, 0x00,
0x6B, 0x00, 0x5F, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x00, 0x00, 0x74, 0x00, 0x31, 0x00,
// Short entry
0x52, 0x41, 0x4D, 0x44, 0x49, 0x53, 0x7E, 0x31, 0x54, 0x58, 0x54, 0x00, 0x18, 0x34, 0x47, 0x76,
0xF9, 0x50, 0x00, 0x00, 0x00, 0x00, 0x48, 0x76, 0xF9, 0x50, 0x03, 0x00, 0x10, 0x00, 0x00, 0x00,
};
// Goto root dir and write a long and short entry
const sector = test_fs.fat_config.clusterToSector(test_fs.root_node.cluster);
try test_fs.stream.seekableStream().seekTo(sector * test_fs.fat_config.bytes_per_sector);
try test_fs.stream.writer().writeAll(entry_buff[0..]);
expectError(error.OutOfMemory, Fat32FS(@TypeOf(stream)).openImpl(test_fs.fs, &test_fs.root_node.node.Dir, "ramdisk_test1.txt"));
}
test "Fat32FS.openImpl - match short name" {
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream, true);
var test_fs = try initialiseFAT32(std.testing.allocator, stream);
defer test_fs.destroy();
var entry_buff = [_]u8{
// Long entry 3
0x43, 0x6E, 0x00, 0x67, 0x00, 0x6E, 0x00, 0x61, 0x00, 0x6D, 0x00, 0x0F, 0x00, 0x6E, 0x65, 0x00,
0x2E, 0x00, 0x74, 0x00, 0x78, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
// Long entry 2
0x02, 0x6E, 0x00, 0x67, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x0F, 0x00, 0x6E, 0x79, 0x00,
0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x6F, 0x00,
// Long entry 1
0x01, 0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x0F, 0x00, 0x6E, 0x6F, 0x00,
0x6E, 0x00, 0x67, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x6F, 0x00,
// Short entry
0x4C, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x7E, 0x31, 0x54, 0x58, 0x54, 0x00, 0x18, 0xA0, 0x68, 0xA9,
0xFE, 0x50, 0x00, 0x00, 0x00, 0x00, 0x6E, 0xA9, 0xFE, 0x50, 0x08, 0x00, 0x13, 0x00, 0x00, 0x00,
};
// Goto root dir and write a long and short entry
const sector = test_fs.fat_config.clusterToSector(test_fs.root_node.cluster);
try test_fs.stream.seekableStream().seekTo(sector * test_fs.fat_config.bytes_per_sector);
try test_fs.stream.writer().writeAll(entry_buff[0..]);
const file_node = try Fat32FS(@TypeOf(stream)).openImpl(test_fs.fs, &test_fs.root_node.node.Dir, "LOOOOO~1.TXT");
defer file_node.File.close();
}
test "Fat32FS.openImpl - match long name" {
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream, true);
var test_fs = try initialiseFAT32(std.testing.allocator, stream);
defer test_fs.destroy();
var entry_buff = [_]u8{
// Long entry 3
0x43, 0x6E, 0x00, 0x67, 0x00, 0x6E, 0x00, 0x61, 0x00, 0x6D, 0x00, 0x0F, 0x00, 0x6E, 0x65, 0x00,
0x2E, 0x00, 0x74, 0x00, 0x78, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
// Long entry 2
0x02, 0x6E, 0x00, 0x67, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x0F, 0x00, 0x6E, 0x79, 0x00,
0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x6F, 0x00,
// Long entry 1
0x01, 0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x0F, 0x00, 0x6E, 0x6F, 0x00,
0x6E, 0x00, 0x67, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x6F, 0x00,
// Short entry
0x4C, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x7E, 0x31, 0x54, 0x58, 0x54, 0x00, 0x18, 0xA0, 0x68, 0xA9,
0xFE, 0x50, 0x00, 0x00, 0x00, 0x00, 0x6E, 0xA9, 0xFE, 0x50, 0x08, 0x00, 0x13, 0x00, 0x00, 0x00,
};
// Goto root dir and write a long and short entry
const sector = test_fs.fat_config.clusterToSector(test_fs.root_node.cluster);
try test_fs.stream.seekableStream().seekTo(sector * test_fs.fat_config.bytes_per_sector);
try test_fs.stream.writer().writeAll(entry_buff[0..]);
const file_node = try Fat32FS(@TypeOf(stream)).openImpl(test_fs.fs, &test_fs.root_node.node.Dir, "looooongloooongveryloooooongname.txt");
defer file_node.File.close();
}
test "Fat32FS.openImpl - no match" {
var stream = &std.io.fixedBufferStream(test_stream_buff[0..]);
try mkfat32.Fat32.make(.{}, stream, true);
var test_fs = try initialiseFAT32(std.testing.allocator, stream);
defer test_fs.destroy();
var test_node_1 = try test_fs.createNode(5, 0, .CREATE_DIR, .{});
defer {
const elem = test_fs.opened_files.remove(test_node_1).?.value;
std.testing.allocator.destroy(elem);
std.testing.allocator.destroy(test_node_1);
}
expectError(vfs.Error.NoSuchFileOrDir, Fat32FS(@TypeOf(stream)).openImpl(test_fs.fs, &test_node_1.Dir, "file.txt"));
}

View file

@ -245,6 +245,9 @@ pub const Error = error{
/// No symlink target was provided when one was expected /// No symlink target was provided when one was expected
NoSymlinkTarget, NoSymlinkTarget,
/// An unexpected error ocurred when performing a VFS operation.
Unexpected,
}; };
/// Errors that can be thrown when attempting to mount /// Errors that can be thrown when attempting to mount