/* archive.c: * **************************************************************** * Copyright (C) 2003 Tom Lord * * See the file "COPYING" for further information about * the copyright and warranty status of this work. */ #include "config-options.h" #include "hackerlab/bugs/panic.h" #include "hackerlab/os/errno.h" #include "hackerlab/os/errno-to-string.h" #include "hackerlab/os/sys/types.h" #include "hackerlab/os/sys/wait.h" #include "hackerlab/os/signal.h" #include "hackerlab/os/time.h" #include "hackerlab/os/unistd.h" #include "hackerlab/os/stdlib.h" #include "hackerlab/fmt/cvt.h" #include "hackerlab/mem/alloc-limits.h" #include "hackerlab/mem/mem.h" #include "hackerlab/hash/hash-utils.h" #include "hackerlab/arrays/ar.h" #include "hackerlab/char/str.h" #include "hackerlab/char/char-class.h" #include "hackerlab/vu/safe.h" #include "hackerlab/fs/cwd.h" #include "hackerlab/fs/file-names.h" #include "tla/libfsutils/tmp-files.h" #include "tla/libfsutils/rmrf.h" #include "tla/libarch/namespace.h" #include "tla/libarch/my.h" #include "tla/libarch/exec.h" #include "tla/libarch/archives.h" #include "tla/libarch/archive-version.h" #include "tla/libarch/pfs.h" #include "tla/libarch/archive-pfs.h" #include "tla/libarch/archive.h" /* __STDC__ prototypes for static functions */ static int invoke_tar_extract (int * pid_ret); static int wait_for_tar (int pid); static void ensure_writable (struct arch_archive * arch, int mirror_ok); static struct arch_archive * connected_by_name = 0; void arch_make_archive (const t_uchar * name, const t_uchar * location, const t_uchar * mirror_of, int dot_listing_lossage, int signed_archive, int tla_archive) { t_uchar * current_loc = 0; t_uchar * version; invariant (arch_valid_archive_name (name)); current_loc = arch_archive_location (name, 1); if (current_loc) { safe_printfmt (2, "arch_make_archive: archive already registered\n name: %s\n", name); exit (2); } version = arch_archive_version_for_new_archive (tla_archive); arch_pfs_make_archive (name, location, version, mirror_of, dot_listing_lossage, signed_archive); arch_run_hook ("make-archive", "ARCH_ARCHIVE", name, "ARCH_LOCATION", location, (t_uchar*)0); lim_free (0, version); } struct arch_archive * arch_archive_connect_location (const t_uchar * name, const t_uchar * location, const t_uchar * want_mirror_of) { struct arch_archive * answer = 0; answer = lim_malloc (0, sizeof (*answer)); mem_set0 ((t_uchar *)answer, sizeof (*answer)); answer->name = str_save (0, name); answer->location = str_save (0, location); answer->client_anticipates_mirror = (want_mirror_of ? str_save (0, want_mirror_of) : 0); arch_pfs_archive_connect (&answer); answer->version = answer->vtable->archive_version (answer); answer->access = arch_archive_access (answer->version); answer->type = arch_archive_type (answer->version); if (answer->access == arch_archive_incompatible) { safe_printfmt (2, "arch_archive_connect: attempt to connect to incompatible archive\n archive: %s\n", (name ? name : location)); exit (2); } answer->mirror_of = arch_get_meta_info_trimming (answer, "mirror"); answer->official_name = arch_get_meta_info_trimming (answer, "name"); if (!answer->official_name) { int ign; printfmt (&ign, 2, "Unable to read the official name of archive %s\n Archive damaged?\n", name); exit (2); } lim_free (0, answer->name); answer->name = str_save (0, answer->official_name); answer->http_blows = arch_get_meta_int_info (answer, "http-blows"); answer->signed_archive = arch_get_meta_int_info (answer, "signed-archive"); if (want_mirror_of && str_cmp (want_mirror_of, answer->mirror_of)) { safe_printfmt (2, "arch_archive_connect: attempt to connect to wrong mirror\n archive: %s\n wanted mirror of: %s\n got mirror of: %s\n", (name ? name : location), want_mirror_of, (answer->mirror_of ? answer->mirror_of : (t_uchar *)"(not a mirror)")); exit (2); } return answer; } struct arch_archive * arch_archive_connect (const t_uchar * name, const t_uchar * want_mirror_of) { struct arch_archive * answer = 0; for (answer = connected_by_name; answer && str_cmp (answer->name, name); answer = answer->next) ; if (answer) { if (want_mirror_of && str_cmp (want_mirror_of, answer->mirror_of)) { safe_printfmt (2, "arch_archive_connect: attempt to connect to wrong mirror\n archive: %s\n wanted mirror of: %s\n got mirror of: %s\n", name, want_mirror_of, (answer->mirror_of ? answer->mirror_of : (t_uchar *)"(not a mirror)")); exit (2); } ++answer->refs; return answer; } else { t_uchar * location = 0; location = arch_archive_location (name, 0); answer = arch_archive_connect_location (name, location, want_mirror_of); lim_free (0, answer->name); answer->name = str_save (0, name); answer->refs = 1; answer->next = connected_by_name; connected_by_name = answer; lim_free(0, location); return answer; } } void arch_archive_close (struct arch_archive * arch) { if (!arch) return; if (arch->refs) --arch->refs; if (!arch->refs) { struct arch_archive ** handle = &connected_by_name; while (*handle) { if (*handle != arch) handle = &((*handle)->next); else { *handle = (*handle)->next; } } arch->vtable->close (arch); lim_free (0, arch->name); lim_free (0, arch->official_name); lim_free (0, arch->location); lim_free (0, arch->version); lim_free (0, arch); } } t_uchar * arch_archive_version (struct arch_archive * arch) { return arch->vtable->archive_version (arch); } rel_table arch_archive_categories (struct arch_archive * arch) { rel_table answer = rel_table_nil; answer = arch->vtable->categories (arch); rel_sort_table_by_field (0, answer, 0); return answer; } rel_table arch_archive_branches (struct arch_archive * arch, const t_uchar * category) { rel_table answer = rel_table_nil; answer = arch->vtable->branches (arch, category); rel_sort_table_by_field (0, answer, 0); return answer; } rel_table arch_archive_versions (struct arch_archive * arch, const t_uchar * package) { rel_table answer = rel_table_nil; answer = arch->vtable->versions (arch, package); arch_sort_table_by_name_field (0, answer, 0); return answer; } t_uchar * arch_archive_latest_revision (struct arch_archive * arch, const t_uchar * version, int full) { rel_table revs = rel_table_nil; t_uchar * answer = 0; revs = arch_archive_revisions (arch, version, full); if (rel_n_records (revs)) answer = str_save (0, rel_peek_str (revs, rel_n_records (revs) - 1, 0)); rel_free_table (revs); return answer; } rel_table arch_archive_revisions (struct arch_archive * arch, const t_uchar * version, int full) { rel_table answer = rel_table_nil; answer = arch->vtable->revisions (arch, version); arch_sort_table_by_patch_level_field (0, answer, 0); if (full) { t_uchar * fqv = 0; int x; if (full == 1) fqv = arch_fully_qualify (arch->name, version); else fqv = str_save (0, version); for (x = 0; x < rel_n_records (answer); ++x) { const t_uchar * t; t_uchar * new_t; t = rel_peek_str (answer, x, 0); new_t = str_alloc_cat_many (0, fqv, "--", t, str_end); rel_set_taking (answer, x, 0, rel_make_field_str (new_t)); lim_free (0, new_t); } lim_free (0, fqv); } return answer; } t_uchar * arch_archive_log (struct arch_archive * arch, const t_uchar * revision) { t_uchar * answer = 0; answer = arch->vtable->archive_log (arch, revision); return answer; } void arch_revision_type (enum arch_revision_type * type, int * is_cached, struct arch_archive * arch, const t_uchar * revision) { if (arch->vtable->revision_type (type, is_cached, arch, revision) < 0) { safe_printfmt (2, "corrupt archive\n name: %s\n location: %s\n revision: %s\n", arch->name, arch->location, revision); exit (2); } } int arch_revision_exists (struct arch_archive * arch, const t_uchar * revision) { enum arch_revision_type type; int is_cached; return (arch->vtable->revision_type (&type, &is_cached, arch, revision) >= 0); } void arch_get_patch_targz (int out_fd, struct arch_archive * arch, const t_uchar * revision) { arch->vtable->get_patch (out_fd, arch, revision); } void arch_get_patch (struct arch_archive * arch, const t_uchar * revision, const t_uchar * dest_dir) { int here_fd; t_uchar * dest_dir_dir = 0; t_uchar * dest_dir_dir_path = 0; t_uchar * dest_dir_tail = 0; t_uchar * dest_dir_path = 0; t_uchar * tmpdir_path = 0; int out_fd = 0; int tar_pid = 0; t_uchar * patches_file_name = 0; t_uchar * patches_file_dest = 0; here_fd = safe_open (".", O_RDONLY, 0); dest_dir_dir = file_name_directory_file (0, dest_dir); if (dest_dir_dir) safe_chdir (dest_dir_dir); dest_dir_dir_path = safe_current_working_directory (); dest_dir_tail = file_name_tail (0, dest_dir); dest_dir_path = file_name_in_vicinity (0, dest_dir_dir_path, dest_dir_tail); tmpdir_path = tmp_file_name (dest_dir_dir_path, ",,get-patch"); patches_file_name = str_alloc_cat (0, revision, ".patches"); patches_file_dest = file_name_in_vicinity (0, "..", dest_dir_tail); safe_mkdir (tmpdir_path, 0777); safe_chdir (tmpdir_path); out_fd = invoke_tar_extract (&tar_pid); arch->vtable->get_patch (out_fd, arch, revision); safe_close (out_fd); if (wait_for_tar (tar_pid)) panic ("arch_get_patch: tar exitted with non-0 status"); safe_rename (patches_file_name, patches_file_dest); safe_fchdir (here_fd); safe_close (here_fd); rmrf_file (tmpdir_path); lim_free (0, dest_dir_dir); lim_free (0, dest_dir_dir_path); lim_free (0, dest_dir_tail); lim_free (0, dest_dir_path); lim_free (0, tmpdir_path); lim_free (0, patches_file_name); lim_free (0, patches_file_dest); } void arch_get_cached_revision_targz (int out_fd, struct arch_archive * arch, const t_uchar * revision) { arch->vtable->get_cached (out_fd, arch, revision); } void arch_get_cached_revision (struct arch_archive * arch, const t_uchar * revision, const t_uchar * dest_dir) { int here_fd; t_uchar * dest_dir_dir = 0; t_uchar * dest_dir_dir_path = 0; t_uchar * dest_dir_tail = 0; t_uchar * dest_dir_path = 0; t_uchar * tmpdir_path = 0; int out_fd = 0; int tar_pid = 0; t_uchar * patches_file_dest = 0; here_fd = safe_open (".", O_RDONLY, 0); dest_dir_dir = file_name_directory_file (0, dest_dir); if (dest_dir_dir) safe_chdir (dest_dir_dir); dest_dir_dir_path = safe_current_working_directory (); dest_dir_tail = file_name_tail (0, dest_dir); dest_dir_path = file_name_in_vicinity (0, dest_dir_dir_path, dest_dir_tail); tmpdir_path = tmp_file_name (dest_dir_dir_path, ",,get-patch"); patches_file_dest = file_name_in_vicinity (0, "..", dest_dir_tail); safe_mkdir (tmpdir_path, 0777); safe_chdir (tmpdir_path); out_fd = invoke_tar_extract (&tar_pid); arch->vtable->get_cached (out_fd, arch, revision); safe_close (out_fd); if (wait_for_tar (tar_pid)) panic ("arch_get_patch: tar exitted with non-0 status"); safe_rename (revision, patches_file_dest); safe_fchdir (here_fd); safe_close (here_fd); rmrf_file (tmpdir_path); lim_free (0, dest_dir_dir); lim_free (0, dest_dir_dir_path); lim_free (0, dest_dir_tail); lim_free (0, dest_dir_path); lim_free (0, tmpdir_path); lim_free (0, patches_file_dest); } void arch_get_import_targz (int out_fd, struct arch_archive * arch, const t_uchar * revision) { arch->vtable->get_import (out_fd, arch, revision); } void arch_get_import_revision (struct arch_archive * arch, const t_uchar * revision, const t_uchar * dest_dir) { int here_fd; t_uchar * dest_dir_dir = 0; t_uchar * dest_dir_dir_path = 0; t_uchar * dest_dir_tail = 0; t_uchar * dest_dir_path = 0; t_uchar * tmpdir_path = 0; int out_fd = 0; int tar_pid = 0; t_uchar * patches_file_dest = 0; here_fd = safe_open (".", O_RDONLY, 0); dest_dir_dir = file_name_directory_file (0, dest_dir); if (dest_dir_dir) safe_chdir (dest_dir_dir); dest_dir_dir_path = safe_current_working_directory (); dest_dir_tail = file_name_tail (0, dest_dir); dest_dir_path = file_name_in_vicinity (0, dest_dir_dir_path, dest_dir_tail); tmpdir_path = tmp_file_name (dest_dir_dir_path, ",,get-patch"); patches_file_dest = file_name_in_vicinity (0, "..", dest_dir_tail); safe_mkdir (tmpdir_path, 0777); safe_chdir (tmpdir_path); out_fd = invoke_tar_extract (&tar_pid); arch->vtable->get_import (out_fd, arch, revision); safe_close (out_fd); if (wait_for_tar (tar_pid)) panic ("arch_get_patch: tar exitted with non-0 status"); safe_rename (revision, patches_file_dest); safe_fchdir (here_fd); safe_close (here_fd); rmrf_file (tmpdir_path); lim_free (0, dest_dir_dir); lim_free (0, dest_dir_dir_path); lim_free (0, dest_dir_tail); lim_free (0, dest_dir_path); lim_free (0, tmpdir_path); lim_free (0, patches_file_dest); } t_uchar * arch_get_continuation (struct arch_archive * arch, const t_uchar * revision) { t_uchar * raw_data = 0; t_uchar * start; t_uchar * end; t_uchar * answer = 0; raw_data = arch->vtable->get_continuation (arch, revision); start = raw_data; while (*start && char_is_space (*start)) ++start; end = start; while (*end && !char_is_space (*end)) ++end; answer = str_save_n (0, start, end - start); lim_free (0, raw_data); return answer; } t_uchar * arch_get_meta_info (struct arch_archive * arch, const t_uchar * meta_info_name) { t_uchar * answer = 0; answer = arch->vtable->get_meta_info (arch, meta_info_name); return answer; } t_uchar * arch_get_meta_info_trimming (struct arch_archive * arch, const t_uchar * meta_info_name) { t_uchar * intermediate = 0; t_uchar * answer = 0; intermediate = arch_get_meta_info (arch, meta_info_name); if (!intermediate) return 0; answer = str_save_trimming (0, intermediate); lim_free (0, intermediate); return answer; } int arch_make_category (t_uchar ** errstr, struct arch_archive * arch, const t_uchar * category) { int answer; ensure_writable (arch, 0); answer = arch->vtable->make_category (errstr, arch, category); arch_run_hook ("make-category", "ARCH_ARCHIVE", arch->name, "ARCH_CATEGORY", category, (t_uchar*)0); return answer; } int arch_make_branch (t_uchar ** errstr, struct arch_archive * arch, const t_uchar * branch) { int answer; ensure_writable (arch, 0); answer = arch->vtable->make_branch (errstr, arch, branch); arch_run_hook ("make-branch", "ARCH_ARCHIVE", arch->name, "ARCH_BRANCH", branch, (t_uchar*)0); return answer; } int arch_make_version (t_uchar ** errstr, struct arch_archive * arch, const t_uchar * version) { int answer; ensure_writable (arch, 0); answer = arch->vtable->make_version (errstr, arch, version); arch_run_hook ("make-version", "ARCH_ARCHIVE", arch->name, "ARCH_VERSION", version, (t_uchar*)0); return answer; } int arch_archive_lock_revision (t_uchar ** errstr, struct arch_archive * a, const t_uchar * version, const t_uchar * prev_level, const t_uchar * uid, const t_uchar * txn_id, const t_uchar * new_level) { ensure_writable (a, 1); return a->vtable->lock_revision (errstr, a, version, prev_level, uid, txn_id, new_level); } int arch_revision_ready (t_uchar ** errstr, struct arch_archive *a, const t_uchar * version, const t_uchar * prev_level, const t_uchar * uid, const t_uchar * txn_id, const t_uchar * new_level) { return a->vtable->revision_ready (errstr, a, version, prev_level, uid, txn_id, new_level); } int arch_archive_finish_revision (t_uchar ** errstr, struct arch_archive * a, const t_uchar * version, const t_uchar * prev_level, const t_uchar * uid, const t_uchar * txn_id, const t_uchar * new_level) { ensure_writable (a, 0); return a->vtable->finish_revision (errstr, a, version, prev_level, uid, txn_id, new_level); } enum arch_revision_lock_state arch_archive_revision_lock_state (t_uchar ** prev_level_ret, t_uchar ** uid_ret, t_uchar ** txn_id_ret, struct arch_archive * a, const t_uchar * version) { ensure_writable (a, 1); return a->vtable->lock_state (prev_level_ret, uid_ret, txn_id_ret, a, version); } int arch_archive_break_revision_lock (t_uchar ** errstr, struct arch_archive * a, const t_uchar * version, const t_uchar * prev_level, const t_uchar * uid, const t_uchar * txn_id) { ensure_writable (a, 1); return a->vtable->break_revision_lock (errstr, a, version, prev_level, uid, txn_id); } int arch_archive_put_log (t_uchar ** errstr, struct arch_archive * a, const t_uchar * version, const t_uchar * prev_level, const t_uchar * uid, const t_uchar * txn_id, const t_uchar * log_text) { ensure_writable (a, 0); return a->vtable->put_log (errstr, a, version, prev_level, uid, txn_id, log_text); } int arch_archive_put_continuation (t_uchar ** errstr, struct arch_archive * a, const t_uchar * version, const t_uchar * prev_level, const t_uchar * uid, const t_uchar * txn_id, const t_uchar * continuation) { ensure_writable (a, 0); return a->vtable->put_continuation (errstr, a, version, prev_level, uid, txn_id, continuation); } int arch_archive_put_changeset_targz (t_uchar ** errstr, struct arch_archive * a, const t_uchar * version, const t_uchar * prev_level, const t_uchar * uid, const t_uchar * txn_id, const t_uchar * level, int in_fd) { int answer; answer = a->vtable->put_changeset (errstr, a, version, prev_level, uid, txn_id, level, in_fd); return answer; } int arch_archive_put_changeset (t_uchar ** errstr, struct arch_archive * a, const t_uchar * version, const t_uchar * prev_level, const t_uchar * uid, const t_uchar * txn_id, const t_uchar * level, const t_uchar * dir) { t_uchar * dir_tail = 0; t_uchar * desired_name = 0; t_uchar * tar_file_path = 0; int in_fd; int answer; dir_tail = file_name_tail (0, dir); desired_name = str_alloc_cat_many (0, version, "--", level, ".patches", str_end); invariant (!str_cmp (dir_tail, desired_name)); /* GNU tar 1.13 is busted and doesn't output to pipes correctly. */ ensure_writable (a, 0); tar_file_path = make_tmp_tar_archive (dir); in_fd = safe_open (tar_file_path, O_RDONLY, 0); answer = a->vtable->put_changeset (errstr, a, version, prev_level, uid, txn_id, level, in_fd); safe_close (in_fd); safe_unlink (tar_file_path); lim_free (0, dir_tail); lim_free (0, desired_name); lim_free (0, tar_file_path); return answer; } int arch_archive_put_import_targz (t_uchar ** errstr, struct arch_archive * a, const t_uchar * version, const t_uchar * prev_level, const t_uchar * uid, const t_uchar * txn_id, const t_uchar * level, int in_fd) { int answer; answer = a->vtable->put_import (errstr, a, version, prev_level, uid, txn_id, level, in_fd); return answer; } int arch_archive_put_import (t_uchar ** errstr, struct arch_archive * a, const t_uchar * version, const t_uchar * prev_level, const t_uchar * uid, const t_uchar * txn_id, const t_uchar * level, const t_uchar * dir) { t_uchar * dir_tail = 0; t_uchar * desired_name = 0; t_uchar * tar_file_path = 0; int in_fd; int answer; dir_tail = file_name_tail (0, dir); desired_name = str_alloc_cat_many (0, version, "--", level, str_end); invariant (!str_cmp (dir_tail, desired_name)); /* GNU tar 1.13 is busted and doesn't output to pipes correctly. */ ensure_writable (a, 0); tar_file_path = make_tmp_tar_archive (dir); in_fd = safe_open (tar_file_path, O_RDONLY, 0); answer = a->vtable->put_import (errstr, a, version, prev_level, uid, txn_id, level, in_fd); safe_close (in_fd); safe_unlink (tar_file_path); lim_free (0, dir_tail); lim_free (0, desired_name); lim_free (0, tar_file_path); return answer; } int arch_archive_put_cached_targz (t_uchar ** errstr, struct arch_archive * a, const t_uchar * revision, int in_fd) { int answer; answer = a->vtable->put_cached (errstr, a, revision, in_fd); return answer; } int arch_archive_put_cached (t_uchar ** errstr, struct arch_archive * a, const t_uchar * revision, const t_uchar * dir) { t_uchar * dir_tail = 0; t_uchar * tar_file_path = 0; int in_fd; int answer; dir_tail = file_name_tail (0, dir); invariant (!str_cmp (dir_tail, revision)); /* GNU tar 1.13 is busted and doesn't output to pipes correctly. */ ensure_writable (a, 1); tar_file_path = make_tmp_tar_archive (dir); in_fd = safe_open (tar_file_path, O_RDONLY, 0); answer = a->vtable->put_cached (errstr, a, revision, in_fd); safe_close (in_fd); safe_unlink (tar_file_path); lim_free (0, dir_tail); lim_free (0, tar_file_path); return answer; } int arch_archive_delete_cached (t_uchar ** errstr, struct arch_archive * a, const t_uchar * revision) { ensure_writable (a, 1); return a->vtable->delete_cached (errstr, a, revision); } void arch_archive_repair_non_txnal (int chatter_fd, struct arch_archive * a) { ensure_writable (a, 1); a->vtable->repair_non_txnal (chatter_fd, a); } t_uchar * arch_generate_txn_id (void) { time_t now; pid_t pid; char hostname[64]; char number[64]; t_uchar * answer; now = time (0); pid = getpid (); mem_set0 ((t_uchar *)hostname, sizeof (hostname)); gethostname (hostname, sizeof (hostname)); cvt_ulong_to_hex (number, hash_ul((t_ulong)now ^ (t_ulong)pid)); answer = str_save (0, number); cvt_ulong_to_hex (number, hash_mem ((t_uchar *)hostname, sizeof (hostname))); answer = str_realloc_cat (0, answer, number); cvt_ulong_to_hex (number, hash_ul ((t_ulong)now ^ ~(t_ulong)pid)); answer = str_realloc_cat (0, answer, number); return answer; } t_uchar * arch_previous_revision (struct arch_archive * arch, const t_uchar * revision) { t_uchar * version = 0; t_uchar * patch_level = 0; enum arch_patch_level_type current_type; enum arch_patch_level_type next_type; t_ulong current_n; t_ulong next_n; t_uchar * next_patch_level = 0; t_uchar * answer = 0; version = arch_parse_package_name (arch_ret_package_version, 0, revision); patch_level = arch_parse_package_name (arch_ret_patch_level, 0, revision); current_type = arch_analyze_patch_level (¤t_n, patch_level); if (current_type == arch_is_base0_level) { answer = 0; } else { if (((current_type == arch_is_patch_level) || (current_type == arch_is_versionfix_level)) && (current_n > 1)) { next_type = current_type; next_n = current_n - 1; } else if (current_n == 1) { next_n = 0; if (current_type == arch_is_patch_level) next_type = arch_is_base0_level; else next_type = arch_is_version_level; } else { rel_table revisions = rel_table_nil; int x; revisions = arch_archive_revisions (arch, version, 0); if (!rel_n_records (revisions)) { safe_printfmt (2, "version has no revisions (%s/%s)\n", arch->name, version); exit (2); } for (x = 0; x < rel_n_records (revisions); ++x) if (rel_peek_str (revisions, x, 0)[0] == 'v') break; invariant (x); if (x == rel_n_records (revisions)) x = rel_n_records (revisions); if (x == 1) { next_type = arch_is_base0_level; next_n = 0; } else { next_type = arch_is_patch_level; next_n = x - 1; } rel_free_table (revisions); } next_patch_level = arch_form_patch_level (next_type, next_n); answer = str_alloc_cat_many (0, version, "--", next_patch_level, str_end); } lim_free (0, version); lim_free (0, patch_level); lim_free (0, next_patch_level); return answer; } t_uchar * arch_ancestor_revision (struct arch_archive * arch, const t_uchar * revision) { enum arch_revision_type type; arch_revision_type (&type, 0, arch, revision); switch (type) { default: { panic ("arch_ancestor_revision: unrecognized revision type"); return 0; } case arch_import_revision: { return 0; } case arch_simple_revision: { t_uchar * prev_revision = 0; t_uchar * answer = 0; prev_revision = arch_previous_revision (arch, revision); answer = arch_fully_qualify (arch->name, prev_revision); lim_free (0, prev_revision); return answer; } case arch_continuation_revision: { return arch_get_continuation (arch, revision); } } } t_uchar * archive_tmp_file_name (const t_uchar * dir, const t_uchar * basename) { t_uchar * my_uid = 0; t_uchar * tmp_name = 0; my_uid = arch_my_id_uid (); tmp_name = tmp_file_name (dir, basename); tmp_name = str_realloc_cat_many (0, tmp_name, ".", my_uid, str_end); lim_free (0, my_uid); return tmp_name; } static int invoke_tar_extract (int * pid_ret) { int pipe_fds[2]; int pid; if (pipe (pipe_fds)) panic ("unable to create pipe fds for tar"); pid = fork (); if (pid == -1) panic ("unable to fork for patch"); if (pid) { *pid_ret = pid; safe_close (pipe_fds[0]); return pipe_fds[1]; } else { t_uchar ** argv; safe_close (pipe_fds[1]); argv = 0; *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = cfg__gnu_tar; *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "-m"; *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "-p"; *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "-s"; *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "-zxf"; *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "-"; *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = 0; safe_move_fd (pipe_fds[0], 0); arch_util_execvp (cfg__gnu_tar, argv); panic ("invoke_tar_extract: execvp for patch returned to caller"); exit (2); } panic ("invoke_tar_extract: not reached"); return -1; } static int wait_for_tar (int pid) { int status; int wait_pid; wait_pid = waitpid (pid, &status, 0); if (wait_pid < 0) { panic_msg ("error waiting for tar subprocess"); kill (0, SIGKILL); panic ("error waiting for subprocess"); } if (WIFSIGNALED (status)) { safe_printfmt (2, "\n"); safe_printfmt (2, "wait_for_tar: tar subprocess killed by signal %d\n", WTERMSIG (status)); safe_printfmt (2, "\n"); exit (2); return -1; } else if (!WIFEXITED (status)) { panic_msg ("waitpid returned for a non-exited process"); kill (0, SIGKILL); panic ("waitpid returned for a non-exited process"); return -1; } else { int exit_status; exit_status = WEXITSTATUS (status); return exit_status; } } t_uchar * make_tmp_tar_archive (const t_uchar * dir) { t_uchar * dir_dir = 0; t_uchar * dir_tail = 0; t_uchar * tmp_stem = 0; t_uchar * tmp_in_cwd = 0; t_uchar * tmp_path = 0; dir_dir = file_name_directory_file (0, dir); if (!dir_dir) dir_dir = str_save (0, "."); dir_tail = file_name_tail (0, dir); tmp_stem = str_alloc_cat_many (0, ",,", dir_tail, ".tar.gz", str_end); tmp_in_cwd = tmp_file_name (".", tmp_stem); tmp_path = file_name_in_vicinity (0, dir_dir, tmp_in_cwd); { int pid; int dev_null_fd; dev_null_fd = safe_open ("/dev/null", O_WRONLY, 0); pid = fork (); if (pid == -1) panic ("unable to fork for patch"); if (!pid) { t_uchar ** argv; safe_chdir (dir_dir); argv = 0; *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = cfg__gnu_tar; *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "-zcf"; *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = tmp_in_cwd; *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = dir_tail; *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = 0; safe_move_fd (dev_null_fd, 1); safe_dup2 (1, 2); arch_util_execvp (cfg__gnu_tar, argv); panic ("make_tmp_tar_archive: execvp for patch returned to caller"); exit (2); } else { int status; int wait_pid; safe_close (dev_null_fd); wait_pid = waitpid (pid, &status, 0); if (wait_pid < 0) { panic_msg ("error waiting for tar subprocess"); kill (0, SIGKILL); panic ("error waiting for subprocess"); } if (WIFSIGNALED (status)) { safe_printfmt (2, "\n"); safe_printfmt (2, "wait_for_tar: tar subprocess killed by signal %d\n", WTERMSIG (status)); safe_printfmt (2, "\n"); exit (2); return 0; } else if (!WIFEXITED (status)) { panic_msg ("waitpid returned for a non-exited process"); kill (0, SIGKILL); panic ("waitpid returned for a non-exited process"); return 0; } else { int exit_status; exit_status = WEXITSTATUS (status); if (exit_status) panic ("make_tmp_tar_archive: tar exitted with non-0 status"); } } } lim_free (0, dir_dir); lim_free (0, dir_tail); lim_free (0, tmp_in_cwd); lim_free (0, tmp_stem); return tmp_path; } static void ensure_writable (struct arch_archive * arch, int mirror_ok) { if (arch->access != arch_archive_writable) { safe_printfmt (2, "attempt to modify archive that has only read-compatibility\n archive: %s\n", arch->name); exit (2); } if (!mirror_ok) { if (!arch->client_anticipates_mirror && !!arch->mirror_of) { safe_printfmt (2, "attempt to write directly to mirror\n archive: %s\n mirror of: %s\n", arch->name, arch->mirror_of); exit (2); } if (arch->client_anticipates_mirror && !arch->mirror_of) { safe_printfmt (2, "archive is not a mirror of %s\n archive: %s\n expected mirror of: %s\n", arch->client_anticipates_mirror, arch->name, arch->client_anticipates_mirror); exit (2); } if (arch->client_anticipates_mirror && str_cmp (arch->client_anticipates_mirror, arch->mirror_of)) { safe_printfmt (2, "attempt to write to the wrong mirror\n archive: %s\n expected mirror of: %s\n got mirror of: %s\n", arch->name, arch->client_anticipates_mirror, arch->mirror_of); exit (2); } } } int arch_get_meta_int_info(struct arch_archive * arch, const t_uchar * key) { t_uchar * key_existence = arch_get_meta_info (arch, key); int result = !!key_existence; lim_free (0, key_existence); return result; } t_uchar * arch_fs_archive_category_path (const struct arch_archive * arch, const t_uchar * archive_path, const t_uchar * category) { if (arch->type == arch_archive_baz) panic ("baz does not support stand alone categories"); return file_name_in_vicinity (0, archive_path, category); } t_uchar * arch_fs_archive_branch_path (const struct arch_archive * arch, const t_uchar * archive_path, const t_uchar * package) { t_uchar * category = 0; t_uchar * category_path = 0; t_uchar * branch_path = 0; if (arch->type == arch_archive_baz) panic ("baz does not support stand alone branches"); invariant (arch_valid_package_name (package, arch_no_archive, arch_req_package, 0)); category = arch_parse_package_name (arch_ret_category, 0, package); category_path = arch_fs_archive_category_path (arch, archive_path, category); branch_path = file_name_in_vicinity (0, category_path, package); lim_free (0, category); lim_free (0, category_path); return branch_path; } t_uchar * arch_fs_archive_version_path (const struct arch_archive * arch, const t_uchar * archive_path, const t_uchar * version) { t_uchar * package = 0; t_uchar * package_path = 0; t_uchar * version_path = 0; invariant (arch_valid_package_name (version, arch_no_archive, arch_req_version, 0)); if (arch->type == arch_archive_baz) return str_save (0, version); package = arch_parse_package_name (arch_ret_package, 0, version); package_path = arch_fs_archive_branch_path (arch, archive_path, package); version_path = file_name_in_vicinity (0, package_path, version); lim_free (0, package); lim_free (0, package_path); return version_path; } t_uchar * arch_fs_archive_revision_path (const struct arch_archive * arch, const t_uchar * archive_path, const t_uchar * revision) { t_uchar * version = 0; t_uchar * version_path = 0; t_uchar * level = 0; t_uchar * revision_path = 0; invariant (arch_valid_package_name (revision, arch_no_archive, arch_req_patch_level, 0)); version = arch_parse_package_name (arch_ret_package_version, 0, revision); version_path = arch_fs_archive_version_path (arch, archive_path, version); level = arch_parse_package_name (arch_ret_patch_level, 0, revision); revision_path = file_name_in_vicinity (0, version_path, level); lim_free (0, version); lim_free (0, version_path); lim_free (0, level); return revision_path; } t_uchar * arch_fs_archive_revision_log_path (const struct arch_archive * arch, const t_uchar * archive_path, const t_uchar * revision) { t_uchar * revision_path = 0; t_uchar * log_path = 0; revision_path = arch_fs_archive_revision_path (arch, archive_path, revision); log_path = file_name_in_vicinity (0, revision_path, "log"); lim_free (0, revision_path); return log_path; } t_uchar * arch_fs_archive_changeset_path (const struct arch_archive * arch, const t_uchar * archive_path, const t_uchar * revision) { t_uchar * revision_path = 0; t_uchar * changeset_path; revision_path = arch_fs_archive_revision_path (arch, archive_path, revision); changeset_path = file_name_in_vicinity (0, revision_path, revision); changeset_path = str_realloc_cat (0, changeset_path, ".patches.tar.gz"); lim_free (0, revision_path); return changeset_path; } t_uchar * arch_fs_archive_import_path (const struct arch_archive * arch, const t_uchar * archive_path, const t_uchar * revision) { t_uchar * revision_path = 0; t_uchar * changeset_path; revision_path = arch_fs_archive_revision_path (arch, archive_path, revision); changeset_path = file_name_in_vicinity (0, revision_path, revision); changeset_path = str_realloc_cat (0, changeset_path, ".src.tar.gz"); lim_free (0, revision_path); return changeset_path; } t_uchar * arch_fs_archive_cached_path (const struct arch_archive * arch, const t_uchar * archive_path, const t_uchar * revision) { t_uchar * revision_path = 0; t_uchar * changeset_path; revision_path = arch_fs_archive_revision_path (arch, archive_path, revision); changeset_path = file_name_in_vicinity (0, revision_path, revision); changeset_path = str_realloc_cat (0, changeset_path, ".tar.gz"); lim_free (0, revision_path); return changeset_path; } t_uchar * arch_fs_archive_cached_checksum_path (const struct arch_archive * arch, const t_uchar * archive_path, const t_uchar * revision) { t_uchar * revision_path = 0; t_uchar * checksum_path = 0; revision_path = arch_fs_archive_revision_path (arch, archive_path, revision); checksum_path = file_name_in_vicinity (0, revision_path, "checksum.cacherev"); lim_free (0, revision_path); return checksum_path; } t_uchar * arch_fs_archive_continuation_path (const struct arch_archive * arch, const t_uchar * archive_path, const t_uchar * revision) { t_uchar * revision_path = 0; t_uchar * continuation_path; revision_path = arch_fs_archive_revision_path (arch, archive_path, revision); continuation_path = file_name_in_vicinity (0, revision_path, "CONTINUATION"); lim_free (0, revision_path); return continuation_path; } t_uchar * arch_fs_archive_revision_lock_unlocked_path (const struct arch_archive * arch, const t_uchar * archive_path, const t_uchar * version, const t_uchar * prev_level) { t_uchar * answer = 0; invariant (arch_valid_package_name (version, arch_no_archive, arch_req_version, 0)); if (!prev_level) { t_uchar * version_path = 0; version_path = arch_fs_archive_version_path (arch, archive_path, version); answer = file_name_in_vicinity (0, version_path, "++revision-lock"); lim_free (0, version_path); } else { t_uchar * revision = 0; t_uchar * revision_path = 0; revision = str_alloc_cat_many (0, version, "--", prev_level, str_end); revision_path = arch_fs_archive_revision_path (arch, archive_path, revision); answer = file_name_in_vicinity (0, revision_path, "++revision-lock"); lim_free (0, revision); lim_free (0, revision_path); } return answer; } t_uchar * arch_fs_archive_revision_lock_locked_path (const struct arch_archive * arch, const t_uchar * archive_path, const t_uchar * version, const t_uchar * prev_level, const t_uchar * arch_user_id, const t_uchar * txn_id) { t_uchar * version_path = 0; t_uchar * lock_basename = 0; t_uchar * answer = 0; invariant (arch_valid_package_name (version, arch_no_archive, arch_req_version, 0)); version_path = arch_fs_archive_version_path (arch, archive_path, version); lock_basename = str_alloc_cat_many (0, "++revision-lock-held--", (prev_level ? prev_level : (t_uchar *)"absolute-0"), "--", arch_user_id, (txn_id ? "--" : 0), txn_id, str_end); answer = file_name_in_vicinity (0, version_path, lock_basename); lim_free (0, version_path); lim_free (0, lock_basename); return answer; } t_uchar * arch_fs_archive_revision_lock_locked_contents_path (const struct arch_archive * arch, const t_uchar * archive_path, const t_uchar * version, const t_uchar * prev_level, const t_uchar * arch_user_id, const t_uchar * txn_id) { t_uchar * locked_path = 0; t_uchar * answer = 0; locked_path = arch_fs_archive_revision_lock_locked_path (arch, archive_path, version, prev_level, arch_user_id, txn_id); answer = file_name_in_vicinity (0, locked_path, "+contents"); lim_free (0, locked_path); return answer; } t_uchar * arch_fs_archive_revision_lock_broken_path (const struct arch_archive * arch, const t_uchar * archive_path, const t_uchar * version, const t_uchar * prev_level) { t_uchar * version_path = 0; t_uchar * lock_dir_basename = 0; t_uchar * lock_basename = 0; t_uchar * broken_dir = 0; t_uchar * answer = 0; version_path = arch_fs_archive_version_path (arch, archive_path, version); lock_dir_basename = str_alloc_cat (0, "++revision-lock-broken--", (prev_level ? prev_level : (t_uchar *)"absolute-0")); lock_basename = str_alloc_cat (0, ",,remade-lock--", (prev_level ? prev_level : (t_uchar *)"absolute-0")); broken_dir = file_name_in_vicinity (0, version_path, lock_dir_basename); answer = file_name_in_vicinity (0, broken_dir, lock_basename); lim_free (0, version_path); lim_free (0, lock_dir_basename); lim_free (0, lock_basename); lim_free (0, broken_dir); return answer; } /* tag: Tom Lord Tue May 20 00:52:06 2003 (archive.c) */