v0.19 IO with system devices #1443

Merged
vyzo merged 31 commits from v0.19-io-devices into v0.19-staging 2026-06-05 11:05:46 +00:00
Owner
No description provided.
vyzo requested review from fare 2026-06-01 13:59:05 +00:00
vyzo force-pushed v0.19-io-devices from 923ebf4fbc to 9fed7ad6c5 2026-06-04 16:57:42 +00:00 Compare
fare approved these changes 2026-06-05 10:27:07 +00:00
@ -0,0 +13,4 @@
call-with-temporary-directory)
(def current-temporary-directory
(make-parameter (getenv "TMPDIR""/tmp")))
Owner

Add space between strings?

Add space between strings?
vyzo marked this conversation as resolved
@ -0,0 +20,4 @@
=> :string
(let (tmp (make-temporary-file-name base))
(unwind-protect
(proc tmp)
Owner

This smells racy to me.

In gerbil-utils/temporary-files.ss, I ported from my CL library UIOP a call-with-temporary-file that has a bunch of options, including for people who want the name and pretty much nothing else. A new file still has to be created, that you can overwrite or replace. Or a new directory, in which you can create fresh files, if the inside function really can't deal with overwriting or replacing an existing file.

This smells racy to me. In gerbil-utils/temporary-files.ss, I ported from my CL library UIOP a call-with-temporary-file that has a bunch of options, including for people who want the name and pretty much nothing else. A new file still has to be created, that you can overwrite or replace. Or a new directory, in which you can create fresh files, if the inside function really can't deal with overwriting or replacing an existing file.
Author
Owner

this is in general problematic as in general you dont know what it will be used for, it could be a file, a directory, a socket, who knows.

the solution i opted for is:

  • eliminate in process races (this is reliable)
  • make it really hard to conflict cross process: both a random name and the timestamp
  • open the file with O_CREAT so that a race will cause an error.

It's not ideal, perhaps we should create the file and force the programmer to delete it? very unergonomic.

this is in general problematic as in general you dont know what it will be used for, it could be a file, a directory, a socket, who knows. the solution i opted for is: - eliminate in process races (this is reliable) - make it really hard to conflict cross process: both a random name and the timestamp - open the file with O_CREAT so that a race will cause an error. It's not ideal, perhaps we should create the file and force the programmer to delete it? very unergonomic.
Author
Owner

upon in person discussion, we agree that the only acceptable solution is to use cryptographic randomness.

I will implement once crypto porting is complete, in the next branch i am working on.

upon in person discussion, we agree that the only acceptable solution is to use cryptographic randomness. I will implement once crypto porting is complete, in the next branch i am working on.
@ -0,0 +27,4 @@
(proc : :procedure))
=> :string
(let* ((tmp (make-temporary-file-name base))
(io (open-input-output-file-io tmp (fxior O_RDWR O_CREAT)#o600)))
Owner

space?

space?
vyzo marked this conversation as resolved
@ -0,0 +70,4 @@
(when (file-exists? name)
(delete-file-or-directory name #t))))))
(def (mktemp (name : :string))
Owner

The name "mktemp" clashes with that of a libc function that is insecure and deprecated. Better to use a very different name. Or maybe use a more secure variant, like the somewhat portable mkstemp, or the (Linux only, but better) mkostemp.

The name "mktemp" clashes with that of a libc function that is insecure and deprecated. Better to use a very different name. Or maybe use a more secure variant, like the somewhat portable mkstemp, or the (Linux only, but better) mkostemp.
Author
Owner

make-random-name it is.

make-random-name it is.
vyzo marked this conversation as resolved
Owner

Why remove these?

Why remove these?
Author
Owner

no round trip equivalence. and who the fuck would write those uncompressed?

no round trip equivalence. and who the fuck would write those uncompressed?
vyzo marked this conversation as resolved
@ -0,0 +22,4 @@
(let (octets (map string->number octets))
(unless (andmap (cut fx< <> 256) octets)
(raise-bad-argument string->ip4-address "not an 4 octet string" str))
(apply u8vector octets)))
Owner

Uh, don't you want to ensure that

  1. There are 1 to 4 numbers between those dots
  2. They are non-negative integers indeed (NOT necessarily fixnums, at least on a 32-bit target, see 3)
  3. You implement the standard inet_aton algorithm from BSD, adopted by everyone since:
    a. If four components, it's four 8-bit bytes, the usual
    b. If three component, it's one 8-bit component, then one big-endian 16-bit component
    c. If two components, it's one 8-bit component, then one big-endian 24-bit component
    d. If one component, it's a single big-endian 32-bit component (NOT fixnum on 32-bit)
    e. In all of the above forms, components of the dotted address can be specified in decimal, octal
    (with a leading 0), or hexadecimal, with a leading 0X--case insensitive). string->number won't do.
    OR you could use the actual inet_aton.
    man 3 inet_aton
Uh, don't you want to ensure that 1. There are 1 to 4 numbers between those dots 2. They are non-negative integers indeed (NOT necessarily fixnums, at least on a 32-bit target, see 3) 3. You implement the standard inet_aton algorithm from BSD, adopted by everyone since: a. If four components, it's four 8-bit bytes, the usual b. If three component, it's one 8-bit component, then one big-endian 16-bit component c. If two components, it's one 8-bit component, then one big-endian 24-bit component d. If one component, it's a single big-endian 32-bit component (NOT fixnum on 32-bit) e. In all of the above forms, components of the dotted address can be specified in decimal, octal (with a leading 0), or hexadecimal, with a leading 0X--case insensitive). string->number won't do. OR you could use the actual inet_aton. man 3 inet_aton
Author
Owner

there is a regexp; we know they are 4 1-3 digit lumps, and there is a check they are below 256. I don't think we need to check anything else... what hex? what endianess? they are bytes written in decimal and they go into a u8vector, network endianness.

there is a regexp; we know they are 4 1-3 digit lumps, and there is a check they are below 256. I don't think we need to check anything else... what hex? what endianess? they are bytes written in decimal and they go into a u8vector, network endianness.
Author
Owner

i'll make an issue to coax the spark to make a version of aton that parses all those weird thhings.

i'll make an issue to coax the spark to make a version of aton that parses all those weird thhings.
Author
Owner
#1445
@ -10,3 +9,3 @@
(def (fcntl-getfl (fd : :fixnum))
=> :fixnum
(do-syscall (___fcntl1 fd F_GETFL)))
(do-syscall (__fcntl1 fd F_GETFL)))
Owner

Does that mean we didn't have a test for it? We need a test!

Does that mean we didn't have a test for it? We need a test!
Author
Owner

no it was code that didnt previously compiled. it is tested in the io test suite.

no it was code that didnt previously compiled. it is tested in the io test suite.
vyzo marked this conversation as resolved
@ -32,2 +34,2 @@
(__open-raw-device 'file fd (file-raw-device-direction flags)))))
(FileDevice raw fd direction path)))
(__open-raw-device 'file fd dir))))
(FileDevice raw fd dir path)))
Owner

Long names are better. The compiler hardly cares, but the code will be read a lot more people (and LLMs) that written.

Long names are better. The compiler hardly cares, but the code will be read a lot more people (and LLMs) that written.
Author
Owner

eh, its obvious here. I dont like long names for locals, it is obvious.

eh, its obvious here. I dont like long names for locals, it is obvious.
vyzo marked this conversation as resolved
@ -3,3 +3,3 @@
;;; socket address utilities
(import :std/ffi
:std/net/address/address
;; :std/net/address/address
Owner

Another good one for LLMs?

Another good one for LLMs?
Author
Owner

ugh this needs to go.

ugh this needs to go.
Author
Owner

the relevant functions are implemented in io.

the relevant functions are implemented in io.
vyzo marked this conversation as resolved
vyzo merged commit 694265b1fa into v0.19-staging 2026-06-05 11:05:46 +00:00
vyzo referenced this pull request from a commit 2026-06-05 11:05:48 +00:00
vyzo deleted branch v0.19-io-devices 2026-06-05 11:05:57 +00:00
Sign in to join this conversation.
No description provided.