A Lisp implemented in AWK
;; SPDX-License-Identifier: BSD-2-Clause

;; Platform-specific code (shall we say - not specified by POSIX).
;; Until otherwise specified, the platform is assumed to be FreeBSD
;; (base, no third-party packages installed).

;; why sha512t256? "On 64-bit hardware, this algorithm is
;; approximately 50% faster than SHA-256 but with the same level of
;; security..." -- md5(1)
(defun crypto-digests filenames
  (let ((command (append '("sha512t256" "-q") filenames)))
    (or (apply output-lines-of command)
        (error "no output from command %s" (repr command)))))

(defun crypto-digest  (filename)
  (some-output-or-error "sha512t256" "-q" filename))

;; see probe-sed-crypto-digest
(defun pipe-crypto-digest () (list :pipe "sha512t256" "-q"))

;; -r: random (version 4) UUID
(defun get-new-uuid () (some-output-or-error "uuidgen" "-r"))

;; %z: size in bytes (st_size). GNU and Busybox use %s for that, but
;; FreeBSD stat says "bad format" about %s.
(defun get-size-of-file (filename)
  (as-number (some-output-or-error "stat" "-f" "%z" filename)))

;; maybe we could do some other checks on this, but nonempty should
;; suffice to begin with
(defun make-temp-filename-from (based-on-path)
  (some-output-or-error "mktemp" (sprintf "%s.XXXXXXXX" based-on-path)))

(defun get-ogm (source-path)
  ;; The jail has its own set of users, so to get the owner and group
  ;; of a file as names, we have to run stat inside the jail, so it
  ;; will query the right passwd file. (The alternative is to use only
  ;; numeric uids and gids everywhere; but some users and groups are
  ;; just created with the next available id, including some created
  ;; by packages; so you can't know their numeric ids ahead of time.)
  (let ((user (apply some-output-or-error
                     (*run-in-chroot* "stat" "-f" "%Su" source-path)))
        (group (apply some-output-or-error
                      (*run-in-chroot* "stat" "-f" "%Sg" source-path)))
        ;; Lp: "low perms." user, group, and other bits from perms,
        ;; but not file type bits. this will be an octal number; let
        ;; us not treat it as a decimal number.
        (mode (some-output-or-error "stat" "-f" "%Lp" source-path)))
    (list user group mode)))

(defun set-ogm (dest-path user group mode)
  ;; Likewise, in order to consume the right mapping of users to
  ;; numeric uids, we have to run the chown and chmod inside the jail
  ;; and pass the unmodified path.
  (apply system-or-error (*run-in-chroot*
                          "chown" (sprintf "%s:%s" user group) dest-path))
  (apply system-or-error (*run-in-chroot*
                          "chmod" mode dest-path)))

;; for GNU, you could chown --reference and chmod --reference
(defun copy-ogm (source-path dest-path)
  (apply set-ogm dest-path (get-ogm source-path)))