diff --git a/pkg/urbit/compat/mingw/compat.c b/pkg/urbit/compat/mingw/compat.c index a15436d47..4c53e0a23 100644 --- a/pkg/urbit/compat/mingw/compat.c +++ b/pkg/urbit/compat/mingw/compat.c @@ -350,8 +350,9 @@ intmax_t mdb_get_filesize(HANDLE han_u) char *realpath(const char *path, char *resolved_path) { - // TODO - return strdup(path); + // XX MAX_PATH + // + return _fullpath(resolved_path, path, MAX_PATH); } long sysconf(int name) diff --git a/pkg/urbit/compat/mingw/daemon.c b/pkg/urbit/compat/mingw/daemon.c index 0220cb75a..46e73b0ea 100644 --- a/pkg/urbit/compat/mingw/daemon.c +++ b/pkg/urbit/compat/mingw/daemon.c @@ -10,7 +10,7 @@ _dup_std_handle(HANDLE* new_u, DWORD typ_u) HANDLE han_u = GetStdHandle(typ_u); BOOL con_u = GetConsoleMode(han_u, &dum_u); if ( con_u ) { - han_u = (HANDLE)_get_osfhandle(open(c3_dev_null, O_RDWR, 0)); + han_u = (HANDLE)_get_osfhandle(c3_open(c3_dev_null, O_RDWR, 0)); } if ( !DuplicateHandle(GetCurrentProcess(), han_u, GetCurrentProcess(), new_u, 0, TRUE, DUPLICATE_SAME_ACCESS) ) { diff --git a/pkg/urbit/daemon/main.c b/pkg/urbit/daemon/main.c index aefc0fe92..3dd71af1d 100644 --- a/pkg/urbit/daemon/main.c +++ b/pkg/urbit/daemon/main.c @@ -55,6 +55,44 @@ _main_presig(c3_c* txt_c) return new_c; } +/* _main_repath(): canonicalize path, using dirname if needed. +*/ +c3_c* +_main_repath(c3_c* pax_c) +{ + c3_c* rel_c; + c3_c* fas_c; + c3_c* dir_c; + c3_w len_w; + c3_i wit_i; + + c3_assert(pax_c); + if ( 0 != (rel_c = realpath(pax_c, 0)) ) { + return rel_c; + } + fas_c = strrchr(pax_c, '/'); + if ( !fas_c ) { + c3_c rec_c[2048]; + + wit_i = snprintf(rec_c, sizeof(rec_c), "./%s", pax_c); + c3_assert(sizeof(rec_c) > wit_i); + return _main_repath(rec_c); + } + c3_assert(u3_unix_cane(fas_c + 1)); + *fas_c = 0; + dir_c = realpath(pax_c, 0); + *fas_c = '/'; + if ( 0 == dir_c ) { + return 0; + } + len_w = strlen(dir_c) + strlen(fas_c) + 1; + rel_c = c3_malloc(len_w); + wit_i = snprintf(rel_c, len_w, "%s%s", dir_c, fas_c); + c3_assert(len_w == wit_i + 1); + c3_free(dir_c); + return rel_c; +} + /* _main_getopt(): extract option map from command line. */ static u3_noun @@ -139,7 +177,7 @@ _main_getopt(c3_i argc, c3_c** argv) break; } case 'Y': { - u3_Host.ops_u.puk_c = strdup(optarg); + u3_Host.ops_u.puk_c = _main_repath(optarg); break; } case 'Z': { @@ -147,11 +185,11 @@ _main_getopt(c3_i argc, c3_c** argv) break; } case 'J': { - u3_Host.ops_u.lit_c = strdup(optarg); + u3_Host.ops_u.lit_c = _main_repath(optarg); break; } case 'B': { - u3_Host.ops_u.pil_c = strdup(optarg); + u3_Host.ops_u.pil_c = _main_repath(optarg); break; } case 'b': { @@ -163,7 +201,7 @@ _main_getopt(c3_i argc, c3_c** argv) break; } case 'A': { - u3_Host.ops_u.arv_c = strdup(optarg); + u3_Host.ops_u.arv_c = _main_repath(optarg); break; } case 'H': { @@ -171,7 +209,7 @@ _main_getopt(c3_i argc, c3_c** argv) break; } case 'I': { - u3_Host.ops_u.jin_c = strdup(optarg); + u3_Host.ops_u.jin_c = _main_repath(optarg); break; } case 'C': { @@ -209,7 +247,7 @@ _main_getopt(c3_i argc, c3_c** argv) break; } case 'k': { - u3_Host.ops_u.key_c = strdup(optarg); + u3_Host.ops_u.key_c = _main_repath(optarg); break; } case 'n': { @@ -231,7 +269,7 @@ _main_getopt(c3_i argc, c3_c** argv) break; } case 'i': { - u3_Host.ops_u.imp_c = strdup(optarg); + u3_Host.ops_u.imp_c = _main_repath(optarg); break; } case 'L': { u3_Host.ops_u.net = c3n; break; } @@ -291,7 +329,7 @@ _main_getopt(c3_i argc, c3_c** argv) } } - u3_Host.dir_c = strdup(argv[optind]); + u3_Host.dir_c = _main_repath(argv[optind]); } // daemon mode (-d) implies disabling terminal assumptions (-t) @@ -705,31 +743,7 @@ main(c3_i argc, printf("~\n"); // printf("welcome.\n"); printf("urbit %s\n", URBIT_VERSION); - - // prints the absolute path of the pier - // - c3_c* abs_c = realpath(u3_Host.dir_c, 0); - - // if the ship is being booted, we use realpath(). Otherwise, we use getcwd() - // with a memory-allocation loop - // - if (abs_c == NULL) { - c3_i mprint_i = 1000; - abs_c = c3_malloc(mprint_i); - - // allocates more memory as needed if the path is too large - // - while ( abs_c != getcwd(abs_c, mprint_i) ) { - c3_free(abs_c); - mprint_i *= 2; - abs_c = c3_malloc(mprint_i); - } - printf("boot: home is %s/%s\n", abs_c, u3_Host.dir_c); - c3_free(abs_c); - } else { - printf("boot: home is %s\n", abs_c); - c3_free(abs_c); - } + printf("boot: home is %s\n", u3_Host.dir_c); // printf("vere: hostname is %s\n", u3_Host.ops_u.nam_c); if ( c3y == u3_Host.ops_u.dem ) { diff --git a/pkg/urbit/include/c/defs.h b/pkg/urbit/include/c/defs.h index 245bfcf2f..54f28a1b1 100644 --- a/pkg/urbit/include/c/defs.h +++ b/pkg/urbit/include/c/defs.h @@ -122,4 +122,35 @@ } \ rut;}) + /* Asserting unix fs wrappers. + ** + ** these all crash the process if passed a non-canonical + ** path (i.e., one containing '.', '..', or the empty path + ** component), so make sure you don't pass them one. if you + ** find yourself fighting with them, then please delete them + ** and do a sed search-and-replace to remove the `c3_` from + ** their call sites; their goal is to decrease maintenance + ** burden, not increase it. + */ + // defined in vere/io/unix.c. + c3_t u3_unix_cane(const c3_c* pax_c); +# define c3_open(a, ...) ({ \ + c3_assert(u3_unix_cane(a)); \ + open(a, __VA_ARGS__);}) +# define c3_opendir(a) ({ \ + c3_assert(u3_unix_cane(a)); \ + opendir(a);}) +# define c3_mkdir(a, b) ({ \ + c3_assert(u3_unix_cane(a)); \ + mkdir(a, b);}) +# define c3_rmdir(a) ({ \ + c3_assert(u3_unix_cane(a)); \ + rmdir(a);}) +# define c3_unlink(a) ({ \ + c3_assert(u3_unix_cane(a)); \ + unlink(a);}) +# define c3_fopen(a, b) ({ \ + c3_assert(u3_unix_cane(a)); \ + fopen(a, b);}) + #endif /* ifndef C3_DEFS_H */ diff --git a/pkg/urbit/include/noun/imprison.h b/pkg/urbit/include/noun/imprison.h index c68088eee..2123fb813 100644 --- a/pkg/urbit/include/noun/imprison.h +++ b/pkg/urbit/include/noun/imprison.h @@ -127,12 +127,12 @@ /* u3i_string(): Produce an LSB-first atom from the C string [a]. */ - u3_noun + u3_atom u3i_string(const c3_c* a_c); /* u3i_tape(): from a C string, to a list of bytes. */ - u3_atom + u3_noun u3i_tape(const c3_c* txt_c); /* u3i_list(): list from `u3_none`-terminated varargs. diff --git a/pkg/urbit/include/vere/vere.h b/pkg/urbit/include/vere/vere.h index 64eea8eac..f835c60be 100644 --- a/pkg/urbit/include/vere/vere.h +++ b/pkg/urbit/include/vere/vere.h @@ -328,7 +328,7 @@ void (*bot_f)(); // call when chis is up } u3_host; // host == computer == process - /** New pier system. + /** Pier system. **/ /* u3_ovum_news: u3_ovum lifecycle events */ @@ -755,7 +755,7 @@ c3_d u3_time_gap_ms(u3_noun now, u3_noun wen); - /** ward: common structure lifecycle + /** Common structure lifecycle. **/ /* u3_dent_init(): initialize file record. */ @@ -840,7 +840,7 @@ c3_w u3_mcut_host(c3_c* buf_c, c3_w len_w, u3_noun hot); - /** New vere + /** IO drivers. **/ /* u3_auto_init(): initialize all drivers. */ @@ -1034,41 +1034,14 @@ void u3_lord_peek(u3_lord* god_u, u3_pico* pic_u); - /** Filesystem (new api). - **/ - /* u3_walk_load(): load file or bail. - */ - u3_noun - u3_walk_load(c3_c* pas_c); - - /* u3_walk_safe(): load file or 0. - */ - u3_noun - u3_walk_safe(c3_c* pas_c); - - /* u3_walk_save(): save file or bail. - */ - void - u3_walk_save(c3_c* pas_c, u3_noun tim, u3_atom pad, c3_c* bas_c, u3_noun pax); - - /* u3_walk(): traverse `dir_c` to produce an arch, updating `old`. - */ - u3_noun - u3_walk(const c3_c* dir_c, u3_noun old); - - /* u3_path(): C unix path in computer for file or directory. - */ - c3_c* - u3_path(c3_o fyl, u3_noun pax); - - /** Filesystem (async) + /** Filesystem (async). **/ /* u3_foil_folder(): load directory, blockingly. create if nonexistent. */ u3_dire* u3_foil_folder(const c3_c* pax_c); // directory object, or 0 - /** Terminal, new style. + /** Terminal. **/ /* u3_term_start_spinner(): prepare spinner state. RETAIN. */ @@ -1166,8 +1139,18 @@ u3_save_io_exit(u3_pier *pir_u); - /** Storage, new school. + /** Storage. **/ + /* u3_unix_save(): save file undir .../.urb/put or bail. + */ + void + u3_unix_save(c3_c* pax_c, u3_atom pad); + + /* u3_unix_cane(): true iff (unix) path is canonical. + */ + c3_t + u3_unix_cane(const c3_c* pax_c); + /* u3_unix_initial_into_card(): create initial filesystem sync card. */ u3_noun @@ -1199,14 +1182,14 @@ u3_auto* u3_cttp_io_init(u3_pier* pir_u); - /** fore, first events + /** fore, first events. **/ /* u3_hind_io_init(): initialize fore */ u3_auto* u3_fore_io_init(u3_pier* pir_u); - /** hind, defaults + /** hind, defaults. **/ /* u3_hind_io_init(): initialize hint */ @@ -1309,7 +1292,7 @@ void u3_pier_info(u3_pier* pir_u); - /* u3_pier_boot(): start the new pier system. + /* u3_pier_boot(): start the pier. */ u3_pier* u3_pier_boot(c3_w wag_w, // config flags @@ -1319,7 +1302,7 @@ u3_noun pax, // path to pier u3_weak fed); // extra private keys - /* u3_pier_stay(): restart the new pier system. + /* u3_pier_stay(): restart the pier. */ u3_pier* u3_pier_stay(c3_w wag_w, u3_noun pax); diff --git a/pkg/urbit/noun/events.c b/pkg/urbit/noun/events.c index 214e228d2..e37fdf0ee 100644 --- a/pkg/urbit/noun/events.c +++ b/pkg/urbit/noun/events.c @@ -239,17 +239,17 @@ _ce_image_open(u3e_image* img_u) c3_c ful_c[8193]; snprintf(ful_c, 8192, "%s", u3P.dir_c); - mkdir(ful_c, 0700); + c3_mkdir(ful_c, 0700); snprintf(ful_c, 8192, "%s/.urb", u3P.dir_c); - mkdir(ful_c, 0700); + c3_mkdir(ful_c, 0700); snprintf(ful_c, 8192, "%s/.urb/chk", u3P.dir_c); - mkdir(ful_c, 0700); + c3_mkdir(ful_c, 0700); snprintf(ful_c, 8192, "%s/.urb/chk/%s.bin", u3P.dir_c, img_u->nam_c); - if ( -1 == (img_u->fid_i = open(ful_c, mod_i, 0666)) ) { - fprintf(stderr, "loom: open %s: %s\r\n", ful_c, strerror(errno)); + if ( -1 == (img_u->fid_i = c3_open(ful_c, mod_i, 0666)) ) { + fprintf(stderr, "loom: c3_open %s: %s\r\n", ful_c, strerror(errno)); return c3n; } else { @@ -333,20 +333,20 @@ _ce_patch_create(u3_ce_patch* pat_u) c3_c ful_c[8193]; snprintf(ful_c, 8192, "%s", u3P.dir_c); - mkdir(ful_c, 0700); + c3_mkdir(ful_c, 0700); snprintf(ful_c, 8192, "%s/.urb", u3P.dir_c); - mkdir(ful_c, 0700); + c3_mkdir(ful_c, 0700); snprintf(ful_c, 8192, "%s/.urb/chk/control.bin", u3P.dir_c); - if ( -1 == (pat_u->ctl_i = open(ful_c, O_RDWR | O_CREAT | O_EXCL, 0600)) ) { - fprintf(stderr, "loom: patch open control.bin: %s\r\n", strerror(errno)); + if ( -1 == (pat_u->ctl_i = c3_open(ful_c, O_RDWR | O_CREAT | O_EXCL, 0600)) ) { + fprintf(stderr, "loom: patch c3_open control.bin: %s\r\n", strerror(errno)); c3_assert(0); } snprintf(ful_c, 8192, "%s/.urb/chk/memory.bin", u3P.dir_c); - if ( -1 == (pat_u->mem_i = open(ful_c, O_RDWR | O_CREAT | O_EXCL, 0600)) ) { - fprintf(stderr, "loom: patch open memory.bin: %s\r\n", strerror(errno)); + if ( -1 == (pat_u->mem_i = c3_open(ful_c, O_RDWR | O_CREAT | O_EXCL, 0600)) ) { + fprintf(stderr, "loom: patch c3_open memory.bin: %s\r\n", strerror(errno)); c3_assert(0); } } @@ -359,10 +359,10 @@ _ce_patch_delete(void) c3_c ful_c[8193]; snprintf(ful_c, 8192, "%s/.urb/chk/control.bin", u3P.dir_c); - unlink(ful_c); + c3_unlink(ful_c); snprintf(ful_c, 8192, "%s/.urb/chk/memory.bin", u3P.dir_c); - unlink(ful_c); + c3_unlink(ful_c); } /* _ce_patch_verify(): check patch data mug. @@ -431,18 +431,18 @@ _ce_patch_open(void) c3_i ctl_i, mem_i; snprintf(ful_c, 8192, "%s", u3P.dir_c); - mkdir(ful_c, 0700); + c3_mkdir(ful_c, 0700); snprintf(ful_c, 8192, "%s/.urb", u3P.dir_c); - mkdir(ful_c, 0700); + c3_mkdir(ful_c, 0700); snprintf(ful_c, 8192, "%s/.urb/chk/control.bin", u3P.dir_c); - if ( -1 == (ctl_i = open(ful_c, O_RDWR)) ) { + if ( -1 == (ctl_i = c3_open(ful_c, O_RDWR)) ) { return 0; } snprintf(ful_c, 8192, "%s/.urb/chk/memory.bin", u3P.dir_c); - if ( -1 == (mem_i = open(ful_c, O_RDWR)) ) { + if ( -1 == (mem_i = c3_open(ful_c, O_RDWR)) ) { close(ctl_i); _ce_patch_delete(); @@ -838,7 +838,7 @@ _ce_backup(void) snprintf(ful_c, 8192, "%s/.urb/bhk", u3P.dir_c); - if ( mkdir(ful_c, 0700) ) { + if ( c3_mkdir(ful_c, 0700) ) { if ( EEXIST != errno ) { fprintf(stderr, "loom: image backup: %s\r\n", strerror(errno)); } @@ -847,15 +847,15 @@ _ce_backup(void) snprintf(ful_c, 8192, "%s/.urb/bhk/%s.bin", u3P.dir_c, nop_u.nam_c); - if ( -1 == (nop_u.fid_i = open(ful_c, mod_i, 0666)) ) { - fprintf(stderr, "loom: open %s: %s\r\n", ful_c, strerror(errno)); + if ( -1 == (nop_u.fid_i = c3_open(ful_c, mod_i, 0666)) ) { + fprintf(stderr, "loom: c3_open %s: %s\r\n", ful_c, strerror(errno)); return; } snprintf(ful_c, 8192, "%s/.urb/bhk/%s.bin", u3P.dir_c, sop_u.nam_c); - if ( -1 == (sop_u.fid_i = open(ful_c, mod_i, 0666)) ) { - fprintf(stderr, "loom: open %s: %s\r\n", ful_c, strerror(errno)); + if ( -1 == (sop_u.fid_i = c3_open(ful_c, mod_i, 0666)) ) { + fprintf(stderr, "loom: c3_open %s: %s\r\n", ful_c, strerror(errno)); return; } @@ -863,11 +863,11 @@ _ce_backup(void) || (c3n == _ce_image_copy(&u3P.sou_u, &sop_u)) ) { - unlink(ful_c); + c3_unlink(ful_c); snprintf(ful_c, 8192, "%s/.urb/bhk/%s.bin", u3P.dir_c, nop_u.nam_c); - unlink(ful_c); + c3_unlink(ful_c); snprintf(ful_c, 8192, "%s/.urb/bhk", u3P.dir_c); - rmdir(ful_c); + c3_rmdir(ful_c); } close(nop_u.fid_i); diff --git a/pkg/urbit/noun/imprison.c b/pkg/urbit/noun/imprison.c index 77feae7f6..b34b9d884 100644 --- a/pkg/urbit/noun/imprison.c +++ b/pkg/urbit/noun/imprison.c @@ -541,7 +541,7 @@ u3i_qual(u3_noun a, u3_noun b, u3_noun c, u3_noun d) /* u3i_string(): Produce an LSB-first atom from the C string [a]. */ -u3_noun +u3_atom u3i_string(const c3_c* a_c) { return u3i_bytes(strlen(a_c), (c3_y *)a_c); @@ -549,7 +549,7 @@ u3i_string(const c3_c* a_c) /* u3i_tape(): from a C string, to a list of bytes. */ -u3_atom +u3_noun u3i_tape(const c3_c* txt_c) { if ( !*txt_c ) { diff --git a/pkg/urbit/noun/manage.c b/pkg/urbit/noun/manage.c index f6e692824..e424d33ab 100644 --- a/pkg/urbit/noun/manage.c +++ b/pkg/urbit/noun/manage.c @@ -432,7 +432,7 @@ u3_noun u3m_file(c3_c* pas_c) { struct stat buf_b; - c3_i fid_i = open(pas_c, O_RDONLY, 0644); + c3_i fid_i = c3_open(pas_c, O_RDONLY, 0644); c3_w fln_w, red_w; c3_y* pad_y; diff --git a/pkg/urbit/noun/trace.c b/pkg/urbit/noun/trace.c index 887a1b1c7..79d290930 100644 --- a/pkg/urbit/noun/trace.c +++ b/pkg/urbit/noun/trace.c @@ -282,13 +282,13 @@ u3t_trace_open(c3_c* dir_c) struct stat st; if ( -1 == stat(fil_c, &st) ) { - mkdir(fil_c, 0700); + c3_mkdir(fil_c, 0700); } c3_c lif_c[2056]; snprintf(lif_c, 2056, "%s/%d.json", fil_c, u3_Host.tra_u.fun_w); - u3_Host.tra_u.fil_u = fopen(lif_c, "w"); + u3_Host.tra_u.fil_u = c3_fopen(lif_c, "w"); u3_Host.tra_u.nid_w = (int)getpid(); fprintf(u3_Host.tra_u.fil_u, "[ "); diff --git a/pkg/urbit/noun/urth.c b/pkg/urbit/noun/urth.c index f6df4910f..30ab44817 100644 --- a/pkg/urbit/noun/urth.c +++ b/pkg/urbit/noun/urth.c @@ -509,7 +509,7 @@ _cu_rock_path_make(c3_c* dir_c, c3_d eve_d, c3_c** out_c) return c3n; } - if ( mkdir(nam_c, 0700) + if ( c3_mkdir(nam_c, 0700) && (EEXIST != errno) ) { fprintf(stderr, "rock: directory create failed (%s, %" PRIu64 "): %s\r\n", @@ -552,8 +552,8 @@ _cu_rock_save(c3_c* dir_c, c3_d eve_d, c3_d len_d, c3_y* byt_y) return c3n; } - if ( -1 == (fid_i = open(nam_c, O_RDWR | O_CREAT | O_TRUNC, 0644)) ) { - fprintf(stderr, "rock: open failed (%s, %" PRIu64 "): %s\r\n", + if ( -1 == (fid_i = c3_open(nam_c, O_RDWR | O_CREAT | O_TRUNC, 0644)) ) { + fprintf(stderr, "rock: c3_open failed (%s, %" PRIu64 "): %s\r\n", dir_c, eve_d, strerror(errno)); c3_free(nam_c); return c3n; @@ -691,8 +691,8 @@ u3u_mmap_read(c3_c* cap_c, c3_c* pat_c, c3_d* out_d, c3_y** out_y) // open file // - if ( -1 == (fid_i = open(pat_c, O_RDONLY, 0644)) ) { - fprintf(stderr, "%s: open failed (%s): %s\r\n", + if ( -1 == (fid_i = c3_open(pat_c, O_RDONLY, 0644)) ) { + fprintf(stderr, "%s: c3_open failed (%s): %s\r\n", cap_c, pat_c, strerror(errno)); return c3n; } @@ -744,8 +744,8 @@ u3u_mmap(c3_c* cap_c, c3_c* pat_c, c3_d len_d, c3_y** out_y) // open file // - if ( -1 == (fid_i = open(pat_c, O_RDWR | O_CREAT | O_TRUNC, 0644)) ) { - fprintf(stderr, "%s: open failed (%s): %s\r\n", + if ( -1 == (fid_i = c3_open(pat_c, O_RDWR | O_CREAT | O_TRUNC, 0644)) ) { + fprintf(stderr, "%s: c3_open failed (%s): %s\r\n", cap_c, pat_c, strerror(errno)); return c3n; } @@ -895,7 +895,7 @@ u3u_uncram(c3_c* dir_c, c3_d eve_d) // leave rocks on disk // - // if ( 0 != unlink(nam_c) ) { + // if ( 0 != c3_unlink(nam_c) ) { // fprintf(stderr, "uncram: failed to delete rock (%s, %" PRIu64 "): %s\r\n", // dir_c, eve_d, strerror(errno)); // c3_free(nam_c); diff --git a/pkg/urbit/tests/unix_tests.c b/pkg/urbit/tests/unix_tests.c new file mode 100644 index 000000000..ca247f5ef --- /dev/null +++ b/pkg/urbit/tests/unix_tests.c @@ -0,0 +1,65 @@ +#include "all.h" +#include "vere/vere.h" + +/* _setup(): prepare for tests. +*/ +static void +_setup(void) +{ +} + +/* _test_safe(): +*/ +static c3_i +_test_safe() +{ + c3_i ret_i = 1; + + if ( !u3_unix_cane("/") || + !u3_unix_cane("~.") || + !u3_unix_cane("a") || + !u3_unix_cane("a/b") || + !u3_unix_cane("a/b/c/defg/h/ijklmnop") ) + { + fprintf(stderr, "_safe fail 1\n"); + ret_i = 0; + } + + if ( u3_unix_cane("") || + u3_unix_cane(".") || + u3_unix_cane("..") || + u3_unix_cane("/.") || + u3_unix_cane("a/b/c//") || + u3_unix_cane("a/b/.") || + u3_unix_cane("/././../.") || + u3_unix_cane("/../etc") ) + { + fprintf(stderr, "_safe fail 2\r\n"); + ret_i = 0; + } + + if ( !u3_unix_cane(".a") || + !u3_unix_cane("/.a.b.c/..c") ) + { + fprintf(stderr, "_safe fail 3\r\n"); + ret_i = 0; + } + + return ret_i; +} + +/* main(): run all test cases. +*/ +int +main(int argc, char* argv[]) +{ + _setup(); + + if ( !_test_safe() ) { + fprintf(stderr, "test unix: failed\r\n"); + exit(1); + } + + fprintf(stderr, "test unix: ok\r\n"); + return 0; +} diff --git a/pkg/urbit/vere/dawn.c b/pkg/urbit/vere/dawn.c index 6ad296341..ca6eb31a7 100644 --- a/pkg/urbit/vere/dawn.c +++ b/pkg/urbit/vere/dawn.c @@ -462,7 +462,7 @@ _dawn_come(u3_noun stars) c3_c pat_c[64]; snprintf(pat_c, 64, "%s.key", who_c + 1); - FILE* fil_u = fopen(pat_c, "w"); + FILE* fil_u = c3_fopen(pat_c, "w"); fprintf(fil_u, "%s\n", key_c); fclose(fil_u); } diff --git a/pkg/urbit/vere/db/lmdb.c b/pkg/urbit/vere/db/lmdb.c index a6acbba6d..308ba3783 100644 --- a/pkg/urbit/vere/db/lmdb.c +++ b/pkg/urbit/vere/db/lmdb.c @@ -42,6 +42,8 @@ u3_lmdb_init(const c3_c* pax_c, size_t siz_i) MDB_env* env_u; c3_w ret_w; + c3_assert(u3_unix_cane(pax_c)); + if ( (ret_w = mdb_env_create(&env_u)) ) { mdb_logerror(stderr, ret_w, "lmdb: init fail"); return 0; diff --git a/pkg/urbit/vere/disk.c b/pkg/urbit/vere/disk.c index a8dc413a1..13a208bda 100644 --- a/pkg/urbit/vere/disk.c +++ b/pkg/urbit/vere/disk.c @@ -585,6 +585,94 @@ u3_disk_read_meta(u3_disk* log_u, return c3y; } +/* _disk_lock(): lockfile path. +*/ +static c3_c* +_disk_lock(c3_c* pax_c) +{ + c3_w len_w = strlen(pax_c) + sizeof("/.vere.lock"); + c3_c* paf_c = c3_malloc(len_w); + c3_i wit_i; + + wit_i = snprintf(paf_c, len_w, "%s/.vere.lock", pax_c); + c3_assert(wit_i + 1 == len_w); + return paf_c; +} + +/* u3_disk_acquire(): acquire a lockfile, killing anything that holds it. +*/ +static void +u3_disk_acquire(c3_c* pax_c) +{ + c3_c* paf_c = _disk_lock(pax_c); + c3_w pid_w; + FILE* loq_u; + + if ( NULL != (loq_u = c3_fopen(paf_c, "r")) ) { + if ( 1 != fscanf(loq_u, "%" SCNu32, &pid_w) ) { + u3l_log("lockfile %s is corrupt!\n", paf_c); + kill(getpid(), SIGTERM); + sleep(1); c3_assert(0); + } + else if (pid_w != getpid()) { + c3_w i_w; + + if ( -1 != kill(pid_w, SIGTERM) ) { + u3l_log("disk: stopping process %d, live in %s...\n", + pid_w, pax_c); + + for ( i_w = 0; i_w < 16; i_w++ ) { + sleep(1); + if ( -1 == kill(pid_w, SIGTERM) ) { + break; + } + } + if ( 16 == i_w ) { + for ( i_w = 0; i_w < 16; i_w++ ) { + if ( -1 == kill(pid_w, SIGKILL) ) { + break; + } + sleep(1); + } + } + if ( 16 == i_w ) { + u3l_log("disk: process %d seems unkillable!\n", pid_w); + c3_assert(0); + } + u3l_log("disk: stopped old process %u\n", pid_w); + } + } + fclose(loq_u); + c3_unlink(paf_c); + } + + if ( NULL == (loq_u = c3_fopen(paf_c, "w")) ) { + u3l_log("disk: unable to open %s\n", paf_c); + c3_assert(0); + } + + fprintf(loq_u, "%u\n", getpid()); + + { + c3_i fid_i = fileno(loq_u); + c3_sync(fid_i); + } + + fclose(loq_u); + c3_free(paf_c); +} + +/* u3_disk_release(): release a lockfile. +*/ +static void +u3_disk_release(c3_c* pax_c) +{ + c3_c* paf_c = _disk_lock(pax_c); + + c3_unlink(paf_c); + c3_free(paf_c); +} + /* u3_disk_exit(): close the log. */ void @@ -633,6 +721,8 @@ u3_disk_exit(u3_disk* log_u) } } + u3_disk_release(log_u->dir_u->pax_c); + u3_dire_free(log_u->dir_u); u3_dire_free(log_u->urb_u); u3_dire_free(log_u->com_u); @@ -697,6 +787,10 @@ u3_disk_init(c3_c* pax_c, u3_disk_cb cb_u) } } + // acquire lockfile. + // + u3_disk_acquire(pax_c); + // create/load $pier/.urb // { @@ -721,11 +815,11 @@ u3_disk_init(c3_c* pax_c, u3_disk_cb cb_u) strcpy(dir_c, pax_c); strcat(dir_c, "/.urb/put"); - mkdir(dir_c, 0700); + c3_mkdir(dir_c, 0700); strcpy(dir_c, pax_c); strcat(dir_c, "/.urb/get"); - mkdir(dir_c, 0700); + c3_mkdir(dir_c, 0700); c3_free(dir_c); } diff --git a/pkg/urbit/vere/foil.c b/pkg/urbit/vere/foil.c index 1d844f5d4..f8a7c406a 100644 --- a/pkg/urbit/vere/foil.c +++ b/pkg/urbit/vere/foil.c @@ -84,6 +84,8 @@ u3_foil_folder(const c3_c* pax_c) uv_dirent_t den_u; c3_i err_i; + c3_assert(u3_unix_cane(pax_c)); + /* open directory, synchronously */ { diff --git a/pkg/urbit/vere/io/http.c b/pkg/urbit/vere/io/http.c index f0d2f0ea2..92352d427 100644 --- a/pkg/urbit/vere/io/http.c +++ b/pkg/urbit/vere/io/http.c @@ -1608,7 +1608,7 @@ _http_write_ports_file(u3_httd* htd_u, c3_c *pax_c) c3_c* paf_c = c3_malloc(len_w); snprintf(paf_c, len_w, "%s/%s", pax_c, nam_c); - c3_i por_i = open(paf_c, O_WRONLY | O_CREAT | O_TRUNC, 0666); + c3_i por_i = c3_open(paf_c, O_WRONLY | O_CREAT | O_TRUNC, 0666); c3_free(paf_c); u3_http* htp_u = htd_u->htp_u; @@ -1639,7 +1639,7 @@ _http_release_ports_file(c3_c *pax_c) c3_c* paf_c = c3_malloc(len_w); snprintf(paf_c, len_w, "%s/%s", pax_c, nam_c); - unlink(paf_c); + c3_unlink(paf_c); c3_free(paf_c); } diff --git a/pkg/urbit/vere/io/term.c b/pkg/urbit/vere/io/term.c index fcccf748a..f2eff77a4 100644 --- a/pkg/urbit/vere/io/term.c +++ b/pkg/urbit/vere/io/term.c @@ -549,14 +549,13 @@ _term_it_show_more(u3_utty* uty_u) /* _term_it_path(): path for console file. */ static c3_c* -_term_it_path(c3_o fyl, u3_noun pax) +_term_it_path(u3_noun pax) { - c3_w len_w; + c3_w len_w = 0; c3_c *pas_c; // measure // - len_w = strlen(u3_Host.dir_c); { u3_noun wiz = pax; @@ -569,7 +568,6 @@ _term_it_path(c3_o fyl, u3_noun pax) // cut // pas_c = c3_malloc(len_w + 1); - strncpy(pas_c, u3_Host.dir_c, len_w); pas_c[len_w] = '\0'; { u3_noun wiz = pax; @@ -578,7 +576,7 @@ _term_it_path(c3_o fyl, u3_noun pax) while ( u3_nul != wiz ) { c3_w tis_w = u3r_met(3, u3h(wiz)); - if ( (c3y == fyl) && (u3_nul == u3t(wiz)) ) { + if ( (u3_nul == u3t(wiz)) ) { *waq_c++ = '.'; } else *waq_c++ = '/'; @@ -598,27 +596,10 @@ _term_it_path(c3_o fyl, u3_noun pax) static void _term_it_save(u3_noun pax, u3_noun pad) { - c3_c* pax_c; - c3_c* bas_c = 0; - c3_w xap_w = u3kb_lent(u3k(pax)); - u3_noun xap = u3_nul; - u3_noun urb = c3_s4('.','u','r','b'); - u3_noun put = c3_s3('p','u','t'); - - // directory base and relative path - if ( 2 < xap_w ) { - u3_noun bas = u3nt(urb, put, u3_nul); - bas_c = _term_it_path(c3n, bas); - xap = u3qb_scag(xap_w - 2, pax); - } - - pax = u3nt(urb, put, pax); - pax_c = _term_it_path(c3y, pax); - - u3_walk_save(pax_c, 0, pad, bas_c, xap); + c3_c* pax_c = _term_it_path(pax); + u3_unix_save(pax_c, pad); c3_free(pax_c); - c3_free(bas_c); } /* _term_ovum_plan(): plan term ovums, configuring spinner. diff --git a/pkg/urbit/vere/io/unix.c b/pkg/urbit/vere/io/unix.c index 4526298bc..f9e175b5d 100644 --- a/pkg/urbit/vere/io/unix.c +++ b/pkg/urbit/vere/io/unix.c @@ -1,5 +1,36 @@ /* vere/unix.c ** +** this file is responsible for maintaining a bidirectional +** mapping between the contents of a clay desk and a directory +** in a unix filesystem. +** +** TODO this driver is crufty and overdue for a rewrite. +** aspirationally, the rewrite should do sanity checking and +** transformations at the noun level to convert messages from +** arvo into sets of fs operations on trusted inputs, and +** inverse transformations and checks for fs contents to arvo +** messages. +** +** the two relevant transformations to apply are: +** +** 1. bidirectionally map file contents to atoms +** 2. bidirectionally map arvo $path <-> unix relative paths +** +** the first transform is trivial. the second poses some +** challenges: an arvo $path is a list of $knot, and the $knot +** space intersects with invalid unix paths in the three cases +** of: %$ (the empty knot), '.', and '..'. we escape these by +** prepending a '!' to the filename corresponding to the $knot, +** yielding unix files named '!', '!.', and '!..'. +** +** there is also the case of the empty path. we elide empty +** paths from this wrapper, which always uses the last path +** component as the file extension/mime-type. +** +** these transforms are implemented, but they ought to be +** implemented in one place, prior to any fs calls; as-is, they +** are sprinkled throughout the file updating code. +** */ #include "all.h" #include @@ -58,6 +89,7 @@ struct _u3_ufil; c3_c* pax_c; // pier directory c3_o alm; // timer set c3_o dyr; // ready to update + u3_noun sat; // (sane %ta) handle #ifdef SYNCLOG c3_w lot_w; // sync-slot struct _u3_sylo { @@ -72,6 +104,50 @@ struct _u3_ufil; void u3_unix_ef_look(u3_unix* unx_u, u3_noun mon, u3_noun all); +/* u3_unix_cane(): true iff (unix) path is canonical. +*/ +c3_t +u3_unix_cane(const c3_c* pax_c) +{ + if ( 0 == pax_c ) { + return 0; + } + // allow absolute paths. + // + if ( '/' == *pax_c ) { + pax_c++; + // allow root. + // + if ( 0 == *pax_c ) { + return 1; + } + } + do { + if ( 0 == *pax_c + || 0 == strcmp(".", pax_c) + || 0 == strcmp("..", pax_c) + || 0 == strncmp("/", pax_c, 1) + || 0 == strncmp("./", pax_c, 2) + || 0 == strncmp("../", pax_c, 3) ) + { + return 0; + } + pax_c = strchr(pax_c, '/'); + } while ( 0 != pax_c++ ); + return 1; +} + +/* _unix_sane_ta(): true iff pat is a valid @ta +** +** %ta is parsed by: +** (star ;~(pose nud low hep dot sig cab)) +*/ +static c3_t +_unix_sane_ta(u3_unix* unx_u, u3_atom pat) +{ + return _(u3n_slam_on(u3k(unx_u->sat), pat)); +} + /* u3_readdir_r(): */ c3_w @@ -91,6 +167,56 @@ u3_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) return(0); } +/* _unix_string_to_knot(): convert c unix path component to $knot +*/ +static u3_atom +_unix_string_to_knot(c3_c* pax_c) +{ + c3_assert(pax_c); + // XX this can happen if we encounter a file without an extension. + // + // c3_assert(*pax_c); + c3_assert(!strchr(pax_c, '/')); + // XX horrible + // +# ifdef _WIN32 + c3_assert(!strchr(pax_c, '\\')); +# endif + if ( '!' == *pax_c ) { + pax_c++; + } + return u3i_string(pax_c); +} + +/* _unix_knot_to_string(): convert $knot to c unix path component. RETAIN. +*/ +static c3_c* +_unix_knot_to_string(u3_atom pon) +{ + c3_c* ret_c; + + if ( u3_nul != pon + && c3_s1('.') != pon + && c3_s2('.','.') != pon + && '!' != u3r_byte(0, pon) ) + { + ret_c = u3r_string(pon); + } + else { + c3_w met_w = u3r_met(3, pon); + + ret_c = c3_malloc(met_w + 2); + *ret_c = '!'; + u3r_bytes(0, met_w, (c3_y*)ret_c + 1, pon); + ret_c[met_w + 1] = 0; + } + c3_assert(!strchr(ret_c, '/')); +# ifdef _WIN32 + c3_assert(!strchr(ret_c, '\\')); +# endif + return ret_c; +} + /* _unix_down(): descend path. */ static c3_c* @@ -108,29 +234,34 @@ _unix_down(c3_c* pax_c, c3_c* sub_c) return don_c; } -/* _unix_string_to_path(): convert c string to u3_noun path - * - * c string must begin with the pier path plus mountpoint +/* _unix_string_to_path(): convert c string to u3_noun $path +** +** c string must begin with the pier path plus mountpoint */ static u3_noun _unix_string_to_path_helper(c3_c* pax_c) { + u3_noun not; + c3_assert(pax_c[-1] == '/'); - c3_c* end_w = strchr(pax_c, '/'); - if ( !end_w ) { - end_w = strrchr(pax_c, '.'); - if ( !end_w ) { - return u3nc(u3i_string(pax_c), u3_nul); + c3_c* end_c = strchr(pax_c, '/'); + if ( !end_c ) { + end_c = strrchr(pax_c, '.'); + if ( !end_c ) { + return u3nc(_unix_string_to_knot(pax_c), u3_nul); } else { - return u3nt(u3i_bytes(end_w - pax_c, (c3_y*) pax_c), - u3i_string(end_w + 1), - u3_nul); + *end_c = 0; + not = _unix_string_to_knot(pax_c); + *end_c = '.'; + return u3nt(not, _unix_string_to_knot(end_c + 1), u3_nul); } } else { - return u3nc(u3i_bytes(end_w - pax_c, (c3_y*) pax_c), - _unix_string_to_path_helper(end_w + 1)); + *end_c = 0; + not = _unix_string_to_knot(pax_c); + *end_c = '/'; + return u3nc(not, _unix_string_to_path_helper(end_c + 1)); } } static u3_noun @@ -144,7 +275,7 @@ _unix_string_to_path(u3_unix* unx_u, c3_c* pax_c) return u3_nul; } else { - return u3nc(u3i_string(pox_c + 1), u3_nul); + return u3nc(_unix_string_to_knot(pox_c + 1), u3_nul); } } else { @@ -152,6 +283,77 @@ _unix_string_to_path(u3_unix* unx_u, c3_c* pax_c) } } +/* _unix_mkdirp(): recursive mkdir of dirname of pax_c. +*/ +static void +_unix_mkdirp(c3_c* pax_c) +{ + c3_c* fas_c = strchr(pax_c + 1, '/'); + + while ( fas_c ) { + *fas_c = 0; + if ( 0 != mkdir(pax_c, 0777) && EEXIST != errno ) { + u3l_log("unix: mkdir %s: %s\n", pax_c, strerror(errno)); + u3m_bail(c3__fail); + } + *fas_c++ = '/'; + fas_c = strchr(fas_c, '/'); + } +} + +/* u3_unix_save(): save file under .../.urb/put or bail. +** +** XX this is quite bad, and doesn't share much in common with +** the rest of unix.c. a refactor would probably share common +** logic with _unix_sync_change, perhaps using openat, making +** unx_u optional, and/or having a flag to not track the file +** for future changes. +*/ +void +u3_unix_save(c3_c* pax_c, u3_atom pad) +{ + c3_i fid_i; + c3_w lod_w, len_w, fln_w, rit_w; + c3_y* pad_y; + c3_c* ful_c; + + if ( !u3_unix_cane(pax_c) ) { + u3l_log("%s: non-canonical path\n", pax_c); + u3z(pad); u3m_bail(c3__fail); + } + if ( '/' == *pax_c) { + pax_c++; + } + lod_w = strlen(u3_Host.dir_c); + len_w = lod_w + sizeof("/.urb/put/") + strlen(pax_c); + ful_c = c3_malloc(len_w); + rit_w = snprintf(ful_c, len_w, "%s/.urb/put/%s", u3_Host.dir_c, pax_c); + c3_assert(len_w == rit_w + 1); + + _unix_mkdirp(ful_c); + fid_i = c3_open(ful_c, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if ( fid_i < 0 ) { + u3l_log("%s: %s\n", ful_c, strerror(errno)); + c3_free(ful_c); + u3z(pad); u3m_bail(c3__fail); + } + + fln_w = u3r_met(3, pad); + pad_y = c3_malloc(fln_w); + u3r_bytes(0, fln_w, pad_y, pad); + u3z(pad); + rit_w = write(fid_i, pad_y, fln_w); + close(fid_i); + c3_free(pad_y); + + if ( rit_w != fln_w ) { + u3l_log("%s: %s\n", ful_c, strerror(errno)); + c3_free(ful_c); + u3m_bail(c3__fail); + } + c3_free(ful_c); +} + /* _unix_rm_r_cb(): callback to delete individual files/directories */ static c3_i @@ -165,7 +367,7 @@ _unix_rm_r_cb(const c3_c* pax_c, u3l_log("bad file type in rm_r: %s\r\n", pax_c); break; case FTW_F: - if ( 0 != unlink(pax_c) && ENOENT != errno ) { + if ( 0 != c3_unlink(pax_c) && ENOENT != errno ) { u3l_log("error unlinking (in rm_r) %s: %s\n", pax_c, strerror(errno)); c3_assert(0); @@ -181,7 +383,7 @@ _unix_rm_r_cb(const c3_c* pax_c, u3l_log("couldn't stat path: %s\r\n", pax_c); break; case FTW_DP: - if ( 0 != rmdir(pax_c) && ENOENT != errno ) { + if ( 0 != c3_rmdir(pax_c) && ENOENT != errno ) { u3l_log("error rmdiring %s: %s\n", pax_c, strerror(errno)); c3_assert(0); } @@ -213,7 +415,7 @@ _unix_rm_r(c3_c* pax_c) static void _unix_mkdir(c3_c* pax_c) { - if ( 0 != mkdir(pax_c, 0755) && EEXIST != errno) { + if ( 0 != c3_mkdir(pax_c, 0755) && EEXIST != errno) { u3l_log("error mkdiring %s: %s\n", pax_c, strerror(errno)); c3_assert(0); } @@ -224,7 +426,7 @@ _unix_mkdir(c3_c* pax_c) static c3_w _unix_write_file_hard(c3_c* pax_c, u3_noun mim) { - c3_i fid_i = open(pax_c, O_WRONLY | O_CREAT | O_TRUNC, 0666); + c3_i fid_i = c3_open(pax_c, O_WRONLY | O_CREAT | O_TRUNC, 0666); c3_w len_w, rit_w, siz_w, mug_w = 0; c3_y* dat_y; @@ -267,7 +469,7 @@ static void _unix_write_file_soft(u3_ufil* fil_u, u3_noun mim) { struct stat buf_u; - c3_i fid_i = open(fil_u->pax_c, O_RDONLY, 0644); + c3_i fid_i = c3_open(fil_u->pax_c, O_RDONLY, 0644); c3_ws len_ws, red_ws; c3_w old_w; c3_y* old_y; @@ -339,7 +541,7 @@ _unix_get_mount_point(u3_unix* unx_u, u3_noun mon) return NULL; } - c3_c* nam_c = u3r_string(mon); + c3_c* nam_c = _unix_knot_to_string(mon); u3_umon* mon_u; for ( mon_u = unx_u->mon_u; @@ -374,7 +576,7 @@ _unix_get_mount_point(u3_unix* unx_u, u3_noun mon) static void _unix_scan_mount_point(u3_unix* unx_u, u3_umon* mon_u) { - DIR* rid_u = opendir(mon_u->dir_u.pax_c); + DIR* rid_u = c3_opendir(mon_u->dir_u.pax_c); if ( !rid_u ) { u3l_log("error opening pier directory: %s: %s\r\n", mon_u->dir_u.pax_c, strerror(errno)); @@ -425,12 +627,11 @@ _unix_scan_mount_point(u3_unix* unx_u, u3_umon* mon_u) } } else { - if ( '.' != out_u->d_name[len_w] - || '\0' == out_u->d_name[len_w + 1] - || '~' == out_u->d_name[strlen(out_u->d_name) - 1] - || ('#' == out_u->d_name[0] && - '#' == out_u->d_name[strlen(out_u->d_name) - 1]) - ) { + if ( '.' != out_u->d_name[len_w] + || '\0' == out_u->d_name[len_w + 1] + || '~' == out_u->d_name[strlen(out_u->d_name) - 1] + || !_unix_sane_ta(unx_u, _unix_string_to_knot(out_u->d_name)) ) + { c3_free(pax_c); continue; } @@ -452,7 +653,7 @@ static u3_noun _unix_free_node(u3_unix* unx_u, u3_unod* nod_u); static void _unix_free_file(u3_ufil *fil_u) { - if ( 0 != unlink(fil_u->pax_c) && ENOENT != errno ) { + if ( 0 != c3_unlink(fil_u->pax_c) && ENOENT != errno ) { u3l_log("error unlinking %s: %s\n", fil_u->pax_c, strerror(errno)); c3_assert(0); } @@ -482,8 +683,8 @@ _unix_free_dir(u3_udir *dir_u) } /* _unix_free_node(): free node, deleting everything within - * - * also deletes from parent list if in it +** +** also deletes from parent list if in it */ static u3_noun _unix_free_node(u3_unix* unx_u, u3_unod* nod_u) @@ -526,12 +727,12 @@ _unix_free_node(u3_unix* unx_u, u3_unod* nod_u) } /* _unix_free_mount_point(): free mount point - * - * this process needs to happen in a very careful order. in particular, - * we must recurse before we get to the callback, so that libuv does all - * the child directories before it does us. - * - * tread carefully +** +** this process needs to happen in a very careful order. in +** particular, we must recurse before we get to the callback, so +** that libuv does all the child directories before it does us. +** +** tread carefully */ static void _unix_free_mount_point(u3_unix* unx_u, u3_umon* mon_u) @@ -559,7 +760,7 @@ _unix_delete_mount_point(u3_unix* unx_u, u3_noun mon) return; } - c3_c* nam_c = u3r_string(mon); + c3_c* nam_c = _unix_knot_to_string(mon); u3_umon* mon_u; u3_umon* tem_u; @@ -651,7 +852,7 @@ _unix_watch_dir(u3_udir* dir_u, u3_udir* par_u, c3_c* pax_c) static void _unix_create_dir(u3_udir* dir_u, u3_udir* par_u, u3_noun nam) { - c3_c* nam_c = u3r_string(nam); + c3_c* nam_c = _unix_knot_to_string(nam); c3_w nam_w = strlen(nam_c); c3_w pax_w = strlen(par_u->pax_c); c3_c* pax_c = c3_malloc(pax_w + 1 + nam_w + 1); @@ -671,12 +872,13 @@ _unix_create_dir(u3_udir* dir_u, u3_udir* par_u, u3_noun nam) static u3_noun _unix_update_node(u3_unix* unx_u, u3_unod* nod_u); /* _unix_update_file(): 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 mug checksum. if same as gum_w, move on. otherwise, overwrite - * add path plus data to %into event. +** +** 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 mug checksum. if same as +** gum_w, move on. otherwise, overwrite add path plus data to +** %into event. */ static u3_noun _unix_update_file(u3_unix* unx_u, u3_ufil* fil_u) @@ -690,7 +892,7 @@ _unix_update_file(u3_unix* unx_u, u3_ufil* fil_u) fil_u->dry = c3n; struct stat buf_u; - c3_i fid_i = open(fil_u->pax_c, O_RDONLY, 0644); + c3_i fid_i = c3_open(fil_u->pax_c, O_RDONLY, 0644); c3_ws len_ws, red_ws; c3_y* dat_y; @@ -745,9 +947,9 @@ _unix_update_file(u3_unix* unx_u, u3_ufil* fil_u) } /* _unix_update_dir(): update directory, producing list of changes - * - * when changing this, consider whether to also change - * _unix_initial_update_dir() +** +** when changing this, consider whether to also change +** _unix_initial_update_dir() */ static u3_noun _unix_update_dir(u3_unix* unx_u, u3_udir* dir_u) @@ -773,7 +975,7 @@ _unix_update_dir(u3_unix* unx_u, u3_udir* dir_u) } else { if ( c3y == nod_u->dir ) { - DIR* red_u = opendir(nod_u->pax_c); + DIR* red_u = c3_opendir(nod_u->pax_c); if ( 0 == red_u ) { u3_unod* nex_u = nod_u->nex_u; can = u3kb_weld(_unix_free_node(unx_u, nod_u), can); @@ -786,7 +988,7 @@ _unix_update_dir(u3_unix* unx_u, u3_udir* dir_u) } else { struct stat buf_u; - c3_i fid_i = open(nod_u->pax_c, O_RDONLY, 0644); + c3_i fid_i = c3_open(nod_u->pax_c, O_RDONLY, 0644); if ( (fid_i < 0) || (fstat(fid_i, &buf_u) < 0) ) { if ( ENOENT != errno ) { @@ -813,7 +1015,7 @@ _unix_update_dir(u3_unix* unx_u, u3_udir* dir_u) // Check for new nodes - DIR* rid_u = opendir(dir_u->pax_c); + DIR* rid_u = c3_opendir(dir_u->pax_c); if ( !rid_u ) { u3l_log("error opening directory %s: %s\r\n", dir_u->pax_c, strerror(errno)); @@ -869,11 +1071,10 @@ _unix_update_dir(u3_unix* unx_u, u3_udir* dir_u) if ( !nod_u ) { if ( !S_ISDIR(buf_u.st_mode) ) { - if ( !strchr(out_u->d_name,'.') - || '~' == out_u->d_name[strlen(out_u->d_name) - 1] - || ('#' == out_u->d_name[0] && - '#' == out_u->d_name[strlen(out_u->d_name) - 1]) - ) { + if ( !strchr(out_u->d_name,'.') + || '~' == out_u->d_name[strlen(out_u->d_name) - 1] + || !_unix_sane_ta(unx_u, _unix_string_to_knot(out_u->d_name)) ) + { c3_free(pax_c); continue; } @@ -942,7 +1143,8 @@ _unix_update_mount(u3_unix* unx_u, u3_umon* mon_u, u3_noun all) u3_noun wir = u3nt(c3__sync, u3dc("scot", c3__uv, unx_u->sev_l), u3_nul); - u3_noun cad = u3nq(c3__into, u3i_string(mon_u->nam_c), all, can); + u3_noun cad = u3nq(c3__into, _unix_string_to_knot(mon_u->nam_c), all, + can); u3_auto_plan(&unx_u->car_u, u3_ovum_init(0, c3__c, wir, cad)); } @@ -950,13 +1152,13 @@ _unix_update_mount(u3_unix* unx_u, u3_umon* mon_u, u3_noun all) } /* _unix_initial_update_file(): read file, but don't watch -** XX deduplicate with _unix_update_file() +** XX deduplicate with _unix_update_file() */ static u3_noun _unix_initial_update_file(c3_c* pax_c, c3_c* bas_c) { struct stat buf_u; - c3_i fid_i = open(pax_c, O_RDONLY, 0644); + c3_i fid_i = c3_open(pax_c, O_RDONLY, 0644); c3_ws len_ws, red_ws; c3_y* dat_y; @@ -1006,14 +1208,14 @@ _unix_initial_update_file(c3_c* pax_c, c3_c* bas_c) } /* _unix_initial_update_dir(): read directory, but don't watch -** XX deduplicate with _unix_update_dir() +** XX deduplicate with _unix_update_dir() */ static u3_noun _unix_initial_update_dir(c3_c* pax_c, c3_c* bas_c) { u3_noun can = u3_nul; - DIR* rid_u = opendir(pax_c); + DIR* rid_u = c3_opendir(pax_c); if ( !rid_u ) { u3l_log("error opening initial directory: %s: %s\r\n", pax_c, strerror(errno)); @@ -1089,8 +1291,8 @@ _unix_sync_file(u3_unix* unx_u, u3_udir* par_u, u3_noun nam, u3_noun ext, u3_nou // form file path - c3_c* nam_c = u3r_string(nam); - c3_c* ext_c = u3r_string(ext); + c3_c* nam_c = _unix_knot_to_string(nam); + c3_c* ext_c = _unix_knot_to_string(ext); c3_w par_w = strlen(par_u->pax_c); c3_w nam_w = strlen(nam_c); c3_w ext_w = strlen(ext_c); @@ -1174,7 +1376,7 @@ _unix_sync_change(u3_unix* unx_u, u3_udir* dir_u, u3_noun pax, u3_noun mim) _unix_sync_file(unx_u, dir_u, u3k(i_pax), u3k(it_pax), mim); } else { - c3_c* nam_c = u3r_string(i_pax); + c3_c* nam_c = _unix_knot_to_string(i_pax); c3_w pax_w = strlen(dir_u->pax_c); u3_unod* nod_u; @@ -1207,7 +1409,7 @@ static void _unix_sync_ergo(u3_unix* unx_u, u3_umon* mon_u, u3_noun can) { u3_noun nac = can; - u3_noun nam = u3i_string(mon_u->nam_c); + u3_noun nam = _unix_string_to_knot(mon_u->nam_c); while ( u3_nul != nac) { _unix_sync_change(unx_u, &mon_u->dir_u, @@ -1263,98 +1465,24 @@ u3_unix_ef_hill(u3_unix* unx_u, u3_noun hil) u3z(hil); } -/* u3_unix_acquire(): acquire a lockfile, killing anything that holds it. -*/ -static void -u3_unix_acquire(c3_c* pax_c) -{ - c3_c* paf_c = _unix_down(pax_c, ".vere.lock"); - c3_w pid_w; - FILE* loq_u; - - if ( NULL != (loq_u = fopen(paf_c, "r")) ) { - if ( 1 != fscanf(loq_u, "%" SCNu32, &pid_w) ) { - u3l_log("lockfile %s is corrupt!\n", paf_c); - kill(getpid(), SIGTERM); - sleep(1); c3_assert(0); - } - else if (pid_w != getpid()) { - c3_w i_w; - - if ( -1 != kill(pid_w, SIGTERM) ) { - u3l_log("unix: stopping process %d, live in %s...\n", - pid_w, pax_c); - - for ( i_w = 0; i_w < 16; i_w++ ) { - sleep(1); - if ( -1 == kill(pid_w, SIGTERM) ) { - break; - } - } - if ( 16 == i_w ) { - for ( i_w = 0; i_w < 16; i_w++ ) { - if ( -1 == kill(pid_w, SIGKILL) ) { - break; - } - sleep(1); - } - } - if ( 16 == i_w ) { - u3l_log("unix: process %d seems unkillable!\n", pid_w); - c3_assert(0); - } - u3l_log("unix: stopped old process %u\n", pid_w); - } - } - fclose(loq_u); - unlink(paf_c); - } - - if ( NULL == (loq_u = fopen(paf_c, "w")) ) { - u3l_log("unix: unable to open %s\n", paf_c); - c3_assert(0); - } - - fprintf(loq_u, "%u\n", getpid()); - - { - c3_i fid_i = fileno(loq_u); - c3_sync(fid_i); - } - - fclose(loq_u); - c3_free(paf_c); -} - -/* u3_unix_release(): release a lockfile. -*/ -static void -u3_unix_release(c3_c* pax_c) -{ - c3_c* paf_c = _unix_down(pax_c, ".vere.lock"); - - unlink(paf_c); - c3_free(paf_c); -} - /* u3_unix_ef_look(): update the root of a specific mount point. */ void u3_unix_ef_look(u3_unix* unx_u, u3_noun mon, u3_noun all) { if ( c3y == unx_u->dyr ) { + c3_c* nam_c = _unix_knot_to_string(mon); + unx_u->dyr = c3n; u3_umon* mon_u = unx_u->mon_u; - - while ( mon_u && ( c3n == u3r_sing_c(mon_u->nam_c, mon) ) ) { + while ( mon_u && 0 != strcmp(nam_c, mon_u->nam_c) ) { mon_u = mon_u->nex_u; } - + c3_free(nam_c); if ( mon_u ) { _unix_update_mount(unx_u, mon_u, all); } } - u3z(mon); } @@ -1431,10 +1559,7 @@ _unix_io_exit(u3_auto* car_u) { u3_unix* unx_u = (u3_unix*)car_u; - // XX move to disk.c? - // - u3_unix_release(unx_u->pax_c); - + u3z(unx_u->sat); c3_free(unx_u->pax_c); c3_free(unx_u); } @@ -1449,10 +1574,7 @@ u3_unix_io_init(u3_pier* pir_u) unx_u->pax_c = strdup(pir_u->pax_c); unx_u->alm = c3n; unx_u->dyr = c3n; - - // XX move to disk.c? - // - u3_unix_acquire(unx_u->pax_c); + unx_u->sat = u3do("sane", c3__ta); u3_auto* car_u = &unx_u->car_u; car_u->nam_m = c3__unix; diff --git a/pkg/urbit/vere/king.c b/pkg/urbit/vere/king.c index e857d6040..ff9e85ce0 100644 --- a/pkg/urbit/vere/king.c +++ b/pkg/urbit/vere/king.c @@ -924,13 +924,13 @@ u3_king_grab(void* vod_p) struct stat st; if ( -1 == stat(nam_c, &st) ) { - mkdir(nam_c, 0700); + c3_mkdir(nam_c, 0700); } c3_c man_c[2048]; snprintf(man_c, 2048, "%s/%s-daemon.txt", nam_c, wen_c); - fil_u = fopen(man_c, "w"); + fil_u = c3_fopen(man_c, "w"); fprintf(fil_u, "%s\r\n", wen_c); c3_free(wen_c); diff --git a/pkg/urbit/vere/pier.c b/pkg/urbit/vere/pier.c index 9aad54105..0cdf9abdb 100644 --- a/pkg/urbit/vere/pier.c +++ b/pkg/urbit/vere/pier.c @@ -526,12 +526,11 @@ _pier_on_scry_done(void* ptr_v, u3_noun nun) // if serialization and export path succeeded, write to disk // if ( (u3_none != out) && (u3_none != pad) ) { - c3_c fil_c[2048]; - snprintf(fil_c, 2048, "%s/.urb/put/%s.%s", - pir_u->pax_c, pac_c+1, ext_c); + c3_c fil_c[256]; + snprintf(fil_c, 256, "%s.%s", pac_c + 1, ext_c); - u3_walk_save(fil_c, 0, out, pir_u->pax_c, pad); - u3l_log("pier: scry result in %s\n", fil_c); + u3_unix_save(fil_c, pad); + u3l_log("pier: scry result in %s/.urb/put/%s\n", u3_Host.dir_c, fil_c); } } diff --git a/pkg/urbit/vere/walk.c b/pkg/urbit/vere/walk.c deleted file mode 100644 index 5c113cbac..000000000 --- a/pkg/urbit/vere/walk.c +++ /dev/null @@ -1,326 +0,0 @@ -/* vere/walk.c -** -*/ -#include "all.h" -#include "vere/vere.h" - - /* |% - ** ++ arch :: fs node - ** $% [& p=@uvI q=*] :: file, hash/data - ** [| p=(map ,@ta arch)] :: directory - ** == :: - ** -- - */ - -#if 0 -static u3_noun -_walk_ok(u3_noun nod) -{ - u3_noun don = u3n_mung(u3k(u2A->toy.arch), u3k(nod)); - - if ( c3n == u3_sing(nod, don) ) { - c3_assert(0); - } - u3z(don); - return nod; -} -#endif - -/* u3_walk_safe(): load file or 0. -*/ -u3_noun -u3_walk_safe(c3_c* pas_c) -{ - struct stat buf_b; - c3_i fid_i = open(pas_c, O_RDONLY, 0644); - c3_w fln_w, red_w; - c3_y* pad_y; - - if ( (fid_i < 0) || (fstat(fid_i, &buf_b) < 0) ) { - // u3l_log("%s: %s\n", pas_c, strerror(errno)); - return 0; - } - fln_w = buf_b.st_size; - pad_y = c3_malloc(buf_b.st_size); - - red_w = read(fid_i, pad_y, fln_w); - close(fid_i); - - if ( fln_w != red_w ) { - c3_free(pad_y); - return 0; - } - else { - u3_noun pad = u3i_bytes(fln_w, (c3_y *)pad_y); - c3_free(pad_y); - - return pad; - } -} - -/* u3_walk_load(): load file or bail. -*/ -u3_noun -u3_walk_load(c3_c* pas_c) -{ - struct stat buf_b; - c3_i fid_i = open(pas_c, O_RDONLY, 0644); - c3_w fln_w, red_w; - c3_y* pad_y; - - if ( (fid_i < 0) || (fstat(fid_i, &buf_b) < 0) ) { - u3l_log("%s: %s\n", pas_c, strerror(errno)); - return u3m_bail(c3__fail); - } - fln_w = buf_b.st_size; - pad_y = c3_malloc(buf_b.st_size); - - red_w = read(fid_i, pad_y, fln_w); - close(fid_i); - - if ( fln_w != red_w ) { - c3_free(pad_y); - u3l_log("u3_walk_load failed"); - return u3m_bail(c3__fail); - } - else { - u3_noun pad = u3i_bytes(fln_w, (c3_y *)pad_y); - c3_free(pad_y); - - return pad; - } -} - -/* _walk_mkdirp(): recursively make directories in pax at bas_c (RETAIN) -*/ -static void -_walk_mkdirp(c3_c* bas_c, u3_noun pax) -{ - c3_c* pax_c; - c3_y* waq_y; - c3_w pax_w, fas_w, len_w; - - if ( u3_nul == pax ) { - return; - } - - pax_w = u3r_met(3, u3h(pax)); - fas_w = strlen(bas_c); - len_w = 1 + fas_w + pax_w; - - pax_c = c3_malloc(1 + len_w); - strcpy(pax_c, bas_c); - - pax_c[fas_w] = '/'; - waq_y = (void*)(1 + pax_c + fas_w); - u3r_bytes(0, pax_w, waq_y, u3h(pax)); - pax_c[len_w] = '\0'; - - if ( 0 != mkdir(pax_c, 0755) && EEXIST != errno ) { - u3l_log("error mkdiring %s: %s\n", pax_c, strerror(errno)); - u3m_bail(c3__fail); - } - - _walk_mkdirp(pax_c, u3t(pax)); - c3_free(pax_c); -} - -/* u3_walk_save(): save file or bail. -*/ -void -u3_walk_save(c3_c* pas_c, u3_noun tim, u3_atom pad, c3_c* bas_c, u3_noun pax) -{ - c3_i fid_i = open(pas_c, O_WRONLY | O_CREAT | O_TRUNC, 0666); - c3_w fln_w, rit_w; - c3_y* pad_y; - - if ( fid_i < 0 ) { - if ( ENOENT == errno && u3_nul != pax ) { - _walk_mkdirp(bas_c, pax); - return u3_walk_save(pas_c, tim, pad, 0, u3_nul); - } - - u3l_log("%s: %s\n", pas_c, strerror(errno)); - u3m_bail(c3__fail); - } - - fln_w = u3r_met(3, pad); - pad_y = c3_malloc(fln_w); - u3r_bytes(0, fln_w, pad_y, pad); - u3z(pad); - u3z(pax); - - rit_w = write(fid_i, pad_y, fln_w); - close(fid_i); - c3_free(pad_y); - - if ( rit_w != fln_w ) { - u3l_log("%s: %s\n", pas_c, strerror(errno)); - u3m_bail(c3__fail); - } - - if ( 0 != tim ) { - struct timeval tim_tv[2]; - - u3_time_out_tv(&tim_tv[0], u3k(tim)); - u3_time_out_tv(&tim_tv[1], tim); - - utimes(pas_c, tim_tv); - } -} - -/* _walk_in(): inner loop of _walk(), producing map. -*/ -static u3_noun -_walk_in(const c3_c* dir_c, c3_w len_w) -{ - DIR* dir_d = opendir(dir_c); - u3_noun map = u3_nul; - - if ( !dir_d ) { - return u3_nul; - } - else while ( 1 ) { - struct dirent ent_n; - struct dirent* out_n; - - if ( u3_readdir_r(dir_d, &ent_n, &out_n) != 0 ) { - u3l_log("%s: %s\n", dir_c, strerror(errno)); - break; - } - else if ( !out_n ) { - break; - } - else if ( !strcmp(out_n->d_name, ".") || - !strcmp(out_n->d_name, "..") || - ('~' == out_n->d_name[0]) || - ('.' == out_n->d_name[0]) ) // XX restricts some spans - { - continue; - } - else { - c3_c* fil_c = out_n->d_name; - c3_w lef_w = len_w + 1 + strlen(fil_c); - c3_c* pat_c = c3_malloc(lef_w + 1); - struct stat buf_b; - - strncpy(pat_c, dir_c, lef_w); - pat_c[len_w] = '/'; - strncpy(pat_c + len_w + 1, fil_c, lef_w); - pat_c[lef_w] = '\0'; - - if ( 0 != stat(pat_c, &buf_b) ) { - c3_free(pat_c); - } else { - u3_noun tim = c3_stat_mtime(&buf_b); - - if ( !S_ISDIR(buf_b.st_mode) ) { - c3_c* dot_c = strrchr(fil_c, '.'); - c3_c* nam_c = strdup(fil_c); - c3_c* ext_c = strdup(dot_c + 1); - - nam_c[dot_c - fil_c] = 0; - { - u3_noun nam = u3i_string(nam_c); - u3_noun ext = u3i_string(ext_c); - u3_noun get = u3kdb_get(u3k(map), u3k(nam)); - u3_noun dat = u3_walk_load(pat_c); - u3_noun hax; - - if ( !strcmp("noun", ext_c) ) { - dat = u3ke_cue(dat); - } - hax = u3do("sham", u3k(dat)); - if ( u3_none == get ) { get = u3_nul; } - - get = u3kdb_put(get, ext, u3nt(c3y, hax, dat)); - map = u3kdb_put(map, nam, u3nc(c3n, get)); - } - c3_free(nam_c); - c3_free(ext_c); - } - else { - u3_noun dir = _walk_in(pat_c, lef_w); - - if ( u3_nul != dir ) { - map = u3kdb_put - (map, u3i_string(fil_c), u3nc(c3n, dir)); - } - else u3z(tim); - } - c3_free(pat_c); - } - } - } - closedir(dir_d); - return map; -} - -/* u3_walk(): traverse `dir_c` to produce an arch, updating `old`. -*/ -u3_noun -u3_walk(const c3_c* dir_c, u3_noun old) -{ - // XX - obviously, cheaper to update old data. - u3z(old); - { - struct stat buf_b; - - if ( 0 != stat(dir_c, &buf_b) ) { - u3l_log("can't stat %s\n", dir_c); - // return u3m_bail(c3__fail); - c3_assert(0); - } - else { - return u3nc(c3n, - _walk_in(dir_c, strlen(dir_c))); - } - } -} - -/* u3_path(): C unix path in computer for file or directory. -*/ -c3_c* -u3_path(c3_o fyl, u3_noun pax) -{ - c3_w len_w; - c3_c *pas_c; - - // measure - // - len_w = strlen(u3_Local); - { - u3_noun wiz = pax; - - while ( u3_nul != wiz ) { - len_w += (1 + u3r_met(3, u3h(wiz))); - wiz = u3t(wiz); - } - } - - // cut - // - pas_c = c3_malloc(len_w + 1); - strncpy(pas_c, u3_Local, len_w); - pas_c[len_w] = '\0'; - { - u3_noun wiz = pax; - c3_c* waq_c = (pas_c + strlen(pas_c)); - - while ( u3_nul != wiz ) { - c3_w tis_w = u3r_met(3, u3h(wiz)); - - if ( (c3y == fyl) && (u3_nul == u3t(wiz)) ) { - *waq_c++ = '.'; - } else *waq_c++ = '/'; - - u3r_bytes(0, tis_w, (c3_y*)waq_c, u3h(wiz)); - waq_c += tis_w; - - wiz = u3t(wiz); - } - *waq_c = 0; - } - u3z(pax); - return pas_c; -} diff --git a/pkg/urbit/worker/main.c b/pkg/urbit/worker/main.c index 428e22a9a..6d76db26b 100644 --- a/pkg/urbit/worker/main.c +++ b/pkg/urbit/worker/main.c @@ -131,7 +131,7 @@ _cw_serf_stdio(c3_i* inn_i, c3_i* out_i) // we replace [FD 0] (stdin) with a fd pointing to /dev/null // we replace [FD 1] (stdout) with a dup of [FD 2] (stderr) // - c3_i nul_i = open(c3_dev_null, O_RDWR, 0); + c3_i nul_i = c3_open(c3_dev_null, O_RDWR, 0); *inn_i = dup(0); *out_i = dup(1); diff --git a/pkg/urbit/worker/serf.c b/pkg/urbit/worker/serf.c index 55cb3ad7d..982cb8ec9 100644 --- a/pkg/urbit/worker/serf.c +++ b/pkg/urbit/worker/serf.c @@ -204,13 +204,13 @@ _serf_grab(u3_noun sac) struct stat st; if ( -1 == stat(nam_c, &st) ) { - mkdir(nam_c, 0700); + c3_mkdir(nam_c, 0700); } c3_c man_c[2054]; snprintf(man_c, 2053, "%s/%s-serf.txt", nam_c, wen_c); - fil_u = fopen(man_c, "w"); + fil_u = c3_fopen(man_c, "w"); fprintf(fil_u, "%s\r\n", wen_c); c3_free(wen_c); @@ -835,13 +835,13 @@ _serf_writ_live_exit(u3_serf* sef_u, c3_w cod_w) struct stat st; if ( -1 == stat(nam_c, &st) ) { - mkdir(nam_c, 0700); + c3_mkdir(nam_c, 0700); } c3_c man_c[2054]; snprintf(man_c, 2053, "%s/%s.txt", nam_c, wen_c); - fil_u = fopen(man_c, "w"); + fil_u = c3_fopen(man_c, "w"); c3_free(wen_c); u3z(wen);