Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ jobs:
uses: actions/checkout@v2

- name: Setup Zig
uses: mlugg/setup-zig@v1
uses: mlugg/setup-zig@v2
with:
version: 0.15.2
version: 0.16.0

- name: Build Demo
run: |
Expand Down
8 changes: 4 additions & 4 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ pub fn build(b: *std.Build) void {
break :time RtcConfig{
.static = .{
.year = year,
.month = std.meta.intToEnum(std.time.epoch.Month, month) catch break :time null,
.month = std.enums.fromInt(std.time.epoch.Month, month) orelse break :time null,
.day = day,
},
};
Expand Down Expand Up @@ -152,9 +152,9 @@ pub fn build(b: *std.Build) void {
if (list.items.len > 0) {
list.appendSlice(b.allocator, ", ") catch @panic("out of memory");
}
list.writer(b.allocator).print("\"{X}\"", .{
name,
}) catch @panic("out of memory");
const formatted = std.fmt.allocPrint(b.allocator, "\"{X}\"", .{name}) catch @panic("out of memory");
defer b.allocator.free(formatted);
list.appendSlice(b.allocator, formatted) catch @panic("out of memory");
}
config_header.addValues(.{
.FF_VOLUMES = @as(i64, @intCast(strings.len)),
Expand Down
75 changes: 41 additions & 34 deletions src/fatfs.zig
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
const builtin = @import("builtin");
const std = @import("std");
const config = @import("config");
const c = @cImport({
@cInclude("ff.h");
@cInclude("diskio.h");
});
const logger = std.log.scoped(.fatfs);
const logger = if (builtin.os.tag == .freestanding)
struct {
fn debug(comptime fmt: []const u8, args: anytype) void {
_ = fmt;
_ = args;
}

fn err(comptime fmt: []const u8, args: anytype) void {
_ = fmt;
_ = args;
}
}
else
std.log.scoped(.fatfs);

pub const volume_count = c.FF_VOLUMES;

Expand All @@ -18,33 +32,33 @@ pub const Path = [:0]const PathChar;
pub const WORD = c.WORD;
pub const DWORD = c.DWORD;

pub const MkDirError = ErrorSet(&.{ FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_PATH, FR_INVALID_NAME, FR_DENIED, FR_EXIST, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE });
pub const MkDirError = ErrorSet(error{ DiskErr, IntErr, NotReady, NoPath, InvalidName, Denied, Exist, WriteProtected, InvalidDrive, NotEnabled, NoFilesystem, Timeout, OutOfMemory });
pub fn mkdir(path: Path) MkDirError.Error!void {
try MkDirError.throw(api.mkdir(path.ptr));
}

pub const UnlinkError = ErrorSet(&.{ FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_FILE, FR_NO_PATH, FR_INVALID_NAME, FR_DENIED, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_LOCKED, FR_NOT_ENOUGH_CORE });
pub const UnlinkError = ErrorSet(error{ DiskErr, IntErr, NotReady, NoFile, NoPath, InvalidName, Denied, WriteProtected, InvalidDrive, NotEnabled, NoFilesystem, Timeout, Locked, OutOfMemory });

pub fn unlink(path: Path) UnlinkError.Error!void {
try UnlinkError.throw(api.unlink(path.ptr));
}

pub const RenameError = ErrorSet(&.{ FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_FILE, FR_NO_PATH, FR_INVALID_NAME, FR_EXIST, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_LOCKED, FR_NOT_ENOUGH_CORE });
pub const RenameError = ErrorSet(error{ DiskErr, IntErr, NotReady, NoFile, NoPath, InvalidName, Exist, WriteProtected, InvalidDrive, NotEnabled, NoFilesystem, Timeout, Locked, OutOfMemory });
pub fn rename(
old_path: Path,
new_path: Path,
) RenameError.Error!void {
try RenameError.throw(api.rename(old_path.ptr, new_path.ptr));
}

pub const StatError = ErrorSet(&.{ FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_FILE, FR_NO_PATH, FR_INVALID_NAME, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE });
pub const StatError = ErrorSet(error{ DiskErr, IntErr, NotReady, NoFile, NoPath, InvalidName, InvalidDrive, NotEnabled, NoFilesystem, Timeout, OutOfMemory });
pub fn stat(path: Path) StatError.Error!FileInfo {
var res: c.FILINFO = undefined;
try StatError.throw(api.stat(path.ptr, &res));
return FileInfo.fromFILINFO(res);
}

pub const ChmodError = ErrorSet(&.{ FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_FILE, FR_NO_PATH, FR_INVALID_NAME, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE });
pub const ChmodError = ErrorSet(error{ DiskErr, IntErr, NotReady, NoFile, NoPath, InvalidName, WriteProtected, InvalidDrive, NotEnabled, NoFilesystem, Timeout, OutOfMemory });
pub const ChmodAttributes = struct {
read_only: ?bool = null,
hidden: ?bool = null,
Expand All @@ -70,7 +84,7 @@ pub fn chmod(path: Path, attributes: ChmodAttributes) ChmodError.Error!void {
try ChmodError.throw(api.chmod(path.ptr, @bitCast(values), @bitCast(mask)));
}

pub const UTimeError = ErrorSet(&.{ FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_FILE, FR_NO_PATH, FR_INVALID_NAME, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE });
pub const UTimeError = ErrorSet(error{ DiskErr, IntErr, NotReady, NoFile, NoPath, InvalidName, WriteProtected, InvalidDrive, NotEnabled, NoFilesystem, Timeout, OutOfMemory });
pub fn utime(path: Path, date: Date, time: Time) UTimeError.Error!void {
const file_info = std.mem.zeroInit(c.FILINFO, .{
.fdate = date.encode(),
Expand All @@ -79,17 +93,17 @@ pub fn utime(path: Path, date: Date, time: Time) UTimeError.Error!void {
try UTimeError.throw(api.utime(path.ptr, &file_info));
}

pub const ChDirError = ErrorSet(&.{ FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_PATH, FR_INVALID_NAME, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE });
pub const ChDirError = ErrorSet(error{ DiskErr, IntErr, NotReady, NoPath, InvalidName, InvalidDrive, NotEnabled, NoFilesystem, Timeout, OutOfMemory });
pub fn chdir(path: Path) ChDirError.Error!void {
try ChDirError.throw(api.chdir(path.ptr));
}

pub const ChDriveError = ErrorSet(&.{FR_INVALID_DRIVE});
pub const ChDriveError = ErrorSet(error{InvalidDrive});
pub fn chdrive(path: Path) ChDriveError.Error!void {
try ChDriveError.throw(api.chdrive(path.ptr));
}

pub const GetCwdError = ErrorSet(&.{ FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE });
pub const GetCwdError = ErrorSet(error{ DiskErr, IntErr, NotReady, NotEnabled, NoFilesystem, Timeout, OutOfMemory });
pub fn getcwd(buffer: []PathChar) GetCwdError.Error!Path {
try GetCwdError.throw(api.getcwd(buffer.ptr, std.math.cast(c_uint, buffer.len) orelse std.math.maxInt(c_uint)));
return @ptrCast(std.mem.sliceTo(buffer, 0));
Expand Down Expand Up @@ -136,7 +150,7 @@ pub const FormatOptions = struct {
use_partitions: bool = false,
};

pub const MkfsError = ErrorSet(&.{ FR_DISK_ERR, FR_NOT_READY, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_MKFS_ABORTED, FR_INVALID_PARAMETER, FR_NOT_ENOUGH_CORE });
pub const MkfsError = ErrorSet(error{ DiskErr, NotReady, WriteProtected, InvalidDrive, MkfsAborted, InvalidParameter, OutOfMemory });
pub fn mkfs(path: Path, options: FormatOptions, workspace: []u8) MkfsError.Error!void {
const opts = c.MKFS_PARM{
.fmt = @intFromEnum(options.filesystem) | if (!options.use_partitions) @as(u8, @intCast(c.FM_SFD)) else 0,
Expand All @@ -153,7 +167,7 @@ pub const FileSystem = struct {

raw: c.FATFS,

pub const MountError = ErrorSet(&.{ FR_INVALID_DRIVE, FR_DISK_ERR, FR_NOT_READY, FR_NOT_ENABLED, FR_NO_FILESYSTEM });
pub const MountError = ErrorSet(error{ InvalidDrive, DiskErr, NotReady, NotEnabled, NoFilesystem });
pub fn mount(self: *Self, drive: Path, force_mount: bool) MountError.Error!void {
try MountError.throw(api.mount(&self.raw, drive.ptr, @intFromBool(force_mount)));
}
Expand All @@ -168,7 +182,7 @@ pub const Dir = struct {

raw: c.DIR,

pub const OpenDirError = ErrorSet(&.{ FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_PATH, FR_INVALID_NAME, FR_INVALID_OBJECT, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE, FR_TOO_MANY_OPEN_FILES });
pub const OpenDirError = ErrorSet(error{ DiskErr, IntErr, NotReady, NoPath, InvalidName, InvalidObject, InvalidDrive, NotEnabled, NoFilesystem, Timeout, OutOfMemory, TooManyOpenFiles });

pub fn open(path: Path) OpenDirError.Error!Self {
var dir = Self{ .raw = undefined };
Expand All @@ -183,7 +197,7 @@ pub const Dir = struct {
dir.* = undefined;
}

pub const ReadDirError = ErrorSet(&.{ FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, FR_TIMEOUT, FR_NOT_ENOUGH_CORE });
pub const ReadDirError = ErrorSet(error{ DiskErr, IntErr, InvalidObject, Timeout, OutOfMemory });

pub fn next(dir: *Self) ReadDirError.Error!?FileInfo {
var res: c.FILINFO = .{};
Expand Down Expand Up @@ -427,7 +441,7 @@ pub const File = struct {
mode: Mode = .open_existing,
};

pub const OpenError = ErrorSet(&.{ FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_FILE, FR_NO_PATH, FR_INVALID_NAME, FR_DENIED, FR_EXIST, FR_INVALID_OBJECT, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_LOCKED, FR_NOT_ENOUGH_CORE, FR_TOO_MANY_OPEN_FILES });
pub const OpenError = ErrorSet(error{ DiskErr, IntErr, NotReady, NoFile, NoPath, InvalidName, Denied, Exist, InvalidObject, WriteProtected, InvalidDrive, NotEnabled, NoFilesystem, Timeout, Locked, OutOfMemory, TooManyOpenFiles });

pub fn open(path: Path, flags: OpenFlags) OpenError.Error!Self {
const int_flags = @intFromEnum(flags.mode) | @intFromEnum(flags.access);
Expand Down Expand Up @@ -471,22 +485,22 @@ pub const File = struct {
file.* = undefined;
}

pub const SyncError = ErrorSet(&.{ FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, FR_TIMEOUT });
pub const SyncError = ErrorSet(error{ DiskErr, IntErr, InvalidObject, Timeout });
pub fn sync(file: *Self) SyncError.Error!void {
try SyncError.throw(api.sync(&file.raw));
}

pub const TruncateError = ErrorSet(&.{ FR_DISK_ERR, FR_INT_ERR, FR_DENIED, FR_INVALID_OBJECT, FR_TIMEOUT });
pub const TruncateError = ErrorSet(error{ DiskErr, IntErr, Denied, InvalidObject, Timeout });
pub fn truncate(file: *Self) TruncateError.Error!void {
try TruncateError.throw(api.truncate(&file.raw));
}

pub const SeekToError = ErrorSet(&.{ FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, FR_TIMEOUT });
pub const SeekToError = ErrorSet(error{ DiskErr, IntErr, InvalidObject, Timeout });
pub fn seekTo(file: *Self, offset: FileSize) !void {
try SeekToError.throw(api.lseek(&file.raw, offset));
}

pub const ExpandError = ErrorSet(&.{ FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, FR_DENIED, FR_TIMEOUT });
pub const ExpandError = ErrorSet(error{ DiskErr, IntErr, InvalidObject, Denied, Timeout });
pub fn expand(file: *Self, new_size: FileSize, force_allocate: bool) !void {
try ExpandError.throw(api.expand(&file.raw, new_size, @intFromBool(force_allocate)));
}
Expand All @@ -513,14 +527,14 @@ pub const File = struct {
try self.seekTo(0);
}

pub const WriteError = ErrorSet(&.{ error.Overflow, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, FR_INVALID_OBJECT, FR_TIMEOUT });
pub const WriteError = ErrorSet(error{ Overflow, DiskErr, IntErr, Denied, InvalidObject, Timeout });
pub fn write(file: *Self, data: []const u8) WriteError.Error!usize {
var written: c_uint = 0;
try WriteError.throw(api.write(&file.raw, data.ptr, std.math.cast(c_uint, data.len) orelse return error.Overflow, &written));
return written;
}

pub const ReadError = ErrorSet(&.{ error.Overflow, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, FR_INVALID_OBJECT, FR_TIMEOUT });
pub const ReadError = ErrorSet(error{ Overflow, DiskErr, IntErr, Denied, InvalidObject, Timeout });
pub fn read(file: *Self, data: []u8) ReadError.Error!usize {
var written: c_uint = 0;
try ReadError.throw(api.read(&file.raw, data.ptr, std.math.cast(c_uint, data.len) orelse return error.Overflow, &written));
Expand Down Expand Up @@ -907,26 +921,19 @@ const FR_NOT_ENOUGH_CORE = error.OutOfMemory;
const FR_TOO_MANY_OPEN_FILES = error.TooManyOpenFiles;
const FR_INVALID_PARAMETER = error.InvalidParameter;

fn ErrorSet(comptime options: []const anyerror) type {
fn ErrorSet(comptime ErrorType: type) type {
return struct {
pub const Error: type = @Type(.{
.error_set = blk: {
var names: [options.len]std.builtin.Type.Error = undefined;
for (&names, options) |*name, err| {
name.* = .{ .name = @errorName(err) };
}
break :blk &names;
},
});
pub const Error = ErrorType;

pub inline fn throw(error_code: c.FRESULT) Error!void {
const mapped_error = if (mapGenericError(error_code)) |_| {
return;
} else |err| err;

inline for (options) |error_option| {
if (mapped_error == error_option)
return error_option; // must return the comptime known value for inference
inline for (@typeInfo(ErrorType).error_set.?) |err_info| {
if (mapped_error == @field(anyerror, err_info.name)) {
return @field(ErrorType, err_info.name);
}
}

std.debug.panic("unexpected error: {s}", .{@errorName(mapped_error)});
Expand Down
Loading