diff --git a/src/all_types.hpp b/src/all_types.hpp index 2a1ef3fefe..0c6af587da 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1211,7 +1211,6 @@ enum PanicMsgId { PanicMsgIdExactDivisionRemainder, PanicMsgIdSliceWidenRemainder, PanicMsgIdUnwrapMaybeFail, - PanicMsgIdUnwrapErrFail, PanicMsgIdInvalidErrorCode, PanicMsgIdCount, @@ -1445,6 +1444,8 @@ struct CodeGen { ZigList error_decls; bool generate_error_name_table; LLVMValueRef err_name_table; + size_t largest_err_name_len; + LLVMValueRef safety_crash_err_fn; IrInstruction *invalid_instruction; ConstExprValue const_void_val; diff --git a/src/codegen.cpp b/src/codegen.cpp index b68f81e442..38e0b37250 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -255,6 +255,7 @@ void codegen_set_linker_script(CodeGen *g, const char *linker_script) { static void render_const_val(CodeGen *g, ConstExprValue *const_val); static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const char *name); static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val); +static void generate_error_name_table(CodeGen *g); static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const char *attr_name) { unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name)); @@ -545,6 +546,34 @@ static bool ir_want_debug_safety(CodeGen *g, IrInstruction *instruction) { return true; } +static bool is_array_of_at_least_n_bytes(CodeGen *g, TypeTableEntry *type_entry, uint32_t n) { + if (type_entry->id != TypeTableEntryIdArray) + return false; + + TypeTableEntry *child_type = type_entry->data.array.child_type; + if (child_type->id != TypeTableEntryIdInt) + return false; + + if (child_type != g->builtin_types.entry_u8) + return false; + + if (type_entry->data.array.len < n) + return false; + + return true; +} + +static uint32_t get_type_alignment(CodeGen *g, TypeTableEntry *type_entry) { + uint32_t alignment = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, type_entry->type_ref); + uint32_t dbl_ptr_bytes = g->pointer_size_bytes * 2; + if (is_array_of_at_least_n_bytes(g, type_entry, dbl_ptr_bytes)) { + return (alignment < dbl_ptr_bytes) ? dbl_ptr_bytes : alignment; + } else { + return alignment; + } +} + + static Buf *panic_msg_buf(PanicMsgId msg_id) { switch (msg_id) { case PanicMsgIdCount: @@ -569,8 +598,6 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) { return buf_create_from_str("slice widening size mismatch"); case PanicMsgIdUnwrapMaybeFail: return buf_create_from_str("attempt to unwrap null"); - case PanicMsgIdUnwrapErrFail: - return buf_create_from_str("attempt to unwrap error"); case PanicMsgIdUnreachable: return buf_create_from_str("reached unreachable code"); case PanicMsgIdInvalidErrorCode: @@ -595,28 +622,128 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) { return val->llvm_global; } -static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) { +static void gen_panic_raw(CodeGen *g, LLVMValueRef msg_ptr, LLVMValueRef msg_len) { FnTableEntry *panic_fn = get_extern_panic_fn(g); LLVMValueRef fn_val = fn_llvm_value(g, panic_fn); + LLVMValueRef args[] = { msg_ptr, msg_len }; + ZigLLVMBuildCall(g->builder, fn_val, args, 2, panic_fn->type_entry->data.fn.calling_convention, false, ""); + LLVMBuildUnreachable(g->builder); +} +static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) { TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true); size_t ptr_index = str_type->data.structure.fields[slice_ptr_index].gen_index; size_t len_index = str_type->data.structure.fields[slice_len_index].gen_index; LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, msg_arg, (unsigned)ptr_index, ""); LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, msg_arg, (unsigned)len_index, ""); - LLVMValueRef args[] = { - LLVMBuildLoad(g->builder, ptr_ptr, ""), - LLVMBuildLoad(g->builder, len_ptr, ""), - }; - ZigLLVMBuildCall(g->builder, fn_val, args, 2, panic_fn->type_entry->data.fn.calling_convention, false, ""); - LLVMBuildUnreachable(g->builder); + LLVMValueRef msg_ptr = LLVMBuildLoad(g->builder, ptr_ptr, ""); + LLVMValueRef msg_len = LLVMBuildLoad(g->builder, len_ptr, ""); + gen_panic_raw(g, msg_ptr, msg_len); } static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) { gen_panic(g, get_panic_msg_ptr_val(g, msg_id)); } +static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { + if (g->safety_crash_err_fn != nullptr) + return g->safety_crash_err_fn; + + static const char *unwrap_err_msg_text = "attempt to unwrap error: "; + + g->generate_error_name_table = true; + generate_error_name_table(g); + + size_t unwrap_err_msg_text_len = strlen(unwrap_err_msg_text); + size_t err_buf_len = strlen(unwrap_err_msg_text) + g->largest_err_name_len; + LLVMValueRef *err_buf_vals = allocate(err_buf_len); + size_t i = 0; + for (; i < unwrap_err_msg_text_len; i += 1) { + err_buf_vals[i] = LLVMConstInt(LLVMInt8Type(), unwrap_err_msg_text[i], false); + } + for (; i < err_buf_len; i += 1) { + err_buf_vals[i] = LLVMGetUndef(LLVMInt8Type()); + } + LLVMValueRef init_value = LLVMConstArray(LLVMInt8Type(), err_buf_vals, err_buf_len); + Buf *global_name = get_mangled_name(g, buf_create_from_str("__zig_panic_buf"), false); + LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(init_value), buf_ptr(global_name)); + LLVMSetInitializer(global_value, init_value); + LLVMSetLinkage(global_value, LLVMInternalLinkage); + LLVMSetGlobalConstant(global_value, false); + LLVMSetUnnamedAddr(global_value, true); + LLVMSetAlignment(global_value, get_type_alignment(g, g->builtin_types.entry_u8)); + + TypeTableEntry *usize = g->builtin_types.entry_usize; + LLVMValueRef full_buf_ptr_indices[] = { + LLVMConstNull(usize->type_ref), + LLVMConstNull(usize->type_ref), + }; + LLVMValueRef full_buf_ptr = LLVMConstInBoundsGEP(global_value, full_buf_ptr_indices, 2); + + LLVMValueRef offset_ptr_indices[] = { + LLVMConstNull(usize->type_ref), + LLVMConstInt(usize->type_ref, unwrap_err_msg_text_len, false), + }; + LLVMValueRef offset_buf_ptr = LLVMConstInBoundsGEP(global_value, offset_ptr_indices, 2); + + Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_fail_unwrap"), false); + LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), &g->err_tag_type->type_ref, 1, false); + LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); + addLLVMFnAttr(fn_val, "noreturn"); + addLLVMFnAttr(fn_val, "cold"); + LLVMSetLinkage(fn_val, LLVMInternalLinkage); + LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv); + + LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); + LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); + LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); + LLVMPositionBuilderAtEnd(g->builder, entry_block); + ZigLLVMClearCurrentDebugLocation(g->builder); + + LLVMValueRef err_val = LLVMGetParam(fn_val, 0); + + LLVMValueRef err_table_indices[] = { + LLVMConstNull(g->builtin_types.entry_usize->type_ref), + err_val, + }; + LLVMValueRef err_name_val = LLVMBuildInBoundsGEP(g->builder, g->err_name_table, err_table_indices, 2, ""); + + LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, err_name_val, slice_ptr_index, ""); + LLVMValueRef err_name_ptr = LLVMBuildLoad(g->builder, ptr_field_ptr, ""); + + LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, err_name_val, slice_len_index, ""); + LLVMValueRef err_name_len = LLVMBuildLoad(g->builder, len_field_ptr, ""); + + LLVMValueRef params[] = { + offset_buf_ptr, // dest pointer + err_name_ptr, // source pointer + err_name_len, // size bytes + LLVMConstInt(LLVMInt32Type(), 1, false), // align bytes + LLVMConstNull(LLVMInt1Type()), // is volatile + }; + + LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, ""); + + LLVMValueRef const_prefix_len = LLVMConstInt(LLVMTypeOf(err_name_len), strlen(unwrap_err_msg_text), false); + LLVMValueRef full_buf_len = LLVMBuildNUWAdd(g->builder, const_prefix_len, err_name_len, ""); + + gen_panic_raw(g, full_buf_ptr, full_buf_len); + + LLVMPositionBuilderAtEnd(g->builder, prev_block); + LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + + g->safety_crash_err_fn = fn_val; + return fn_val; +} + +static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) { + LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g); + LLVMBuildCall(g->builder, safety_crash_err_fn, &err_val, 1, ""); + LLVMBuildUnreachable(g->builder); + +} + static void add_bounds_check(CodeGen *g, LLVMValueRef target_val, LLVMIntPredicate lower_pred, LLVMValueRef lower_value, LLVMIntPredicate upper_pred, LLVMValueRef upper_value) @@ -790,33 +917,6 @@ static LLVMRealPredicate cmp_op_to_real_predicate(IrBinOp cmp_op) { } } -static bool is_array_of_at_least_n_bytes(CodeGen *g, TypeTableEntry *type_entry, uint32_t n) { - if (type_entry->id != TypeTableEntryIdArray) - return false; - - TypeTableEntry *child_type = type_entry->data.array.child_type; - if (child_type->id != TypeTableEntryIdInt) - return false; - - if (child_type != g->builtin_types.entry_u8) - return false; - - if (type_entry->data.array.len < n) - return false; - - return true; -} - -static uint32_t get_type_alignment(CodeGen *g, TypeTableEntry *type_entry) { - uint32_t alignment = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, type_entry->type_ref); - uint32_t dbl_ptr_bytes = g->pointer_size_bytes * 2; - if (is_array_of_at_least_n_bytes(g, type_entry, dbl_ptr_bytes)) { - return (alignment < dbl_ptr_bytes) ? dbl_ptr_bytes : alignment; - } else { - return alignment; - } -} - static LLVMValueRef gen_struct_memcpy(CodeGen *g, LLVMValueRef src, LLVMValueRef dest, TypeTableEntry *type_entry) { @@ -2522,7 +2622,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block); LLVMPositionBuilderAtEnd(g->builder, err_block); - gen_debug_safety_crash(g, PanicMsgIdUnwrapErrFail); + gen_debug_safety_crash_for_err(g, err_val); LLVMPositionBuilderAtEnd(g->builder, ok_block); } @@ -3384,7 +3484,7 @@ static LLVMValueRef gen_test_fn_val(CodeGen *g, FnTableEntry *fn_entry) { } static void generate_error_name_table(CodeGen *g) { - if (!g->generate_error_name_table || g->error_decls.length == 1) { + if (g->err_name_table != nullptr || !g->generate_error_name_table || g->error_decls.length == 1) { return; } @@ -3400,6 +3500,8 @@ static void generate_error_name_table(CodeGen *g) { assert(error_decl_node->type == NodeTypeErrorValueDecl); Buf *name = error_decl_node->data.error_value_decl.name; + g->largest_err_name_len = max(g->largest_err_name_len, buf_len(name)); + LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true); LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), ""); LLVMSetInitializer(str_global, str_init); @@ -3417,7 +3519,7 @@ static void generate_error_name_table(CodeGen *g) { LLVMValueRef err_name_table_init = LLVMConstArray(str_type->type_ref, values, (unsigned)g->error_decls.length); g->err_name_table = LLVMAddGlobal(g->module, LLVMTypeOf(err_name_table_init), - buf_ptr(get_mangled_name(g, buf_create_from_str("err_name_table"), false))); + buf_ptr(get_mangled_name(g, buf_create_from_str("__zig_err_name_table"), false))); LLVMSetInitializer(g->err_name_table, err_name_table_init); LLVMSetLinkage(g->err_name_table, LLVMPrivateLinkage); LLVMSetGlobalConstant(g->err_name_table, true); diff --git a/src/main.cpp b/src/main.cpp index e7ad823fce..32b22e8bda 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -248,8 +248,6 @@ int main(int argc, char **argv) { fprintf(stderr, " %s", args.at(i)); } fprintf(stderr, "\n"); - } else { - os_delete_file(buf_create_from_str("./build")); } return (term.how == TerminationIdClean) ? term.code : -1; } diff --git a/std/build.zig b/std/build.zig index 44b3ddd12c..ae62efdf83 100644 --- a/std/build.zig +++ b/std/build.zig @@ -395,6 +395,33 @@ pub const Builder = struct { return self.invalid_user_input; } + + fn spawnChild(self: &Builder, exe_path: []const u8, args: []const []const u8) { + if (self.verbose) { + %%io.stderr.printf("{}", exe_path); + for (args) |arg| { + %%io.stderr.printf(" {}", arg); + } + %%io.stderr.printf("\n"); + } + + var child = os.ChildProcess.spawn(exe_path, args, &self.env_map, + StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator) + %% |err| debug.panic("Unable to spawn {}: {}\n", exe_path, @errorName(err)); + + const term = %%child.wait(); + switch (term) { + Term.Clean => |code| { + if (code != 0) { + debug.panic("Process {} exited with error code {}\n", exe_path, code); + } + }, + else => { + debug.panic("Process {} terminated unexpectedly\n", exe_path); + }, + }; + + } }; const Version = struct { @@ -568,14 +595,7 @@ const Exe = struct { %return zig_args.append(lib_path); } - if (builder.verbose) { - printInvocation(builder.zig_exe, zig_args); - } - // TODO issue #301 - var child = os.ChildProcess.spawn(builder.zig_exe, zig_args.toSliceConst(), &builder.env_map, - StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator) - %% |err| debug.panic("Unable to spawn zig compiler: {}\n", @errorName(err)); - %return waitForCleanExit(&child); + builder.spawnChild(builder.zig_exe, zig_args.toSliceConst()); } }; @@ -700,14 +720,7 @@ const CLibrary = struct { %%cc_args.append(dir); } - if (builder.verbose) { - printInvocation(cc, cc_args); - } - - var child = os.ChildProcess.spawn(cc, cc_args.toSliceConst(), &builder.env_map, - StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator) - %% |err| debug.panic("Unable to spawn compiler: {}\n", @errorName(err)); - %return waitForCleanExit(&child); + builder.spawnChild(cc, cc_args.toSliceConst()); %%self.object_files.append(o_file); } @@ -732,14 +745,18 @@ const CLibrary = struct { %%cc_args.append(object_file); } - if (builder.verbose) { - printInvocation(cc, cc_args); - } + builder.spawnChild(cc, cc_args.toSliceConst()); - var child = os.ChildProcess.spawn(cc, cc_args.toSliceConst(), &builder.env_map, - StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator) - %% |err| debug.panic("Unable to spawn compiler: {}\n", @errorName(err)); - %return waitForCleanExit(&child); + // sym link for libfoo.so.1 to libfoo.so.1.2.3 + const major_only = %%fmt.allocPrint(builder.allocator, "lib{}.so.{d}", self.name, self.version.major); + defer builder.allocator.free(major_only); + _ = os.deleteFile(builder.allocator, major_only); + %%os.symLink(builder.allocator, self.out_filename, major_only); + // sym link for libfoo.so to libfoo.so.1 + const name_only = %%fmt.allocPrint(builder.allocator, "lib{}.so", self.name); + defer builder.allocator.free(name_only); + _ = os.deleteFile(builder.allocator, name_only); + %%os.symLink(builder.allocator, major_only, name_only); } } @@ -848,14 +865,7 @@ const CExecutable = struct { %%cc_args.append(dir); } - if (builder.verbose) { - printInvocation(cc, cc_args); - } - - var child = os.ChildProcess.spawn(cc, cc_args.toSliceConst(), &builder.env_map, - StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator) - %% |err| debug.panic("Unable to spawn compiler: {}\n", @errorName(err)); - %return waitForCleanExit(&child); + builder.spawnChild(cc, cc_args.toSliceConst()); %%self.object_files.append(o_file); } @@ -879,14 +889,7 @@ const CExecutable = struct { %%cc_args.append(full_path_lib); } - if (builder.verbose) { - printInvocation(cc, cc_args); - } - - var child = os.ChildProcess.spawn(cc, cc_args.toSliceConst(), &builder.env_map, - StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator) - %% |err| debug.panic("Unable to spawn compiler: {}\n", @errorName(err)); - %return waitForCleanExit(&child); + builder.spawnChild(cc, cc_args.toSliceConst()); } pub fn setTarget(self: &CExecutable, target_arch: Arch, target_os: Os, target_environ: Environ) { diff --git a/std/os/child_process.zig b/std/os/child_process.zig index 019f9460de..f3d9a112e3 100644 --- a/std/os/child_process.zig +++ b/std/os/child_process.zig @@ -142,7 +142,7 @@ pub const ChildProcess = struct { const pid_err = posix.getErrno(pid); if (pid_err > 0) { return switch (pid_err) { - errno.EAGAIN, errno.ENOMEM, errno.ENOSYS => error.SysResources, + errno.EAGAIN, errno.ENOMEM, errno.ENOSYS => error.SystemResources, else => error.Unexpected, }; } @@ -210,7 +210,7 @@ fn makePipe() -> %[2]i32 { const err = posix.getErrno(posix.pipe(&fds)); if (err > 0) { return switch (err) { - errno.EMFILE, errno.ENFILE => error.SysResources, + errno.EMFILE, errno.ENFILE => error.SystemResources, else => error.Unexpected, } } @@ -242,7 +242,7 @@ fn writeIntFd(fd: i32, value: ErrInt) -> %void { switch (err) { errno.EINTR => continue, errno.EINVAL => unreachable, - else => return error.SysResources, + else => return error.SystemResources, } } index += amt_written; @@ -260,7 +260,7 @@ fn readIntFd(fd: i32) -> %ErrInt { switch (err) { errno.EINTR => continue, errno.EINVAL => unreachable, - else => return error.SysResources, + else => return error.SystemResources, } } index += amt_written; diff --git a/std/os/index.zig b/std/os/index.zig index 68f33828e6..2b40f5e8ed 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -25,13 +25,16 @@ const BufMap = @import("../buf_map.zig").BufMap; const cstr = @import("../cstr.zig"); error Unexpected; -error SysResources; +error SystemResources; error AccessDenied; error InvalidExe; error FileSystem; error IsDir; error FileNotFound; error FileBusy; +error LinkPathAlreadyExists; +error SymLinkLoop; +error ReadOnlyFileSystem; /// Fills `buf` with random bytes. If linking against libc, this calls the /// appropriate OS-specific library call. Otherwise it uses the zig standard @@ -174,7 +177,7 @@ pub fn posixOpen(path: []const u8, flags: usize, perm: usize, allocator: ?&Alloc errno.ENFILE => error.SystemFdQuotaExceeded, errno.ENODEV => error.NoDevice, errno.ENOENT => error.PathNotFound, - errno.ENOMEM => error.NoMem, + errno.ENOMEM => error.SystemResources, errno.ENOSPC => error.NoSpaceLeft, errno.ENOTDIR => error.NotDir, errno.EPERM => error.BadPerm, @@ -191,7 +194,7 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void { if (err > 0) { return switch (err) { errno.EBUSY, errno.EINTR => continue, - errno.EMFILE => error.SysResources, + errno.EMFILE => error.SystemResources, errno.EINVAL => unreachable, else => error.Unexpected, }; @@ -305,7 +308,7 @@ fn posixExecveErrnoToErr(err: usize) -> error { assert(err > 0); return switch (err) { errno.EFAULT => unreachable, - errno.E2BIG, errno.EMFILE, errno.ENAMETOOLONG, errno.ENFILE, errno.ENOMEM => error.SysResources, + errno.E2BIG, errno.EMFILE, errno.ENAMETOOLONG, errno.ENFILE, errno.ENOMEM => error.SystemResources, errno.EACCES, errno.EPERM => error.AccessDenied, errno.EINVAL, errno.ENOEXEC => error.InvalidExe, errno.EIO, errno.ELOOP => error.FileSystem, @@ -381,3 +384,59 @@ pub fn getCwd(allocator: &Allocator) -> %[]u8 { return buf; } } + +pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) -> %void { + const full_buf = %return allocator.alloc(u8, existing_path.len + new_path.len + 2); + defer allocator.free(full_buf); + + const existing_buf = full_buf; + mem.copy(u8, existing_buf, existing_path); + existing_buf[existing_path.len] = 0; + + const new_buf = full_buf[existing_path.len + 1...]; + mem.copy(u8, new_buf, new_path); + new_buf[new_path.len] = 0; + + const err = posix.getErrno(posix.symlink(existing_buf.ptr, new_buf.ptr)); + if (err > 0) { + return switch (err) { + errno.EFAULT, errno.EINVAL => unreachable, + errno.EACCES, errno.EPERM => error.AccessDenied, + errno.EDQUOT => error.DiskQuota, + errno.EEXIST => error.LinkPathAlreadyExists, + errno.EIO => error.FileSystem, + errno.ELOOP => error.SymLinkLoop, + errno.ENAMETOOLONG => error.NameTooLong, + errno.ENOENT, errno.ENOTDIR => error.FileNotFound, + errno.ENOMEM => error.SystemResources, + errno.ENOSPC => error.NoSpaceLeft, + errno.EROFS => error.ReadOnlyFileSystem, + else => error.Unexpected, + }; + } +} + +pub fn deleteFile(allocator: &Allocator, path: []const u8) -> %void { + const buf = %return allocator.alloc(u8, path.len + 1); + defer allocator.free(buf); + + mem.copy(u8, buf, path); + buf[path.len] = 0; + + const err = posix.getErrno(posix.unlink(buf.ptr)); + if (err > 0) { + return switch (err) { + errno.EACCES, errno.EPERM => error.AccessDenied, + errno.EBUSY => error.FileBusy, + errno.EFAULT, errno.EINVAL => unreachable, + errno.EIO => error.FileSystem, + errno.EISDIR => error.IsDir, + errno.ELOOP => error.SymLinkLoop, + errno.ENAMETOOLONG => error.NameTooLong, + errno.ENOENT, errno.ENOTDIR => error.FileNotFound, + errno.ENOMEM => error.SystemResources, + errno.EROFS => error.ReadOnlyFileSystem, + else => error.Unexpected, + }; + } +} diff --git a/std/os/linux.zig b/std/os/linux.zig index 640a915b77..2214fb8dd1 100644 --- a/std/os/linux.zig +++ b/std/os/linux.zig @@ -287,6 +287,10 @@ pub fn read(fd: i32, buf: &u8, count: usize) -> usize { arch.syscall3(arch.SYS_read, usize(fd), usize(buf), count) } +pub fn symlink(existing: &const u8, new: &const u8) -> usize { + arch.syscall2(arch.SYS_symlink, usize(existing), usize(new)) +} + pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) -> usize { arch.syscall4(arch.SYS_pread, usize(fd), usize(buf), count, offset) } @@ -340,6 +344,10 @@ pub fn kill(pid: i32, sig: i32) -> usize { arch.syscall2(arch.SYS_kill, usize(pid), usize(sig)) } +pub fn unlink(path: &const u8) -> usize { + arch.syscall1(arch.SYS_unlink, usize(path)) +} + pub fn waitpid(pid: i32, status: &i32, options: i32) -> usize { arch.syscall4(arch.SYS_wait4, usize(pid), usize(status), usize(options), 0) }