summaryrefslogtreecommitdiff
path: root/vere/pkg/vere/foil.c
diff options
context:
space:
mode:
authorpolwex <polwex@sortug.com>2025-10-05 21:56:51 +0700
committerpolwex <polwex@sortug.com>2025-10-05 21:56:51 +0700
commitfcedfddf00b3f994e4f4e40332ac7fc192c63244 (patch)
tree51d38e62c7bdfcc5f9a5e9435fe820c93cfc9a3d /vere/pkg/vere/foil.c
claude is gud
Diffstat (limited to 'vere/pkg/vere/foil.c')
-rw-r--r--vere/pkg/vere/foil.c148
1 files changed, 148 insertions, 0 deletions
diff --git a/vere/pkg/vere/foil.c b/vere/pkg/vere/foil.c
new file mode 100644
index 0000000..ce4d734
--- /dev/null
+++ b/vere/pkg/vere/foil.c
@@ -0,0 +1,148 @@
+/// @file
+
+#include "noun.h"
+#include "vere.h"
+
+ /* assumptions:
+ ** all measurements are in chubs (double-words, c3_d, uint64_t).
+ ** little-endian addressing is ASSUMED.
+ **
+ ** framing:
+ ** the last two chubs of a frame:
+ **
+ ** {
+ ** 64-bit frame length
+ ** {
+ ** (high 32 bits) mug of frame
+ ** (low 32 bits) mug of current address
+ ** }
+ ** }
+ **
+ ** we can scan for one of these frames with very low probability
+ ** of a false positive. we always write to and read from the end
+ ** of a file. a frame position points to its end.
+ **
+ ** protocol:
+ ** once the callback is called, all results are fully fsynced.
+ ** all callbacks are optional and can be passed 0.
+ */
+
+/* _foil_fail(): fail with error.
+*/
+static void
+_foil_fail(const c3_c* why_c, c3_i err_i)
+{
+ if ( err_i ) {
+ u3l_log("%s: error: %s", why_c, uv_strerror(err_i));
+ u3_assert(0);
+ } else {
+ u3l_log("%s: file error", why_c);
+ }
+ exit(1);
+}
+
+/* _foil_close(): close file, blockingly.
+*/
+static void
+_foil_close(uv_file fil_f)
+{
+ c3_i err_i;
+ uv_fs_t ruq_u;
+
+ if ( 0 != (err_i = uv_fs_close(u3L, &ruq_u, fil_f, 0)) ) {
+ _foil_fail("uv_fs_close", err_i);
+ }
+}
+
+/* _foil_path(): allocate path.
+*/
+static c3_c*
+_foil_path(u3_dire* dir_u,
+ const c3_c* nam_c)
+{
+ c3_w len_w = strlen(dir_u->pax_c);
+ c3_c* pax_c;
+
+ pax_c = c3_malloc(1 + len_w + 1 + strlen(nam_c));
+ strcpy(pax_c, dir_u->pax_c);
+ pax_c[len_w] = '/';
+ strcpy(pax_c + len_w + 1, nam_c);
+
+ return pax_c;
+}
+
+/* u3_foil_folder(): load directory, blockingly. null if nonexistent.
+*/
+u3_dire*
+u3_foil_folder(const c3_c* pax_c)
+{
+ u3_dire* dir_u;
+ uv_fs_t ruq_u;
+ uv_dirent_t den_u;
+ c3_i err_i;
+
+ /* open directory, synchronously
+ */
+ {
+ err_i = uv_fs_scandir(u3L, &ruq_u, pax_c, 0, 0);
+
+ if ( err_i < 0 ) {
+ if ( UV_ENOENT != err_i ) {
+ _foil_fail(pax_c, err_i);
+ return 0;
+ }
+ else {
+ // XX remove mkdir and retry
+ if ( 0 != (err_i = uv_fs_mkdir(u3L, &ruq_u, pax_c, 0700, 0)) ) {
+ _foil_fail(pax_c, err_i);
+ return 0;
+ }
+ else {
+ uv_fs_req_cleanup(&ruq_u);
+ return u3_foil_folder(pax_c);
+ }
+ }
+ }
+
+ dir_u = u3_dire_init(pax_c);
+ }
+
+ /* create entries for all files and directories
+ */
+ while ( UV_EOF != uv_fs_scandir_next(&ruq_u, &den_u) ) {
+ if ( UV_DIRENT_FILE == den_u.type ) {
+ u3_dent* det_u = u3_dent_init(den_u.name);
+ det_u->nex_u = dir_u->all_u;
+ dir_u->all_u = det_u;
+ } else if ( UV_DIRENT_DIR == den_u.type ) {
+ u3_dent* det_u = u3_dent_init(den_u.name);
+ det_u->nex_u = dir_u->dil_u;
+ dir_u->dil_u = det_u;
+ }
+ }
+
+ /* clean up request
+ */
+ {
+ uv_fs_req_cleanup(&ruq_u);
+ }
+
+ /* open directory file for reading, to fsync
+ */
+ {
+ if ( 0 > (err_i = uv_fs_open(u3L,
+ &ruq_u,
+ pax_c,
+ O_RDONLY,
+ 0600,
+ 0)) )
+ {
+ _foil_fail("open directory", err_i);
+ return 0;
+ }
+ dir_u->fil_u = ruq_u.result;
+
+ uv_fs_req_cleanup(&ruq_u);
+ }
+ return dir_u;
+}