From 2f26b60d59bf607df44e50c51487c5c83aac91f3 Mon Sep 17 00:00:00 2001 From: Philip C Monk Date: Thu, 4 Jun 2015 22:47:27 -0400 Subject: [PATCH] initial work --- i/v/vere.h | 51 +- v/reck.c | 14 +- v/unix.c | 2025 +++++++++++++--------------------------------------- 3 files changed, 537 insertions(+), 1553 deletions(-) diff --git a/i/v/vere.h b/i/v/vere.h index 05f89d2c43..8a593dc071 100644 --- a/i/v/vere.h +++ b/i/v/vere.h @@ -297,6 +297,7 @@ struct _u3_udir; struct _u3_ufil; +#ifdef DELETEME /* u3_unod: in-file or in-directory. */ typedef struct _u3_unod { @@ -344,6 +345,43 @@ struct _u3_uhot* nex_u; // internal list } u3_uhot; +#endif + + typedef struct _u3_unod { + uv_fs_event_t was_u; // stat watcher + c3_o dir; // c3y if dir, c3n if file + c3_o dry; // ie, unmodified + c3_c* pax_c; // absolute path + struct _u3_unod* nex_u; // internal list + struct _u3_unod* par_u; // parent + } u3_unod; + + typedef struct _u3_ufil { + uv_fs_event_t was_u; // stat watcher + c3_o dir; // c3y if dir, c3n if file + c3_o dry; // ie, unmodified + c3_c* pax_c; // absolute path + struct _u3_unod* nex_u; // internal list + c3_w sum_w; // md5sum of last %into + c3_w mus_w; // md5sum of last %ergo + } u3_ufil; + + typedef struct _u3_udir { + uv_fs_event_t was_u; // stat watcher + c3_o dir; // c3y if dir, c3n if file + c3_o dry; // ie, unmodified + c3_c* pax_c; // absolute path + struct _u3_unod* nex_u; // internal list + u3_unod* kid_u; // subnodes + } u3_udir; + + typedef struct _u3_umon { + u3_udir dir_u; // root directory + c3_c* nam_c; // mount point name + u3_umon* nex_u; // internal list + } u3_umon; + + /* u3_usig: receive signals. */ typedef struct _u3_usig { @@ -356,7 +394,7 @@ */ typedef struct _u3_unix { uv_check_t syn_u; // fs sync check - u3_uhot* hot_u; // host state + u3_umon* mon_u; // mount points u3_usig* sig_u; // signal list #ifdef SYNCLOG c3_w lot_w; // sync-slot @@ -935,17 +973,10 @@ void u3_unix_ef_look(void); - /* u3_unix_ef_init(): update filesystem for new acquisition. + /* u3_unix_ef_ergo(): update filesystem from urbit */ void - u3_unix_ef_init(u3_noun who); - - /* u3_unix_ef_ergo(): update filesystem, outbound. - */ - void - u3_unix_ef_ergo(u3_noun who, - u3_noun syd, - u3_noun rel, + u3_unix_ef_ergo(u3_noun mon, u3_noun can); /* u3_unix_io_init(): initialize storage. diff --git a/v/reck.c b/v/reck.c index 568c8978d7..7333cd116b 100644 --- a/v/reck.c +++ b/v/reck.c @@ -102,7 +102,9 @@ _reck_kick_term(u3_noun pox, c3_l tid_l, u3_noun fav) { u3A->own = u3nc(u3k(p_fav), u3A->own); +#ifdef DELETEME u3_unix_ef_init(u3k(p_fav)); +#endif u3_noun hox = u3dc("scot", 'p', u3k(p_fav)); c3_c* nam_c = u3r_string(hox); @@ -164,12 +166,10 @@ _reck_kick_sync(u3_noun pox, u3_noun fav) switch ( u3h(fav) ) { default: break; case c3__ergo: { - u3_noun who = u3k(u3h(u3t(fav))); - u3_noun syd = u3k(u3h(u3t(u3t(fav)))); - u3_noun rel = u3k(u3h(u3t(u3t(u3t(fav))))); - u3_noun can = u3k(u3t(u3t(u3t(u3t(fav))))); + u3_noun mon = u3k(u3h(u3t(fav))); + u3_noun can = u3k(u3t(u3t(fav))); - u3_unix_ef_ergo(who, syd, rel, can); + u3_unix_ef_ergo(mon, can); u3z(pox); u3z(fav); return c3y; } break; } @@ -208,7 +208,9 @@ _reck_kick_ames(u3_noun pox, u3_noun fav) { u3A->own = u3nc(u3k(p_fav), u3A->own); +#ifdef DELETEME u3_unix_ef_init(u3k(p_fav)); +#endif // uL(fprintf(uH, "kick: init: %d\n", p_fav)); u3z(pox); u3z(fav); return c3y; @@ -298,7 +300,9 @@ _reck_kick_spec(u3_noun pox, u3_noun fav) { u3A->own = u3nc(u3k(p_fav), u3A->own); +#ifdef DELETEME u3_unix_ef_init(u3k(p_fav)); +#endif // uL(fprintf(uH, "kick: init: %d\n", p_fav)); u3z(pox); u3z(fav); return c3y; diff --git a/v/unix.c b/v/unix.c index ea6b603087..45e9380ad8 100644 --- a/v/unix.c +++ b/v/unix.c @@ -1,3 +1,8 @@ +// XXX where does mon_u in u3_unix get initialized? +// XXX _unix_string_to_path +// XXX aww, man, i do need parentage because of the dryness thing +// XXX _unix_dir_watch +// XXX _unix_file_watch /* v/unix.c ** ** This file is in the public domain. @@ -24,39 +29,6 @@ /* undef this to turn off syncing out to unix */ #define ERGO_SYNC -/* _unix_ship_in(): c3_w[4] to ship. -*/ -static u3_noun -_unix_ship_in(c3_w* who_w) -{ - return u3i_words(4, who_w); -} - -/* _unix_ship_out(): ship to c3_w[4]. RETAIN. -*/ -static void -_unix_ship_out(u3_noun own, c3_w* who_w) -{ - u3r_words(0, 4, who_w, own); - { - u3_noun inn = _unix_ship_in(who_w); - - c3_assert(_(u3r_sing(inn, own))); - u3z(inn); - } -} - -/* _unix_ship_sing(): yes iff two ships are identical. -*/ -static c3_o -_unix_ship_sing(c3_w* one_w, c3_w* two_w) -{ - return __((one_w[0] == two_w[0]) && - (one_w[1] == two_w[1]) && - (one_w[2] == two_w[2]) && - (one_w[3] == two_w[3])); -} - /* _unix_down(): descend path. */ static c3_c* @@ -104,6 +76,482 @@ _unix_opendir(c3_c* pax_c) return rid_u; } + +/* _unix_get_mount_point(): retrieve or create mount point +*/ +static u3_umon* +_unix_get_mount_point(u3_noun mon) +{ + if ( c3n == u3ud(mon) ) { + c3_assert(!"mount point must be an atom"); + u3z(mon); + return NULL; + } + + c3_c* nam_c = u3r_string(mon); + u3_umon* mon_u; + + for ( mon_u = u3_Host.unx_u.mon_u; + mon_u && 0 != strcmp(nam_c, mon_u->nam_c); + mon_u = mon_u->nex_u ) + { + } + + if ( 0 == u3_mon ) { + mon_u = malloc(sizeof(u3_umon)); + mon_u->nam_c = nam_c; + mon_u->dir_u = malloc(sizeof(u3_udir)); + mon_u->dir_u.dir = c3y; + mon_u->dir_u.dry = c3n; + mon_u->dir_u.pax_c = _unix_down(u3_Host.dir_c, nam_c); + + /* + c3_w dir_w = strlen(u3_Host.dir_c) + c3_w nam_w = strlen(nam_c); + mon_u->dir_u.pax_c = malloc(sizeof(c3_c) * (dir_w + 1 + nam_w)); + strncpy(mon_u->dir_u.pax_c, u3_Host.dir_c, dir_w); + mon_u->dir_u.pax_c[dir_w] = '/'; + strncpy(mon_u->dir_u.pax_c+dir_w+1, nam_c, nam_w); + */ + + mon_u->dir_u.nex_u = NULL; + mon_u->dir_u.kid_u = NULL; + mon_u->nex_u = u3_Host.unx_u.mon_u; + u3_Host.unx_u.mon_u = mon_u; + } + + free(nam_c); + u3z(mon); + + return mon_u; +} + +/* _unix_free_node(): free node, deleting everything within +*/ +void +_unix_free_node(u3_unod* nod_u) +{ + if ( c3y == nod_u->dir_u ) { + uv_close((uv_handle_t*)&dir_u->was_u, _unix_free_dir); + } + else { + uv_close((uv_handle_t*)&dir_u->was_u, _unix_free_file); + } +} + +/* _unix_free_file(): free file, unlinking it +*/ +void +_unix_free_file(u3_ufil* fil_u) +{ + if ( 0 != unlink(fil_u->pax_c) && ENOENT != errno ) { + uL(fprintf(uH, "error unlinking %s: %s\n", fil_u->pax_c, strerror(errno))); + c3_assert(0); + } + + free(nod_u->pax_c); + free(nod_u); +} + +/* _unix_free_dir(): free directory, deleting everything within +*/ +static void +_unix_free_dir(uv_handle_t* was_u) +{ + u3_udir* dir_u = (void*) was_u; + + u3_unod nod_u = dir_u->kid_u; + while ( nod_u ) { + u3_udir* nex_u = nod_u->nex_u; + _unix_free_node(nod_u); + nod_u = nex_u; + } + + if ( 0 != rmdir(dir_u->pax_c) && ENOENT != errno ) { + uL(fprintf(uH, "error rmdiring %s: %s\n", dir_u->pax_c, strerror(errno))); + c3_assert(0); + } + + free(nod_u->pax_c); + free(nod_u); +} + +/* _unix_free_mount_point(): free mount point +*/ +void +_unix_free_mount_point(u3_umon* mon_u) +{ + u3_unod nod_u; + for ( nod_u = mon_u->dir_u.kid_u; kid_u; kid_u = kid_u->nex_u ) { + _unix_free_node(kid_u); + } + + free(mon_u->dir_u.pax_c); + free(mon_u->nam_c); + free(mon_u); +} + +/* _unix_delete_mount_point(): remove mount point from list and free +*/ +void +_unix_delete_mount_point(u3_noun mon) +{ + if ( c3n == u3ud(mon) ) { + c3_assert(!"mount point must be an atom"); + u3z(mon); + return; + } + + c3_c* nam_c = u3r_string(mon); + u3_umon* mon_u; + u3_umon* tem_u; + + mon_u = u3_host.unx_u.mon_u; + if ( !mon_u ) { + uL(fprintf(uH, "mount point already gone: %s\r\n", nam_c)); + goto _delete_mount_point_out; + } + if ( 0 == strcmp(nam_c, mon_u->nam_c) ) { + u3_Host.unx_u.mon_u = mon_u->nex_u; + _unix_free_mount_point(mon_u); + goto _delete_mount_point_out; + } + + for ( ; + mon_u->nex_u && 0 != strcmp(nam_c, mon_u->nex_u->nam_c); + mon_u = mon_u->nex_u ) + { + } + + if ( !mon_u->nex_u ) { + uL(fprintf(uH, "mount point already gone: %s\r\n", nam_c)); + goto _delete_mount_point_out; + } + + tem_u = mon_u->nex_u; + mon_u->nex_u = mon_u->nex_u->nex_u; + _unix_free_mount_point(tem_u); + +_delete_mount_point_out: + free(nam_c); + u3z(mon); +} + +/* _unix_node_update(): update node, producing list of changes +*/ +static u3_noun +_unix_node_update(u3_unod* nod_u) +{ + if ( c3y == dir_u->dir ) { + return _unix_dir_update((void*)nod_u); + } + else { + return _unix_file_update((void*)nod_u); + } +} + +/* _unix_file_update(): update file, producing list of changes + * + * when scanning through files, if dry, do nothing. otherwise, mark as + * dry, then check if file exists. if not, remove self from node list + * and add path plus sig to %into event. otherwise, read the file and + * get a md5 checksum. if same as sum_w, move on. otherwise, overwrite + * sum_w with new md5sum and add path plus data to %into event. +*/ +static u3_noun +_unix_file_update(u3_ufil* fil_u) +{ + c3_assert( c3n == fil_u->dir ); + + if ( c3y == fil_u->dry ) { + return u3_nul; + } + + fil_u->dry = c3y; + + struct stat buf_u; + c3_i fid_i = open(fil_u->pax_c, O_RDONLY, 0644); + c3_w len_w; + c3_y* dat_y; + + if ( (fid_i < 0) || (fstat(fid_i, &buf_u) < 0) ) { + if ( ENOENT == erno ) { + return u3nc(u3nc(pax, u3_nul), u3_nul) + } + else { + uL(fprintf(uH, "error opening file %s: %s\r\n", + fil_u->pax_c, strerror(errno))); + return u3_nul; + } + } + + len_w = buf_u.st_size; + dat_y = c3_malloc(len_w); + + red_w = read(fid_i, dat_y, len_w); + c3_i col_i = close(fid_i); + + if ( col_i < 0 ) { + uL(fprintf(uH, "error closing file %s: %s\r\n", + fil_u->pax_c, strerror(errno))); + } + + if ( len_w != red_w ) { + free(dat_y); + c3_assert(0); + return u3_nul; + } + else { + // XXX check md5 + u3_noun pax = _unix_string_to_path(fil_u->pax_c); + u3_noun mim = u3nt(c3__text, u3i_string("plain"), u3_nul); + u3_noun dat = u3nt(mim, len_w, u3i_bytes(len_w, dat_y)); + return u3nc(u3nt(pax, u3_nul, dat), u3_nul) + } +} + +/* _unix_dir_update(): update directory, producing list of changes +*/ +static u3_noun +_unix_dir_update(u3_udir* dir_u) +{ + c3_assert( c3y == dir_u->dir ); + + if ( c3y == dir_u->dry ) { + return u3_nul; + } + + u3_nod* nod_u; + + for ( nod_u = dir_u->kid_u; nod_u; ) { + if ( c3y == nod_u->dry ) { + nod_u = nod_u->nex_u; + } + else { + if ( c3y == nod_u->dir ) { + DIR* red_u = opendir(nod_u->pax_c); + + if ( 0 == red_u ) { + u3_udir* nex_u = nod_u->nex_u; + + _unix_free_node(nod_u); // XXX actually need to delete from list + + nod_u = nex_u; + } + else { + closedir(rid_u); + nod_u = nod_u->nex_u; + } + } + else { + } + } + } + + // Check for new files + + DIR* rid_u = opendir(dir_u->pax_c); + if ( !rid_u ) { + uL(fprintf(uH, "error opening directory %s: %s\r\n", + dir_u->pax_c, strerror(errno))); + } + + while ( 1 ) { + struct dirent ent_u; + struct dirent* out_u; + c3_w err_w + + if ( (err_w = readdir_r(rid_u, &ent_u, &out_u)) != 0 ) { + uL(fprintf(uH, "error loading directory %s: %s\n", + dir_u->pax_c, strerror(err_w))); + c3_assert(0); + } + else if ( !out_u ) { + break; + } + else if ( '.' == out_u->d_name[0] ) { + continue; + } + else { + c3_c* pax_c = _unix_down(dir_u->pax_c, out_u->d_name); + + struct stat buf_u; + + if ( 0 != stat(pax_c, &buf_u) ) { + free(pax_c); + continue; + } + else { + u3_unod* nod_u; + for ( nod_u = dir_u->kid_u; nod_u; nod_u = nod_u->nex_u ) { + if ( !strcmp(pax_c, nod_u->pax_c) ) { + if ( S_ISDIR(buf_u.st_mode) ) { + c3_assert(nod_u->dir); + } + else { + c3_assert(!nod_u->dir); + } + break; + } + } + + if ( !nod_u ) { + if ( !S_ISDIR(buf_u.st_mode) ) { + if ( !strchr(out_u->d_name,'.') + || strchr(out_u->d_name,'.') != strrchr(out_u->d_name,'.') + || '~' == out_u->d_name[strlen(out_u->d_name) - 1] + ) { + free(pax_c); + continue; + } + + u3_ufil* fil_u = c3_malloc(sizeof(u3_ufil)); + _unix_file_watch(fil_u, dir_u, pax_c); + fil_u->nex = dir_u->kid_u; + dir_u->kid_u = fil_u; + } + else { + if ( strchr(out_u->d_name,'.') ) { + free(pax_c); + continue; + } + + u3_udir* dis_u = c3_malloc(sizeof(u3_udir)); + _unix_dir_watch(dis_u, dir_u, pax_c); + _unix_dir_update(dis_u); + dis_u->nex_u = dir_u->kid_u; + dir_u->kid_u = dis_u; + } + } + } + } + } + + c3_w col_i = closedir(rid_u); + if ( col_i < 0 ) { + uL(fprintf(uH, "error closing directory %s: %s\r\n", + dir_u->pax_c, strerror(errno))); + } + + // get change list + + u3_noun can; + u3_unod nod_u; + for ( nod_u = dir_u->kid_u; nod_u; nod_u = nod_u->nex_u ) { + can = u3kb_weld(_unix_node_update(nod_u),can); + } + + return can; +} + +/* _unix_mount_update(): update mount point +*/ +void +_unix_mount_update(u3_umon* mon_u) +{ + if ( c3n == mon_u->dir_u.dry ) { + u3_noun can = _unix_dir_update(dir_u); + u3v_plan(u3nq(u3_blip, c3__sync, u3k(u3A->sen), u3_nul), + u3nt(c3__into, u3i_string(mon_u->nam_c), can)); + } +} + +/* _unix_sync_ergo(): sync changes to unix +*/ +void +_unix_sync_ergo(u3_umon mon_u, u3_noun can) +{ + c3_assert(!"not implemented"); + u3z(can); +} + +/* _unix_sign_cb: signal callback. +*/ +static void +_unix_sign_cb(uv_signal_t* sil_u, c3_i num_i) +{ + u3_lo_open(); + { + switch ( num_i ) { + default: fprintf(stderr, "\r\nmysterious signal %d\r\n", num_i); break; + + case SIGTERM: + fprintf(stderr, "\r\ncaught signal %d\r\n", num_i); + u3_Host.liv = c3n; + break; + case SIGINT: + fprintf(stderr, "\r\ninterrupt\r\n"); + u3_term_ef_ctlc(); + break; + case SIGWINCH: u3_term_ef_winc(); break; + } + } + u3_lo_shut(c3y); +} + +/* _unix_ef_sync(): check for files to sync. + */ +static void +_unix_ef_sync(uv_check_t* han_u) +{ + u3_lo_open(); + u3_lo_shut(c3y); +} + +/* u3_unix_ef_ergo(): update filesystem from urbit +*/ +void +u3_unix_ef_ergo(u3_noun mon + u3_noun can) +{ + u3_uhot* hot_u; + + mon_u = _unix_get_mount_point(mon); + + _unix_sync_ergo(mon_u, can); +} + +/* u3_unix_io_init(): initialize unix sync. +*/ +void +u3_unix_io_init(void) +{ + u3_unix* unx_u = &u3_Host.unx_u; + + { + u3_usig* sig_u; + + sig_u = c3_malloc(sizeof(u3_usig)); + uv_signal_init(u3L, &sig_u->sil_u); + + sig_u->num_i = SIGTERM; + sig_u->nex_u = unx_u->sig_u; + unx_u->sig_u = sig_u; + } + { + u3_usig* sig_u; + + sig_u = c3_malloc(sizeof(u3_usig)); + uv_signal_init(u3L, &sig_u->sil_u); + + sig_u->num_i = SIGINT; + sig_u->nex_u = unx_u->sig_u; + unx_u->sig_u = sig_u; + } + { + u3_usig* sig_u; + + sig_u = c3_malloc(sizeof(u3_usig)); + uv_signal_init(u3L, &sig_u->sil_u); + + sig_u->num_i = SIGWINCH; + sig_u->nex_u = unx_u->sig_u; + unx_u->sig_u = sig_u; + } + + uv_check_init(u3_Host.lup_u, &u3_Host.unx_u.syn_u); +} + /* u3_unix_acquire(): acquire a lockfile, killing anything that holds it. */ void @@ -181,1461 +629,6 @@ u3_unix_release(c3_c* pax_c) free(paf_c); } -/* _unix_dir_dry(): recursively dry a directory. -*/ -static void -_unix_dir_dry(u3_udir* dir_u) -{ - u3_udir* dis_u; - u3_ufil* fil_u; - - dir_u->dry = c3y; - for ( dis_u = dir_u->dis_u; dis_u; dis_u = dis_u->nex_u ) { - _unix_dir_dry(dis_u); - } - for ( fil_u = dir_u->fil_u; fil_u; fil_u = fil_u->nex_u ) { - fil_u->dry = c3y; - } -} - -/* _unix_fs_event_cb(): filesystem event callback. -*/ -static void -_unix_fs_event_cb(uv_fs_event_t* was_u, - const c3_c* pax_c, - c3_i evt_i, - c3_i sas_i) -{ - // note that we're doing something tricky and weird here. - // - // * libuv passes around a pointer to a uv_fs_event_t - // * we define a struct that STARTS with a uv_fs_event_t and then has - // more fields after it - // * this is what we pass into libuv up top - // * this is what we get out of libuv down below - // * thus a cast is cool - u3_unod* nod_u = (u3_unod*) was_u; - -#ifdef SYNCLOG - - c3_w slot = u3_Host.unx_u.lot_w++ % 1024; - free(u3_Host.unx_u.sylo[slot].pax_c); - u3_Host.unx_u.sylo[slot].pax_c = 0; - u3_Host.unx_u.sylo[slot].unx = c3y; - u3_Host.unx_u.sylo[slot].wer_m = c3_s4('u','v','s','y'); - u3_Host.unx_u.sylo[slot].wot_m = 0; - u3_Host.unx_u.sylo[slot].pax_c = strdup(nod_u->pax_c); -#endif - - { - while ( nod_u ) { - nod_u->dry = c3n; - nod_u = (u3_unod*) nod_u->par_u; - } - } -} - -/* _unix_file_watch(): create file tracker (from filesystem) -*/ -static void -_unix_file_watch(u3_ufil* fil_u, - u3_udir* dir_u, - c3_c* pax_c, - c3_c* pot_c, - c3_w* mod_w) -{ - // (1) build data structure - // - fil_u->non = c3n; - fil_u->dry = c3n; - fil_u->pax_c = pax_c; - fil_u->pot_c = pot_c; - { - c3_c* dot_c = strrchr(pax_c, '.'); - c3_c* fas_c = strrchr(pax_c, '/'); - - fil_u->dot_c = dot_c ? (fas_c ? ((dot_c > fas_c) ? dot_c : 0) - : dot_c) - : 0; - } - fil_u->par_u = dir_u; - fil_u->mod_w[0] = mod_w[0]; fil_u->mod_w[1] = mod_w[1]; - fil_u->mod_w[2] = mod_w[2]; fil_u->mod_w[3] = mod_w[3]; - fil_u->nex_u = 0; - - c3_assert(!fil_u->dot_c || (fil_u->dot_c > fil_u->pax_c)); - - - // (2) stuff data structure into libuv - // - c3_w ret_w = uv_fs_event_init(u3L, // loop - &fil_u->was_u // uv_fs_event_t - ); - if (0 != ret_w){ - uL(fprintf(uH, "event init: %s\n", uv_strerror(ret_w))); - c3_assert(0); - } - - // - ret_w = uv_fs_event_start(&fil_u->was_u, // uv_fs_event_t - _unix_fs_event_cb, // callback - pax_c, // dir as strings - 0); // flags - if ( 0 != ret_w ){ - uL(fprintf(uH, "event start: %s\n", uv_strerror(ret_w))); - c3_assert(0); - } - -} - -/* _unix_dir_watch(): instantiate directory tracker. -*/ -static void -_unix_dir_watch(u3_udir* dir_u, u3_udir* par_u, c3_c* pax_c, c3_c* pot_c) -{ - // (1) build data structure - // - dir_u->yes = c3y; - dir_u->dry = c3n; - dir_u->pax_c = pax_c; - dir_u->pot_c = pot_c; - dir_u->par_u = par_u; - dir_u->dis_u = 0; - dir_u->fil_u = 0; - dir_u->nex_u = 0; - - - // (2) stuff data structure into libuv - // - c3_w ret_w = uv_fs_event_init(u3L, &dir_u->was_u ); - if (0 != ret_w){ - uL(fprintf(uH, "event init: %s\n", uv_strerror(ret_w))); - c3_assert(0); - } - - // note that we're doing something tricky here; see comment in _unix_fs_event_cb - // - ret_w = uv_fs_event_start(&dir_u->was_u, - _unix_fs_event_cb, - pax_c, - 0); - if (0 != ret_w){ - uL(fprintf(uH, "event start: %s\n", uv_strerror(ret_w))); - c3_assert(0); - } - -} - -/* _unix_file_done(): finish freeing file. -*/ -static void -_unix_file_done(uv_handle_t* was_u) -{ - u3_ufil* fil_u = (void*) was_u; - - // uL(fprintf(uH, "file: dun: %s\n", fil_u->pax_c)); - // free(fil_u->pot_c); XXX - free(fil_u->pax_c); - free(fil_u); -} - -/* _unix_file_free(): free (within) file tracker. -*/ -static void -_unix_file_free(u3_ufil* fil_u) -{ - // uL(fprintf(uH, "file: free: %s\n", fil_u->pax_c)); - uv_close((uv_handle_t*)&fil_u->was_u, _unix_file_done); -} - -#if 0 -/* _unix_file_sane(): sanity check file. -*/ -static void -_unix_file_sane(u3_ufil* fil_u) -{ -} - -/* _unix_dir_sane(): sanity check directory. -*/ -static void -_unix_dir_sane(u3_udir* dir_u) -{ - u3_udir* dis_u; - u3_ufil* fil_u; - - for ( dis_u = dir_u->dis_u; dis_u; dis_u = dis_u->nex_u ) { - _unix_dir_sane(dis_u); - } - for ( fil_u = dir_u->fil_u; fil_u; fil_u = fil_u->nex_u ) { - _unix_file_sane(fil_u); - } -} -#endif - -/* _unix_dir_free(): free (within) directory tracker. -*/ -static void _unix_dir_free(u3_udir* dir_u); -static void -_unix_dir_done(uv_handle_t* was_u) -{ - u3_udir* dir_u = (void*) was_u; - - while ( dir_u->dis_u ) { - u3_udir* nex_u = dir_u->dis_u->nex_u; - - _unix_dir_free(dir_u->dis_u); - dir_u->dis_u = nex_u; - } - while ( dir_u->fil_u ) { - u3_ufil* nex_u = dir_u->fil_u->nex_u; - - _unix_file_free(dir_u->fil_u); - dir_u->fil_u = nex_u; - } - - // free(dir_u->pot_c); XXX - free(dir_u->pax_c); - free(dir_u); -} -static void -_unix_dir_free(u3_udir* dir_u) -{ - uv_close((uv_handle_t*)&dir_u->was_u, _unix_dir_done); -} - -/* _unix_dir_update(): update directory. -*/ -static void -_unix_dir_update(u3_udir* dir_u, DIR* rid_u) -{ - if ( c3y == dir_u->dry ) { - return; - } - else { - // Update all wet subdirectories. - // - u3_udir** dis_u; - u3_ufil** fil_u; - - for ( dis_u = &(dir_u->dis_u); *dis_u; ) { - if ( c3y == (*dis_u)->dry ) { - dis_u = &(*dis_u)->nex_u; - } - else { - DIR* red_u = opendir((*dis_u)->pax_c); - - if ( 0 == red_u ) { - u3_udir* ded_u = *dis_u; - u3_udir* nex_u = ded_u->nex_u; - - // uL(fprintf(uH, "removed directory %s\n", ded_u->pax_c)); - _unix_dir_free(ded_u); - - *dis_u = nex_u; - } - else { - _unix_dir_update(*dis_u, red_u); - - closedir(red_u); - dis_u = &(*dis_u)->nex_u; - } - } - } - - // Check all wet files to see if they need deleting. - // - for ( fil_u = &(dir_u->fil_u); *fil_u; ) { - if ( c3y == (*fil_u)->dry ) { - fil_u = &(*fil_u)->nex_u; - } - else { - struct stat buf_u; - - if ( -1 == stat((*fil_u)->pax_c, &buf_u) || - !(S_IFREG & buf_u.st_mode) ) - { - u3_ufil* ded_u = *fil_u; - u3_ufil* nex_u = ded_u->nex_u; - - // uL(fprintf(uH, "removed file %s\n", ded_u->pax_c)); - _unix_file_free(ded_u); - *fil_u = nex_u; - } - else { - fil_u = &(*fil_u)->nex_u; - } - } - } - - // Scan for new files/directories. XX - this is O(n^2) brute - // force, and could be done by smarter event processing. - // - while ( 1 ) { - struct dirent ent_u; - struct dirent* out_u; - - if ( readdir_r(rid_u, &ent_u, &out_u) != 0 ) { - // uL(fprintf(uH, "%s: %s\n", dir_u->pax_c, strerror(errno))); - c3_assert(0); - } - else if ( !out_u ) { - break; - } - else if ( ('.' == out_u->d_name[0]) ) { // XX screws up some paths - continue; - } - else { - c3_c* pax_c = _unix_down(dir_u->pax_c, out_u->d_name); - c3_c* pot_c = _unix_down(dir_u->pot_c, out_u->d_name); - struct stat buf_u; - - // uL(fprintf(uH, " in %s\n", pax_c)); - if ( 0 != stat(pax_c, &buf_u) ) { - free(pax_c); - free(pot_c); - continue; - } - else { - if ( !S_ISDIR(buf_u.st_mode) ) { - c3_w mod_w[4]; - u3_ufil* fil_u; - - if ( ( NULL == strrchr(out_u->d_name, '.')) || - ( '~' == out_u->d_name[strlen(out_u->d_name) - 1] ) - ) { - free(pax_c); - free(pot_c); - continue; - } - - { - u3_noun mod = c3_stat_mtime(&buf_u); - - u3r_words(0, 4, mod_w, mod); - u3z(mod); - } - for ( fil_u = dir_u->fil_u; fil_u; fil_u = fil_u->nex_u ) { - if ( !strcmp(pax_c, fil_u->pax_c) ) { - break; - } - } - if ( !fil_u ) { - fil_u = c3_malloc(sizeof(u3_ufil)); - - // uL(fprintf(uH, "found file %s\n", pax_c)); - _unix_file_watch(fil_u, dir_u, pax_c, pot_c, mod_w); - - fil_u->nex_u = dir_u->fil_u; - dir_u->fil_u = fil_u; - } - } - else { - u3_udir* dis_u; - - for ( dis_u = dir_u->dis_u; dis_u; dis_u = dis_u->nex_u ) { - if ( !strcmp(pax_c, dis_u->pax_c) ) { - break; - } - } - if ( !dis_u ) { - DIR* red_u = _unix_opendir(pax_c); - dis_u = c3_malloc(sizeof(u3_udir)); - - // uL(fprintf(uH, "found directory %s\n", pax_c)); - _unix_dir_watch(dis_u, dir_u, pax_c, pot_c); - _unix_dir_update(dis_u, red_u); - - dis_u->nex_u = dir_u->dis_u; - dir_u->dis_u = dis_u; - - closedir(red_u); - } else { - free(pax_c); - free(pot_c); - } - } - } - } - } - } -} - -/* unix_load(): load a file as a cage - * - * return value of u3_none means delete, u3_nul means no change -*/ -static u3_weak -_unix_load(u3_ufil* fil_u) -{ - struct stat buf_u; - c3_i fid_i = open(fil_u->pax_c, O_RDONLY, 0644); - c3_w fln_w, red_w; - c3_y* pad_y; - c3_i fit_i = open(fil_u->pot_c, O_RDONLY, 0644); - c3_w flt_w, ret_w; - c3_y* pat_y; - - if ( (fid_i < 0) || (fstat(fid_i, &buf_u) < 0) ) { - // ignore if the file disappeared between getting the sync event and now - if ( ENOENT != errno ) { - uL(fprintf(uH, "error loading %s: %s\n", fil_u->pax_c, strerror(errno))); - } - return u3_none; - } - fln_w = buf_u.st_size; - pad_y = c3_malloc(fln_w); - - red_w = read(fid_i, pad_y, fln_w); - close(fid_i); // should probably check the return value - - if ( fln_w != red_w ) { - free(pad_y); - c3_assert(0); - return 0; - } - else { - if ( !(fit_i < 0 || fstat(fit_i, &buf_u) < 0) ) { - flt_w = buf_u.st_size; - pat_y = c3_malloc(flt_w); - - ret_w = read(fit_i, pat_y, flt_w); - close(fit_i); - - if ( flt_w != ret_w ) { - free(pad_y); - c3_assert(0); - return 0; - } - - if ( fln_w == flt_w && 0 == memcmp(pad_y, pat_y, fln_w) ) { - free(pad_y); - free(pat_y); - return u3_nul; - } - - free(pat_y); - } - - // -:!>(*[[@tas @tas ~] @ud @]) - u3_noun typ = u3nt(c3__cell, - u3nt(c3__cell, - u3nc(c3__atom, c3__tas), - u3nt(c3__cell, - u3nc(c3__atom, c3__tas), - u3nt(c3__cube, - u3_nul, - u3nc(c3__atom, 'n')))), - u3nt(c3__cell, - u3nc(c3__atom, c3__ud), - u3nc(c3__atom, u3_nul))); - u3_noun nam = u3nt(c3__text, u3i_string("plain"), u3_nul); - u3_noun pad = u3nt(nam, fln_w, u3i_bytes(fln_w, (c3_y *)pad_y)); - u3_noun cay = u3nt(c3__mime, typ, pad); - free(pad_y); - - return cay; - } -} - -/* _unix_file_load(): load a file by watcher. -*/ -static u3_weak -_unix_file_load(u3_ufil* fil_u) -{ - return _unix_load(fil_u); -} - -/* _unix_dir_name(): directory name. -*/ -static u3_noun -_unix_dir_name(u3_udir* dir_u) -{ - c3_w pel_w = strlen(dir_u->par_u->pax_c); - c3_c* pax_c = dir_u->pax_c + pel_w + 1; - c3_c* fas_c = strchr(pax_c, '/'); - - return fas_c ? u3i_bytes((fas_c - pax_c), (c3_y*) pax_c) - : u3i_string(pax_c); -} - -/* _unix_file_tame(): file name/extension for toplevel. -*/ -static u3_noun -_unix_file_tame(u3_ufil* fil_u) -{ - c3_c* fas_c = strrchr(fil_u->pax_c, '/'); - c3_c* pax_c = fil_u->pax_c + (fas_c-fil_u->pax_c) + 1; - - if ( !fil_u->dot_c ) { - return u3_none; - } - else { - c3_c* ext_c = fil_u->dot_c + 1; - c3_w nam_w = fil_u->dot_c - pax_c; - - return u3nc(u3i_bytes(nam_w, (c3_y*)pax_c), - u3i_string(ext_c)); - } -} - -/* _unix_file_name(): file name/extension. -*/ -static u3_noun -_unix_file_name(u3_ufil* fil_u) -{ - c3_w pel_w = strlen(fil_u->par_u->pax_c); - c3_c* pax_c = fil_u->pax_c + pel_w + 1; - - if ( !fil_u->dot_c ) { - return u3i_string(pax_c); - } - else { - c3_c* ext_c = fil_u->dot_c + 1; - - ext_c = (*ext_c == '^') ? (ext_c + 1) : ext_c; - return u3nc(u3i_bytes((fil_u->dot_c - pax_c), (c3_y*)pax_c), - u3i_string(ext_c)); - } -} - -/* _unix_dir_khan_file(): process a file for khan. -*/ -static u3_noun -_unix_dir_khan_file(u3_noun pam, u3_noun wib, u3_noun woz) -{ - u3_weak ole; - if ( c3n == u3du(wib) ) { - ole = u3kdb_get(u3k(pam), u3k(wib)); - - if ( u3_none == ole ) { - ole = u3nq(u3_nul, woz, u3_nul, u3_nul); - } - else if ( u3_nul == ole ) { - ole = u3nt(u3_nul, woz, u3_nul); - } - else { - u3_noun elo; - - elo = u3nt(u3_nul, woz, u3k(u3t(u3t(ole)))); - u3z(ole); - - ole = elo; - } - pam = u3kdb_put(pam, wib, ole); - } - else { - u3_noun fid = u3h(wib); - u3_noun har = u3t(wib); - - ole = u3kdb_get(u3k(pam), u3k(fid)); - - if ( u3_none == ole ) { - ole = u3nq(u3_nul, - u3_nul, - u3_nul, - u3kdb_put(u3_nul, - u3k(har), - u3nq(u3_nul, woz, u3_nul, u3_nul))); - } - else if ( u3_nul == ole ) { - c3_assert(!"impossible because of the strncmp check in _unix_dir_khan"); - } - else { - u3_noun oor, elo; - u3_noun roo = u3t(u3t(u3t(ole))); - u3_weak tup = u3kdb_get(u3k(roo), u3k(har)); - - if ( u3_none == tup ) { - tup = u3nt(u3_nul, woz, u3_nul); - } else { - u3_noun upt; - - upt = u3nq(u3_nul, woz, u3_nul, u3k(u3t(tup))); - u3z(tup); - - tup = upt; - } - oor = u3kdb_put(u3k(roo), u3k(har), tup); - elo = u3nq(u3_nul, u3k(u3h(u3t(ole))), u3_nul, oor); - - u3z(ole); ole = elo; - } - pam = u3kdb_put(pam, u3k(fid), ole); - u3z(wib); - } - return pam; -} - -/* _unix_dir_khan(): resolve directory to khan. -*/ -static u3_noun -_unix_dir_khan(u3_udir* dir_u) -{ - if ( c3y == dir_u->dry ) { - return u3_nul; - } - - u3_udir* dis_u; - u3_ufil* fil_u; - u3_noun pam = u3_nul; - - for ( dis_u = dir_u->dis_u; dis_u; dis_u = dis_u->nex_u ) { - for ( fil_u = dir_u->fil_u; fil_u; fil_u = fil_u->nex_u ) { - if ( 0 == strncmp(dis_u->pax_c, fil_u->pax_c, strlen(dis_u->pax_c)) ) { - dis_u->dry = c3n; - break; - } - } - u3_noun pre = _unix_dir_name(dis_u); - u3_noun kan = _unix_dir_khan(dis_u); - - // uL(fprintf(uH, "dir %s\n", u3r_string(pre))); - if ( u3_nul == kan || u3_nul != u3h(u3t(kan)) || u3_nul != u3t(u3t(kan)) ) { - pam = u3kdb_put(pam, pre, kan); - } - else { - u3z(kan); u3z(pre); - } - } - - if ( !dir_u->par_u->par_u ) { // toplevel - for ( fil_u = dir_u->par_u->fil_u; fil_u; fil_u = fil_u->nex_u ) { - // uL(fprintf(uH, "top %s\n", fil_u->pax_c)); - u3_noun wib = _unix_file_tame(fil_u); - if ( u3_none == wib ) continue; - u3_noun dur = _unix_dir_name(dir_u); - if ( c3n == u3r_sing(dur, u3h(wib)) ) { // wrong desk - u3z(dur); u3z(wib); - continue; - } - u3_noun woz = u3nt(u3_nul, u3_nul, _unix_file_load(fil_u)); - pam = _unix_dir_khan_file(pam, u3k(u3t(wib)), woz); - u3z(dur); - u3z(wib); - } - } - - for ( fil_u = dir_u->fil_u; fil_u; fil_u = fil_u->nex_u ) { - u3_noun wib = _unix_file_name(fil_u); - u3_weak baw = _unix_file_load(fil_u); - u3_noun wol = (u3_none == baw ? u3nc(u3_nul, u3_nul) : - u3_nul == baw ? u3_nul : - u3nt(u3_nul, u3_nul, baw)); - pam = _unix_dir_khan_file(pam, wib, wol); - } - return u3nq(u3_nul, u3_nul, u3_nul, pam); -} - -/* _find_mug(): find a noun with a given mug. retain. DELETEME -*/ -#if 0 -static u3_weak -_find_mug(u3_noun som, c3_l mug_l) -{ - if ( mug_l == u3r_mug(som) ) { - return som; - } - else { - u3_weak pro; - - if ( _(u3du(som)) ) { - if ( (pro = _find_mug(u3h(som), mug_l)) != u3_none ) { - return pro; - } - else return _find_mug(u3t(som), mug_l); - } - else return u3_none; - } -} -#endif - -#if 0 -/* _unix_desk_peek(): peek for ankh. -*/ -static u3_noun -_unix_desk_peek(u3_noun hox, - u3_noun syd, - u3_noun lok) -{ - u3_noun arg; - u3_noun cay; - - arg = u3nc(c3_s2('c','z'), u3nq(hox, syd, lok, u3_nul)); - cay = u3v_peek(arg); - - if ( u3_nul == cay ) { - return u3nt(0, u3_nul, u3_nul); - } - else { - u3_noun ank = u3k(u3t(cay)); - - u3z(cay); return ank; - } -} -#endif - -#if 0 -/* _unix_ankh_sing_map(): compare ankh maps for u3_ankh_sing(). -*/ -static u3_noun _unix_ankh_sing_in(u3_noun, u3_noun); - -static u3_noun -_unix_ankh_sing_map(u3_noun mun, u3_noun mur) // retain -{ - u3_noun n_mun, l_mun, r_mun; - u3_noun n_mur, l_mur, r_mur; - - if ( (u3_nul == mun) && (u3_nul == mur) ) { return c3y; } - if ( (u3_nul == mun) || (u3_nul == mur) ) { return c3n; } - - u3x_trel(mun, &n_mun, &l_mun, &r_mun); - u3x_trel(mur, &n_mur, &l_mur, &r_mur); - - if ( (c3n == (u3r_sing(u3h(n_mun), u3h(n_mur)))) || - (c3n == _unix_ankh_sing_in(u3t(n_mun), u3t(n_mur))) || - (c3n == _unix_ankh_sing_map(l_mun, l_mur)) || - (c3n == _unix_ankh_sing_map(r_mun, r_mur)) ) - { - return c3n; - } else return c3y; -} - -/* _unix_node_sing(): test node equality. -*/ -static u3_noun -_unix_node_sing(u3_noun xud, u3_noun bud) -{ - if ( (u3_nul == xud) && (u3_nul == bud) ) { return c3y; } - if ( (u3_nul == xud) || (u3_nul == bud) ) { return c3n; } - - return u3r_sing(u3t(u3t(xud)), u3t(u3t(bud))); -} - -/* _unix_ankh_sing_in(): stupid ankh test which ignores broken hash. -*/ -static u3_noun -_unix_ankh_sing_in(u3_noun xun, u3_noun bur) // retain -{ - u3_noun p_xun, q_xun, r_xun; - u3_noun p_bur, q_bur, r_bur; - - u3x_trel(xun, &p_xun, &q_xun, &r_xun); - u3x_trel(bur, &p_bur, &q_bur, &r_bur); - - if ( c3n == _unix_node_sing(q_xun, q_bur) ) { - return c3n; - } - return _unix_ankh_sing_map(r_xun, r_bur); -} - -/* _unix_ankh_sing(): full ankh compare. -*/ -static u3_noun -_unix_ankh_sing(u3_noun xun, u3_noun bur) // retain -{ - if ( c3y == u3r_sing(xun, bur) ) { - return c3y; - } else { - if ( c3n == _unix_ankh_sing_in(xun, bur) ) { - // fprintf(stderr, "uas: no, no (%x, %x)\r\n", u3_mug(xun), u3_mug(bur)); - return c3n; - } - else { - // fprintf(stderr, "uas: no, yes\r\n"); - return c3y; - } - } -} -#endif - -/* _unix_desk_sync_into(): sync external changes to desk. -*/ -static void -_unix_desk_sync_into(u3_noun who, - u3_noun hox, - u3_noun syd, - u3_udir* dir_u) -{ - u3_noun xun, fav, pax; - - xun = _unix_dir_khan(dir_u); - - if ( _(u3ud(xun)) ) { - u3z(who); u3z(hox); u3z(syd); u3z(xun); - return; - } - else { - pax = u3nq(u3_blip, c3__sync, u3k(u3A->sen), u3_nul); - fav = u3nq(c3__into, who, syd, u3k(u3t(xun))); - - u3v_plan(pax, fav); - - u3z(hox); u3z(xun); - return; - } -} - -/* _unix_ship_update(): update top level ship. -*/ -static void -_unix_ship_update(u3_uhot* hot_u) -{ - u3_udir* dir_u = &(hot_u->dir_u); - - if ( c3n == dir_u->dry ) { - DIR* rid_u = _unix_opendir(dir_u->pax_c); - u3_udir* dis_u; - u3_noun who = _unix_ship_in(hot_u->who_w); - u3_noun hox = u3dc("scot", 'p', u3k(who)); - - _unix_dir_update(dir_u, rid_u); - for ( dis_u = dir_u->dis_u; dis_u; dis_u = dis_u->nex_u ) { - u3_noun syd = _unix_dir_name(dis_u); - - // uL(fprintf(uH, "sync %s %s\n", u3r_string(hox), u3r_string(syd))); - _unix_desk_sync_into(u3k(who), u3k(hox), syd, dis_u); - } - u3z(hox); - u3z(who); - - closedir(rid_u); - _unix_dir_dry(dir_u); - } -} - -/* _unix_hot_gain(): gain ship. - * - * I feel like there's some freeing here I missed - * particularly pin_c and/or pot_c -*/ -static void -_unix_hot_gain(u3_noun who, u3_noun mek) -{ - u3_noun hox = u3dc("scot", 'p', u3k(who)); - c3_c* hox_c = u3r_string(hox); - c3_c* pax_c = _unix_down(u3_Host.dir_c, hox_c + 1); - c3_c* pin_c = _unix_down(pax_c, "in"); - c3_c* pot_c = _unix_down(pax_c, "out"); -// DIR* rox_u = opendir(hox_c); - DIR* rid_u = opendir(pax_c); - DIR* rin_u = opendir(pin_c); - DIR* rot_u = opendir(pot_c); - -// if ( !rox_u ) { -// if ( c3y == mek ) { -// _unix_mkdir(hox_c); -// } else { -// u3z(who); -// u3z(hox); -// return; -// } -// } else closedir(rox_u); - if ( !rid_u ) { - if ( c3y == mek ) { - _unix_mkdir(pax_c); - } else { - u3z(who); - u3z(hox); - return; - } - } else closedir(rid_u); - if ( !rin_u ) { - if ( c3y == mek ) { - _unix_mkdir(pin_c); - } else { - u3z(who); - u3z(hox); - return; - } - } else closedir(rin_u); - if ( !rot_u ) { - if ( c3y == mek ) { - _unix_mkdir(pot_c); - } else { - u3z(who); - u3z(hox); - return; - } - } else closedir(rot_u); - - // uL(fprintf(uH, "GAIN %s\n", pax_c)); - - free(pax_c); - free(hox_c); - u3z(hox); - u3_unix_acquire(pin_c); - - { - u3_uhot* hot_u = c3_malloc(sizeof(u3_uhot)); - - _unix_dir_watch(&hot_u->dir_u, 0, pin_c, pot_c); - - _unix_ship_out(who, hot_u->who_w); - u3z(who); - - hot_u->nex_u = u3_Host.unx_u.hot_u; - u3_Host.unx_u.hot_u = hot_u; - } -} - -/* _unix_hot_lose(): release within a host directory. -*/ -static void -_unix_hot_lose(u3_uhot* hot_u) -{ - // uL(fprintf(uH, "lose: %s\n", hot_u->dir_u.pax_c)); - _unix_dir_free(&(hot_u->dir_u)); -} - -/* _unix_home(): find home directory from identity. -*/ -static u3_uhot* -_unix_home(u3_noun who) -{ - u3_unix* unx_u = &u3_Host.unx_u; - u3_uhot* hot_u; - c3_w who_w[4]; - - _unix_ship_out(who, who_w); - for ( hot_u = unx_u->hot_u; - hot_u && !_(_unix_ship_sing(who_w, hot_u->who_w)); - hot_u = hot_u->nex_u ) - { - // uL(fprintf(uH, "uh: %p, %s\n", hot_u, hot_u->dir_u.pax_c)); - } - return hot_u; -} - -#ifdef ERGO_SYNC -/* _unix_mkpath(): mkdir -p, asserting - * - * adapted from - * http://niallohiggins.com/2009/01/08/mkpath-mkdir-p-alike-in-c-for-unix/ - */ -static void -_unix_mkpath(const char *s) -{ - char *q, *r = NULL, *path = NULL, *up = NULL; - - if (strcmp(s, ".") == 0 || strcmp(s, "/") == 0) - return; - - if ((path = strdup(s)) == NULL) - c3_assert(0); - - if ((q = strdup(s)) == NULL) - c3_assert(0); - - if ((r = dirname(q)) == NULL) - goto out; - - if ((up = strdup(r)) == NULL) - c3_assert(0); - - _unix_mkpath(up); - - _unix_mkdir(path); - - free(up); -out: - free(q); - free(path); -} - -/* _unix_dir_forge: instantiate directory tracker (and make directory). -*/ -static void -_unix_dir_forge(u3_udir* dir_u, u3_udir* par_u, u3_noun tet) -{ - - c3_c* tet_c = u3r_string(tet); - c3_w pax_w = strlen(par_u->pax_c); - c3_w tet_w = strlen(tet_c); - c3_c* pax_c = c3_malloc(pax_w + 1 + tet_w + 1); - c3_c* pot_c = c3_malloc(pax_w + 1 + 1 + tet_w + 1); - - strncpy(pax_c, par_u->pax_c, pax_w + 1); - pax_c[pax_w] = '/'; - strncpy(pax_c + pax_w + 1, tet_c, tet_w + 1); - pax_c[pax_w + tet_w + 1] = '\0'; - - strncpy(pot_c, par_u->pot_c, pax_w + 1 + 1); - pot_c[pax_w + 1] = '/'; - strncpy(pot_c + pax_w + 1 + 1, tet_c, tet_w + 1); - pot_c[pax_w + 1 + tet_w + 1] = '\0'; - - free(tet_c); - u3z(tet); - - _unix_mkdir(pax_c); - _unix_mkdir(pot_c); - _unix_dir_watch(dir_u, par_u, pax_c, pot_c); -} - -/* _unix_file_form(): form a filename path downward. -*/ -static c3_c* -_unix_file_form(c3_c* pax_c, - u3_noun pre, - u3_noun ket, - u3_noun ext) -{ - c3_c* pre_c = u3r_string(pre); - c3_c* ext_c = u3r_string(ext); - c3_w pax_w = strlen(pax_c); - c3_w pre_w = strlen(pre_c); - c3_w ext_w = strlen(ext_c); - c3_w ket_w = (c3y == ket) ? 1 : 0; - c3_c* pox_c = c3_malloc(pax_w + 1 + pre_w + 1 + ket_w + ext_w + 1); - - strncpy(pox_c, pax_c, pax_w); - pox_c[pax_w] = '/'; - strncpy(pox_c + pax_w + 1, pre_c, pre_w); - pox_c[pax_w + 1 + pre_w] = '.'; - if ( c3y == ket ) { - pox_c[pax_w + 1 + pre_w + 1] = '^'; - } - strncpy(pox_c + pax_w + 1 + pre_w + 1 + ket_w, ext_c, ext_w); - pox_c[pax_w + 1 + pre_w + 1 + ket_w + ext_w] = '\0'; - - free(pre_c); free(ext_c); - u3z(pre); u3z(ext); - - return pox_c; -} - -/* _unix_unlink(): unlink, asserting. -*/ -static void -_unix_unlink(c3_c* pax_c) -{ - if ( 0 != unlink(pax_c) && ENOENT != errno ) { - uL(fprintf(uH, "error unlinking %s: %s\n", pax_c, strerror(errno))); - c3_assert(0); - } -} - -/* _unix_pdir(): find directory reference from text. -*/ -static u3_udir** -_unix_pdir(u3_udir* par_u, u3_noun tet) -{ - c3_c* tet_c = u3r_string(tet); - c3_w pax_w = strlen(par_u->pax_c); - u3_udir** dir_u; - - u3z(tet); - - dir_u = &(par_u->dis_u); - while ( 1 ) { - if ( !*dir_u || !strcmp(((*dir_u)->pax_c + pax_w + 1), tet_c) ) { - free(tet_c); return dir_u; - } - else dir_u = &((*dir_u)->nex_u); - } -} - -/* unix_save(): save a file. -*/ -static void -_unix_save(c3_c* pax_c, u3_atom oat) -{ - c3_c* dir = strdup(pax_c); - _unix_mkpath(dirname(dir)); - free(dir); - - c3_i fid_i = open(pax_c, O_WRONLY | O_CREAT | O_TRUNC, 0666); - c3_w fln_w, rit_w, siz_w; - c3_y* oat_y; - - if ( fid_i < 0 ) { - uL(fprintf(uH, "error opening %s: %s\n", pax_c, strerror(errno))); - u3m_bail(c3__fail); - } - - siz_w = u3h(u3t(oat)); - fln_w = u3r_met(3, u3t(u3t(oat))); - oat_y = c3_malloc(siz_w); - memset(oat_y, 0, siz_w); - - u3r_bytes(0, fln_w, oat_y, u3t(u3t(oat))); - u3z(oat); - - rit_w = write(fid_i, oat_y, siz_w); - if ( rit_w != siz_w ) { - uL(fprintf(uH, "error writing %s: %s\n", pax_c, strerror(errno))); - c3_assert(0); - } - - close(fid_i); - free(oat_y); -} - -/* _unix_desk_sync_tofu(): sync out file install. -*/ -static void -_unix_desk_sync_tofu(u3_udir* dir_u, - u3_noun pre, - u3_noun ext, - u3_noun mim) -{ - c3_c* pox_c = _unix_file_form(dir_u->pax_c, u3k(pre), c3n, u3k(ext)); - c3_c* pot_c = _unix_file_form(dir_u->pot_c, u3k(pre), c3n, u3k(ext)); - c3_c* pux_c = _unix_file_form(dir_u->pax_c, u3k(pre), c3y, u3k(ext)); - c3_c* put_c = _unix_file_form(dir_u->pot_c, u3k(pre), c3y, u3k(ext)); - u3_ufil** fil_u; - - // uL(fprintf(uH, "tofu pox_c %s op %s\n", pox_c, u3r_string(u3h(mis)))); - -#ifdef SYNCLOG - c3_w slot = u3_Host.unx_u.lot_w++ % 1024; - free(u3_Host.unx_u.sylo[slot].pax_c); - u3_Host.unx_u.sylo[slot].pax_c = 0; -#endif - - fil_u = &(dir_u->fil_u); - while ( 1 ) { // XX crude! - if ( !*fil_u || - !strcmp((*fil_u)->pax_c, pox_c) /* || - !strcmp((*fil_u)->pax_c, pux_c) */ ) - { - break; - } - else fil_u = &((*fil_u)->nex_u); - } - - if ( *fil_u && u3_nul == mim ) { - uL(fprintf(uH, "file goning: %s\n", pox_c)); - u3_ufil* ded_u = *fil_u; - -#ifdef SYNCLOG - u3_Host.unx_u.sylo[slot].unx = c3n; - u3_Host.unx_u.sylo[slot].wer_m = c3_s4('t','o','f','u'); - u3_Host.unx_u.sylo[slot].wot_m = c3__del; - u3_Host.unx_u.sylo[slot].pax_c = strdup(ded_u->pax_c); -#endif - - *fil_u = ded_u->nex_u; - _unix_unlink(ded_u->pax_c); - _unix_unlink(ded_u->pot_c); - _unix_file_free(ded_u); - free(ded_u->pot_c); - - free(pox_c); - free(pot_c); - free(pux_c); - free(put_c); - } - else if (u3_nul == mim) { - // uL(fprintf(uH, "file already gone: %s\n", pox_c)); // fires too often - - free(pox_c); - free(pot_c); - free(pux_c); - free(put_c); - } - else { - c3_c* pax_c; - c3_c* pat_c; - - if ( *fil_u ) { - _unix_unlink((*fil_u)->pax_c); - free((*fil_u)->pax_c); - _unix_unlink((*fil_u)->pot_c); - free((*fil_u)->pot_c); - } - -#if 0 - if ( c3y == u3du(god) ) { - pax_c = pux_c; free(pox_c); - pat_c = put_c; free(pot_c); - } else { -#endif - pax_c = pox_c; free(pux_c); - pat_c = pot_c; free(put_c); -#if 0 - } -#endif - -#ifdef SYNCLOG - u3_Host.unx_u.sylo[slot].unx = c3n; - u3_Host.unx_u.sylo[slot].wer_m = c3_s4('t','o','f','u'); - u3_Host.unx_u.sylo[slot].wot_m = u3h(mis); - u3_Host.unx_u.sylo[slot].pax_c = strdup(pax_c); -#endif - - _unix_save(pax_c, u3k(u3t(mim))); - _unix_save(pat_c, u3k(u3t(mim))); - - if ( *fil_u ) { - (*fil_u)->dot_c = (pax_c + ((*fil_u)->dot_c - (*fil_u)->pax_c)); - (*fil_u)->pax_c = pax_c; - (*fil_u)->pot_c = pat_c; - - u3r_words(0, 4, (*fil_u)->mod_w, u3A->now); - } - else { - c3_w mod_w[4]; - - u3r_words(0, 4, mod_w, u3A->now); - *fil_u = c3_malloc(sizeof(u3_ufil)); - - _unix_file_watch(*fil_u, dir_u, pax_c, pat_c, mod_w); - } - } - - u3z(pre); u3z(ext); u3z(mim); -} - -/* _unix_desk_sync_tako(): sync out change. -*/ -static void -_unix_desk_sync_tako(u3_udir* dir_u, u3_noun pax, u3_noun mim) -{ - if ( (c3n == u3du(pax)) ) { - c3_assert(!"tack"); - } - else if ( c3n == u3du(u3t(pax)) ) { // at toplevel - u3_noun i_pax = u3h(pax); - u3_noun t_pax = u3t(pax); - c3_c* par_u = strrchr(dir_u->pax_c, '/') + 1; - u3_noun pem = u3i_string(par_u); - c3_assert( u3_nul == t_pax ); // XX ugly, wrong - - _unix_desk_sync_tofu(dir_u->par_u, pem, u3k(i_pax), mim); - } - else { - u3_noun i_pax = u3h(pax); - u3_noun t_pax = u3t(pax); - u3_noun it_pax = u3h(t_pax); - u3_noun tt_pax = u3t(t_pax); - - if ( u3_nul == tt_pax ) { - _unix_desk_sync_tofu(dir_u, u3k(i_pax), u3k(it_pax), mim); - } - else { - u3_udir** dis_u = _unix_pdir(dir_u, u3k(i_pax)); - - if ( !*dis_u ) { - *dis_u = c3_malloc(sizeof(u3_udir)); - - _unix_dir_forge(*dis_u, dir_u, u3k(i_pax)); - } - _unix_desk_sync_tako(*dis_u, u3k(t_pax), mim); - } - } - u3z(pax); -} - -/* _unix_desk_sync_list(): sync computed changes. -*/ -static void -_unix_desk_sync_list(u3_udir* dir_u, u3_noun can) -{ - u3_noun nac = can; - - while ( u3_nul != nac ) { - _unix_desk_sync_tako(dir_u, u3k(u3h(u3h(nac))), u3k(u3t(u3h(nac)))); - nac = u3t(nac); - } - - u3z(can); -} -#endif - -/* _unix_desk_sync_ergo(): sync desk changes to unix. -*/ -static void -_unix_desk_sync_ergo(u3_noun hox, - u3_noun syd, - u3_noun lok, - u3_noun can, - u3_uhot* hot_u) -{ -#ifndef ERGO_SYNC - u3z(hox); u3z(syd); u3z(lok); u3z(can); -#else - - u3_udir** dir_u = _unix_pdir(&(hot_u->dir_u), u3k(syd)); - -#if 0 - uL(fprintf(uH, "ergo %s %s %s\n", u3r_string(hox), - u3r_string(syd), - u3r_string(lok))); -#endif - - if ( !*dir_u ) { - *dir_u = c3_malloc(sizeof(u3_udir)); - - _unix_dir_forge(*dir_u, &(hot_u->dir_u), u3k(syd)); - } - - _unix_desk_sync_list(*dir_u, can); - u3z(lok); u3z(syd); u3z(hox); - -#endif -} - -/* u3_unix_ef_init(): update filesystem for new acquisition. -*/ -void -u3_unix_ef_init(u3_noun who) -{ - _unix_hot_gain(u3k(who), c3y); - - u3v_plan(u3nq(u3_blip, c3__sync, u3k(u3A->sen), u3_nul), - u3nq(c3__into, who, - u3_blip, - u3nc(u3_nul, u3_nul))); -} - -/* u3_unix_ef_ergo(): update filesystem, outbound. -*/ -void -u3_unix_ef_ergo(u3_noun who, - u3_noun syd, - u3_noun rel, - u3_noun can) -{ - u3_noun hox = u3dc("scot", 'p', u3k(who)); // XXX unnecessary? - u3_noun lok = u3dc("scot", c3__ud, rel); // XXX unnecessary? - u3_uhot* hot_u; - - hot_u = _unix_home(who); - u3z(who); - - if ( 0 != hot_u ) { - _unix_desk_sync_ergo(hox, syd, lok, can, hot_u); - } - else - { - u3z(syd); u3z(syd); u3z(rel); u3z(can); - } -} - -/* u3_unix_ef_look(): update the root. -*/ -void -u3_unix_ef_look(void) -{ - u3_unix* unx_u = &u3_Host.unx_u; - u3_noun won; - u3_uhot* hot_u; - - if ( u3_nul != u3A->roe ) { - // We can't generate a working %into event here because there - // are other events, possibly containing %into, that are queued; - // they will change the state of %clay and cause a patch that - // doesn't work. - // - return; - } - - // find owners without directories - { - for ( won = u3A->own; u3_nul != won; won = u3t(won) ) { - u3_noun who = u3h(won); - c3_w who_w[4]; - - _unix_ship_out(who, who_w); - for ( hot_u = unx_u->hot_u; - hot_u && !_(_unix_ship_sing(who_w, hot_u->who_w)); - hot_u = hot_u->nex_u ); - - if ( 0 == hot_u ) { - _unix_hot_gain(u3k(who), c3n); - } - } - } - - // find directories without owners - { - u3_uhot** het_u = &(unx_u->hot_u); - - while ( 0 != (hot_u=*het_u) ) { - for ( won = u3A->own; u3_nul != won; won = u3t(won) ) { - u3_noun who = u3h(won); - c3_w who_w[4]; - - _unix_ship_out(who, who_w); - if ( _(_unix_ship_sing(who_w, hot_u->who_w)) ) { - break; - } - } - - if ( u3_nul == won ) { - *het_u = hot_u->nex_u; - - // uL(fprintf(uH, "sync: lose %s\n", hot_u->dir_u.pax_c)); - _unix_hot_lose(hot_u); - - free(hot_u); - continue; - } - else { - het_u = &(hot_u->nex_u); - } - } - } - - // update all ships - { - u3_uhot* hot_u; - - for ( hot_u = unx_u->hot_u; hot_u; hot_u = hot_u->nex_u ) { - _unix_ship_update(hot_u); - } - } -} - -/* _unix_ef_sync(): check for files to sync. - */ -static void -_unix_ef_sync(uv_check_t* han_u) -{ - u3_lo_open(); - u3_lo_shut(c3y); -} - -/* _unix_sign_cb: signal callback. -*/ -static void -_unix_sign_cb(uv_signal_t* sil_u, c3_i num_i) -{ - u3_lo_open(); - { - switch ( num_i ) { - default: fprintf(stderr, "\r\nmysterious signal %d\r\n", num_i); break; - - case SIGTERM: - fprintf(stderr, "\r\ncaught signal %d\r\n", num_i); - u3_Host.liv = c3n; - break; - case SIGINT: - fprintf(stderr, "\r\ninterrupt\r\n"); - u3_term_ef_ctlc(); - break; - case SIGWINCH: u3_term_ef_winc(); break; - // case SIGCHLD: u3_save_ef_chld(); break; - } - } - u3_lo_shut(c3y); -} - -/* u3_unix_ef_hold() -*/ -void -u3_unix_ef_hold(void) -{ - u3_unix* unx_u = &u3_Host.unx_u; - u3_usig* sig_u; - - for ( sig_u = unx_u->sig_u; sig_u; sig_u = sig_u->nex_u ) { - uv_signal_stop(&sig_u->sil_u); - } -} - /* u3_unix_ef_move() */ void @@ -1649,48 +642,16 @@ u3_unix_ef_move(void) } } -/* u3_unix_io_init(): initialize unix sync. +/* u3_unix_ef_look(): update the root. */ void -u3_unix_io_init(void) +u3_unix_ef_look(void) { - u3_unix* unx_u = &u3_Host.unx_u; + u3_umon* mon_u; - { - u3_usig* sig_u; - - sig_u = c3_malloc(sizeof(u3_usig)); - uv_signal_init(u3L, &sig_u->sil_u); - - sig_u->num_i = SIGTERM; - sig_u->nex_u = unx_u->sig_u; - unx_u->sig_u = sig_u; + for ( mon_u = u3_Host.unx_u->mon_u; mon_u; mon_u = mon_u->nex_u ) { + _unix_mount_update(mon_u); } - { - u3_usig* sig_u; - - sig_u = c3_malloc(sizeof(u3_usig)); - uv_signal_init(u3L, &sig_u->sil_u); - - sig_u->num_i = SIGINT; - sig_u->nex_u = unx_u->sig_u; - unx_u->sig_u = sig_u; - } - { - u3_usig* sig_u; - - sig_u = c3_malloc(sizeof(u3_usig)); - uv_signal_init(u3L, &sig_u->sil_u); - - sig_u->num_i = SIGWINCH; - sig_u->nex_u = unx_u->sig_u; - unx_u->sig_u = sig_u; - } -#if SYNCLOG - unx_u->lot_w = 0; - memset(unx_u->sylo, 0, sizeof(unx_u->sylo)); -#endif - uv_check_init(u3_Host.lup_u, &u3_Host.unx_u.syn_u); } /* u3_unix_io_talk(): start listening for fs events. @@ -1710,19 +671,6 @@ u3_unix_io_exit(void) { uv_check_stop(&u3_Host.unx_u.syn_u); u3_unix_release(u3_Host.dir_c); - - { - u3_uhot* hot_u; - - for ( hot_u = u3_Host.unx_u.hot_u; hot_u; hot_u = hot_u->nex_u ) { - u3_unix_release(hot_u->dir_u.pax_c); - } - } -#ifdef SYNCLOG - for (int i = 0; i<1024; i++) { - free(u3_Host.unx_u.sylo[i].pax_c); - } -#endif } /* u3_unix_io_poll(): update unix IO state. @@ -1731,3 +679,4 @@ void u3_unix_io_poll(void) { } +