ajhahn.de
← FlashOS
Flash 65 lines
// cp — copy SRC to DST for /bin/cp.
//
//   cp SRC DST
//
// Opens SRC read-only, creates DST (a fresh writable file via SYS_CREATE),
// and streams SRC's bytes into it in 512-byte chunks. DST must not already
// exist (create fails closed on a name collision — no clobber); SRC and DST
// are files, and DST's name must fit 8.3 (the create syscall rejects a longer
// one). Errors print a diagnostic to fd 2 and exit.
//
// The first consumer of SYS_CREATE: it is what exercises the create -> write
// -> persist path end to end (the acceptance loop copies a file, reboots, and
// reads it back). Same coreutil recipe as cat: flibc _start shim, flibc_mem,
// stack buffer only.

use flibc

link "flibc_start"
link "flibc_mem"

const BUF_LEN usize = 512

fn diag(msg []u8) {
    _ = flibc.sys.write_fd(2, msg.ptr, msg.len)
}

export fn main(argc usize, argv argv) noreturn {
    if argc < 3 {
        diag("usage: cp SRC DST\n")
        flibc.exit()
    }
    const src = argv[1] orelse flibc.exit()
    const dst = argv[2] orelse flibc.exit()

    const sfd = flibc.sys.open(src)
    if sfd < 0 {
        diag("cp: cannot open source\n")
        flibc.exit()
    }
    const dfd = flibc.sys.create(dst)
    if dfd < 0 {
        diag("cp: cannot create destination\n")
        _ = flibc.sys.close(sfd)
        flibc.exit()
    }

    var buf [BUF_LEN]u8 = undefined
    while true {
        n := flibc.sys.read(sfd, &buf, buf.len)
        if n <= 0 {
            break
        }
        // FAT32 write() pushes the whole chunk in one call; a short write is
        // therefore an error (ENOSPC / fault), not a partial that needs a
        // retry loop.
        if flibc.sys.write_fd(dfd, &buf, #intCast(n)) != n {
            diag("cp: write error\n")
            break
        }
    }
    _ = flibc.sys.close(sfd)
    _ = flibc.sys.close(dfd)
    flibc.exit()
}