Programming Language

Nocter

A self-contained systems language built around simplicity, encapsulation, and foolproof design.

/development/std/fs/darwin.nct

darwin.nct

//! Darwin filesystem operations and native metadata decoding.

see ./index.nct
see ./filesystem.nct

use /internal/io.io_error_from_os
use /internal/os.OSErrorKind
use /internal/os/darwin.{SyscallResult, errno_interrupted}
use /internal/os/darwin.{stat_buffer_size, stat_mode_directory, stat_mode_offset}
use /internal/os/darwin.{stat_mode_regular, stat_size_offset}
use /internal/os/darwin.{sys_rename, sys_stat64, sys_unlink}
use /internal/os/darwin.{errno, error_from_errno, syscall1, syscall2}
use /internal/path.{target_path_address, target_path_argument}
use /mem.{RawBuffer, page_try_allocator}
use /ptr.addr
use /internal/ptr.{from_addr, take_value_at_ptr}

#target: "arm64-darwin"
struct DarwinStatQuery {
    result: SyscallResult
    storage: RawBuffer
}

#target: "arm64-darwin"
func stat_path(path: &str): DarwinStatQuery! {
    let argument = target_path_argument(path)?
    var allocator = page_try_allocator()
    let storage = allocator.try_alloc(stat_buffer_size, 8)?
    var result = syscall2(
        sys_stat64,
        target_path_address(&argument),
        addr(storage.bytes().ptr()),
    )
    while result.errno == errno_interrupted {
        result = syscall2(
            sys_stat64,
            target_path_address(&argument),
            addr(storage.bytes().ptr()),
        )
    }
    return DarwinStatQuery { result: result, storage: move storage }
}

#target: "arm64-darwin"
func metadata_target(path: &str): Metadata! {
    let query = stat_path(path)?
    if query.result.errno != 0 {
        return io_error_from_os(error_from_errno(errno(query.result.errno)))
    }

    let address: usize = addr(query.storage.bytes().ptr())
    let mode_pointer: *u16 = from_addr(address)
    let size_pointer: *u64 = from_addr(address)
    let mode: u16 = take_value_at_ptr(mode_pointer, stat_mode_offset)
    var file_type = FileType.other
    if mode >= stat_mode_regular && mode < stat_mode_regular + 4096 {
        file_type = FileType.regular
    } else if mode >= stat_mode_directory && mode < stat_mode_directory + 4096 {
        file_type = FileType.directory
    }
    let len: u64 = take_value_at_ptr(size_pointer, stat_size_offset)
    return Metadata { file_type: file_type, len: len }
}

#target: "arm64-darwin"
func exists_target(path: &str): bool! {
    let query = stat_path(path)?
    if query.result.errno == 0 {
        return true
    }
    let os_error = error_from_errno(errno(query.result.errno))
    if os_error.kind is OSErrorKind.not_found {
        return false
    }
    return io_error_from_os(os_error)
}

#target: "arm64-darwin"
func remove_file_target(path: &str): void! {
    let argument = target_path_argument(path)?
    let result = syscall1(sys_unlink, target_path_address(&argument))
    if result.errno != 0 {
        return io_error_from_os(error_from_errno(errno(result.errno)))
    }
    return
}

#target: "arm64-darwin"
func rename_target(source: &str, destination: &str): void! {
    let source_argument = target_path_argument(source)?
    let destination_argument = target_path_argument(destination)?
    let result = syscall2(
        sys_rename,
        target_path_address(&source_argument),
        target_path_address(&destination_argument),
    )
    if result.errno != 0 {
        return io_error_from_os(error_from_errno(errno(result.errno)))
    }
    return
}