/* libraries.c: * **************************************************************** * Copyright (C) 2003 Tom Lord * * See the file "COPYING" for further information about * the copyright and warranty status of this work. */ #include "hackerlab/bugs/exception.h" #include "hackerlab/bugs/panic.h" #include "hackerlab/char/str.h" #include "hackerlab/fs/file-names.h" #include "hackerlab/vu/safe.h" #include "libfsutils/dir-listing.h" #include "libfsutils/same.h" #include "libarch/my.h" #include "libarch/namespace.h" #include "libarch/patch-logs.h" #include "libarch/changeset-utils.h" #include "libarch/libraries.h" #include "libarch/project-tree.h" #include "libarch/inode-sig.h" /* __STDC__ prototypes for static functions */ rel_table arch_library_archive_dirs (rel_table opt_lib_path, t_uchar const * const archive, int for_add) { rel_table lib_path = 0; rel_table answer = 0; int x; invariant (arch_valid_archive_name (archive)); if (opt_lib_path) { lib_path = rel_copy_table (opt_lib_path); } else { lib_path = arch_my_library_path (for_add ? arch_library_path_add_order : arch_library_path_search_order); if (!lib_path) return 0; } for (x = 0; x < rel_n_records (lib_path); ++x) { t_uchar * lib_dir; t_uchar * maybe_archive_dir = 0; lib_dir = lib_path[x][0]; maybe_archive_dir = file_name_in_vicinity (0, lib_dir, archive); if (!safe_access (maybe_archive_dir, F_OK)) { rel_add_records (&answer, rel_make_record (maybe_archive_dir, 0), 0); } lim_free (0, maybe_archive_dir); } if (for_add && !answer) { t_uchar * priority_lib_dir; t_uchar * archive_dir = 0; priority_lib_dir = lib_path[0][0]; archive_dir = file_name_in_vicinity (0, priority_lib_dir, archive); rel_add_records (&answer, rel_make_record (archive_dir, 0), 0); lim_free (0, archive_dir); } rel_free_table (lib_path); return answer; } rel_table arch_library_category_dirs (rel_table opt_lib_path, t_uchar const * const archive, t_uchar const * const category, int for_add) { rel_table answer = 0; rel_table archive_dirs = 0; int x; invariant (arch_valid_package_name (category, arch_no_archive, arch_req_category, 0)); archive_dirs = arch_library_archive_dirs (opt_lib_path, archive, for_add); if (!archive_dirs) return 0; for (x = 0; x < rel_n_records (archive_dirs); ++x) { t_uchar * archive_dir; t_uchar * maybe_category_dir = 0; archive_dir = archive_dirs[x][0]; maybe_category_dir = file_name_in_vicinity (0, archive_dir, category); if (!safe_access (maybe_category_dir, F_OK)) { rel_add_records (&answer, rel_make_record (maybe_category_dir, 0), 0); } lim_free (0, maybe_category_dir); } if (for_add && !answer) { t_uchar * priority_archive_dir; t_uchar * category_dir = 0; priority_archive_dir = archive_dirs[0][0]; category_dir = file_name_in_vicinity (0, priority_archive_dir, category); rel_add_records (&answer, rel_make_record (category_dir, 0), 0); lim_free (0, category_dir); } rel_free_table (archive_dirs); return answer; } rel_table arch_library_branch_dirs (rel_table opt_lib_path, t_uchar const * const archive, t_uchar const * const branch, int for_add) { rel_table answer = 0; t_uchar * category = 0; rel_table category_dirs = 0; int x; invariant (arch_valid_package_name (branch, arch_no_archive, arch_req_package, 0)); category = arch_parse_package_name (arch_ret_category, 0, branch); category_dirs = arch_library_category_dirs (opt_lib_path, archive, category, for_add); if (!category_dirs) return 0; for (x = 0; x < rel_n_records (category_dirs); ++x) { t_uchar * category_dir; t_uchar * maybe_branch_dir = 0; category_dir = category_dirs[x][0]; maybe_branch_dir = file_name_in_vicinity (0, category_dir, branch); if (!safe_access (maybe_branch_dir, F_OK)) { rel_add_records (&answer, rel_make_record (maybe_branch_dir, 0), 0); } lim_free (0, maybe_branch_dir); } if (for_add && !answer) { t_uchar * priority_category_dir; t_uchar * branch_dir = 0; priority_category_dir = category_dirs[0][0]; branch_dir = file_name_in_vicinity (0, priority_category_dir, branch); rel_add_records (&answer, rel_make_record (branch_dir, 0), 0); lim_free (0, branch_dir); } rel_free_table (category_dirs); lim_free (0, category); return answer; } rel_table arch_library_version_dirs (rel_table opt_lib_path, t_uchar const * const archive, t_uchar const * const version, int for_add) { rel_table answer = 0; t_uchar * branch = 0; rel_table branch_dirs = 0; int x; invariant (arch_valid_package_name (version, arch_no_archive, arch_req_version, 0)); branch = arch_parse_package_name (arch_ret_package, 0, version); branch_dirs = arch_library_branch_dirs (opt_lib_path, archive, branch, for_add); if (!branch_dirs) return 0; for (x = 0; x < rel_n_records (branch_dirs); ++x) { t_uchar * branch_dir; t_uchar * maybe_version_dir = 0; branch_dir = branch_dirs[x][0]; maybe_version_dir = file_name_in_vicinity (0, branch_dir, version); if (!safe_access (maybe_version_dir, F_OK)) { rel_add_records (&answer, rel_make_record (maybe_version_dir, 0), 0); } lim_free (0, maybe_version_dir); } if (for_add && !answer) { t_uchar * priority_branch_dir; t_uchar * version_dir = 0; priority_branch_dir = branch_dirs[0][0]; version_dir = file_name_in_vicinity (0, priority_branch_dir, version); rel_add_records (&answer, rel_make_record (version_dir, 0), 0); lim_free (0, version_dir); } rel_free_table (branch_dirs); lim_free (0, branch); return answer; } rel_table arch_library_revision_dirs (rel_table opt_lib_path, t_uchar * archive, t_uchar * revision, int for_add) { rel_table answer = 0; t_uchar * version = 0; rel_table version_dirs = 0; int x; 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_dirs = arch_library_version_dirs (opt_lib_path, archive, version, for_add); if (!version_dirs) return 0; for (x = 0; x < rel_n_records (version_dirs); ++x) { t_uchar * version_dir; t_uchar * maybe_revision_dir = 0; version_dir = version_dirs[x][0]; maybe_revision_dir = file_name_in_vicinity (0, version_dir, revision); if (!safe_access (maybe_revision_dir, F_OK)) { rel_add_records (&answer, rel_make_record (maybe_revision_dir, 0), 0); } lim_free (0, maybe_revision_dir); } if (for_add && !answer) { t_uchar * priority_version_dir; t_uchar * revision_dir = 0; priority_version_dir = version_dirs[0][0]; revision_dir = file_name_in_vicinity (0, priority_version_dir, revision); rel_add_records (&answer, rel_make_record (revision_dir, 0), 0); lim_free (0, revision_dir); } rel_free_table (version_dirs); lim_free (0, version); return answer; } arch_project_tree_t * arch_library_find (rel_table opt_lib_path, arch_patch_id *patch_id, int check_inode_sigs) { static assoc_table validated_trees = NULL; rel_table revision_dirs = 0; arch_project_tree_t * answer = NULL; revision_dirs = arch_library_revision_dirs (opt_lib_path, arch_patch_id_archive(patch_id), arch_patch_id_revision(patch_id), 0); if (rel_n_records(revision_dirs) == 0) return 0; invariant (!safe_access (revision_dirs[0][0], F_OK)); { t_uchar * tree_version = arch_tree_version (revision_dirs[0][0]); if (str_cmp (tree_version, arch_patch_id_branch (patch_id))) arch_set_tree_version (revision_dirs[0][0], patch_id); lim_free (0, tree_version); } answer = arch_project_tree_new_exact (talloc_context, revision_dirs[0][0]); if (check_inode_sigs && !assoc_ref (validated_trees, answer->root)) { if (!arch_valid_inode_sig (answer, arch_patch_id_archive(patch_id), arch_patch_id_revision(patch_id))) { safe_printfmt (2, "corrupt library (failed inode signature validation)\n revision: %s\nYou should remove this revision from your library.\n", arch_patch_id_patch_id(patch_id)); exit (2); } assoc_set (&validated_trees, answer->root, arch_patch_id_patch_id(patch_id)); } rel_free_table (revision_dirs); return answer; } t_uchar * arch_library_find_file (t_uchar * archive, t_uchar * revision, t_uchar * loc) { arch_project_tree_t * revision_tree; t_uchar * file_path = 0; arch_patch_id patch_id; arch_patch_id_init_archive (&patch_id, archive, revision); revision_tree = arch_library_find (0, &patch_id, 1); arch_patch_id_finalise (&patch_id); if (revision_tree) { file_path = file_name_in_vicinity (0, revision_tree->root, loc); if (safe_access (file_path, F_OK)) { lim_free (0, file_path); file_path = 0; } } arch_project_tree_delete (revision_tree); return file_path; } t_uchar * arch_library_find_file_by_id (t_uchar * archive, t_uchar * revision, t_uchar * id) { arch_project_tree_t * revision_tree; t_uchar * file_path = 0; arch_patch_id patch_id; arch_patch_id_init_archive (&patch_id, archive, revision); revision_tree = arch_library_find (0, &patch_id, 1); arch_patch_id_finalise (&patch_id); if (revision_tree) { t_uchar * index_file = 0; rel_table index = 0; int x; index_file = arch_library_index_file (archive, revision); index = arch_read_changeset_index (index_file); for (x = 0; x < rel_n_records (index); ++x) { if (!str_cmp (id, index[x][1])) { file_path = file_name_in_vicinity (0, revision_tree->root, index[x][0]); break; } } lim_free (0, index_file); rel_free_table (index); } arch_project_tree_delete (revision_tree); return file_path; } rel_table arch_library_archives (void) { rel_table lib_path = 0; rel_table answer = 0; int x; lib_path = arch_my_library_path (arch_library_path_search_order); for (x = 0; x < rel_n_records (lib_path); ++x) { rel_table tmp = 0; rel_table files = 0; files = directory_files (lib_path[x][0]); tmp = arch_pick_archives_by_field (files, 0); rel_append_x (&answer, tmp); rel_free_table (tmp); rel_free_table (files); } rel_sort_table_by_field (0, answer, 0); rel_uniq_by_field (&answer, 0); rel_free_table (lib_path); return answer; } rel_table arch_library_categories (t_uchar * archive) { rel_table answer = 0; rel_table archive_dirs = 0; int x; archive_dirs = arch_library_archive_dirs (0, archive, 0); for (x = 0; x < rel_n_records (archive_dirs); ++x) { rel_table files = 0; rel_table tmp = 0; files = directory_files (archive_dirs[x][0]); tmp = arch_pick_categories_by_field (files, 0); rel_append_x (&answer, tmp); rel_free_table (files); rel_free_table (tmp); } rel_sort_table_by_field (0, answer, 0); rel_uniq_by_field (&answer, 0); rel_free_table (archive_dirs); return answer; } rel_table arch_library_branches (t_uchar * archive, t_uchar * category) { rel_table answer = 0; rel_table category_dirs = 0; int x; category_dirs = arch_library_category_dirs (0, archive, category, 0); for (x = 0; x < rel_n_records (category_dirs); ++x) { rel_table files = 0; rel_table tmp = 0; files = directory_files (category_dirs[x][0]); tmp = arch_pick_branches_by_field (files, 0); rel_append_x (&answer, tmp); rel_free_table (files); rel_free_table (tmp); } rel_sort_table_by_field (0, answer, 0); rel_uniq_by_field (&answer, 0); rel_free_table (category_dirs); return answer; } rel_table arch_library_versions (t_uchar * archive, t_uchar * branch) { rel_table answer = 0; rel_table branch_dirs = 0; int x; branch_dirs = arch_library_branch_dirs (0, archive, branch, 0); for (x = 0; x < rel_n_records (branch_dirs); ++x) { rel_table files = 0; rel_table tmp = 0; files = directory_files (branch_dirs[x][0]); tmp = arch_pick_versions_by_field (files, 0); rel_append_x (&answer, tmp); rel_free_table (files); rel_free_table (tmp); } rel_sort_table_by_field (0, answer, 0); rel_uniq_by_field (&answer, 0); rel_free_table (branch_dirs); return answer; } rel_table arch_library_revisions (t_uchar const * const archive, t_uchar const * const version, int full) { rel_table answer = 0; rel_table version_dirs = 0; int x; version_dirs = arch_library_version_dirs (0, archive, version, 0); for (x = 0; x < rel_n_records (version_dirs); ++x) { rel_table files = 0; rel_table tmp = 0; int y; files = directory_files (version_dirs[x][0]); tmp = arch_pick_revisions_by_field (files, 0); for (y = 0; y < rel_n_records (tmp); ++y) { if (full) { rel_replace_record (tmp, y, rel_make_record (arch_fully_qualify (archive, tmp[y][0]), NULL)); } else { rel_replace_record (tmp, y, rel_make_record (arch_parse_package_name (arch_ret_patch_level, 0, tmp[y][0]), NULL)); } } rel_append_x (&answer, tmp); rel_free_table (files); rel_free_table (tmp); } if (full) { arch_sort_table_by_name_field (0, answer, 0); } else { arch_sort_table_by_patch_level_field (0, answer, 0); } rel_uniq_by_field (&answer, 0); rel_free_table (version_dirs); return answer; } t_uchar * arch_library_log (t_uchar * archive, t_uchar * revision) { arch_project_tree_t * rev_tree = 0; t_uchar * log_path = 0; int in_fd; t_uchar * answer = 0; size_t len; arch_patch_id patch_id; arch_patch_id_init_archive (&patch_id, archive, revision); rev_tree = arch_library_find (0, &patch_id, 1); arch_patch_id_finalise (&patch_id); log_path = arch_log_file (rev_tree->root, archive, revision); in_fd = safe_open (log_path, O_RDONLY, 0); safe_file_to_string (&answer, &len, in_fd); answer = lim_realloc (0, answer, len + 1); answer[len] = 0; safe_close (in_fd); arch_project_tree_delete (rev_tree); lim_free (0, log_path); return answer; } /** * FIXME give this a directory hint for functions that * already have found the library dir */ t_uchar * arch_library_index_file (t_uchar const * const archive, t_uchar const * const revision) { arch_project_tree_t * rev_tree; t_uchar * answer = 0; arch_patch_id patch_id; arch_patch_id_init_archive (&patch_id, archive, revision); rev_tree = arch_library_find (0, &patch_id, 1); arch_patch_id_finalise (&patch_id); invariant (!!rev_tree); answer = file_name_in_vicinity (0, rev_tree->root, ",,index"); arch_project_tree_delete (rev_tree); return answer; } rel_table arch_library_index (arch_patch_id * revision) { t_uchar * index_path = 0; rel_table answer = 0; index_path = arch_library_index_file (arch_patch_id_archive (revision), arch_patch_id_revision (revision)); answer = arch_read_changeset_index (index_path); lim_free (0, index_path); return answer; } int arch_library_has_archive (t_uchar const * const lib, t_uchar const * const archive) { t_uchar * path = file_name_in_vicinity (0, lib, archive); int answer; answer = !safe_access (path, F_OK); lim_free (0, path); return answer; } int arch_library_has_category (t_uchar const * const lib, t_uchar const * const archive, t_uchar const * const category) { t_uchar * archive_path = file_name_in_vicinity (0, lib, archive); t_uchar * category_path = file_name_in_vicinity (0, archive_path, category); int answer; answer = !safe_access (category_path, F_OK); lim_free (0, archive_path); lim_free (0, category_path); return answer; } int arch_library_has_branch (t_uchar const * const lib, t_uchar const * const archive, t_uchar const * const branch) { t_uchar * category = arch_parse_package_name (arch_ret_category, 0, branch); t_uchar * archive_path = file_name_in_vicinity (0, lib, archive); t_uchar * category_path = file_name_in_vicinity (0, archive_path, category); t_uchar * branch_path = file_name_in_vicinity (0, category_path, branch); int answer; answer = !safe_access (branch_path, F_OK); lim_free (0, category); lim_free (0, archive_path); lim_free (0, category_path); lim_free (0, branch_path); return answer; } int arch_library_has_version (t_uchar const * const lib, t_uchar const * const archive, t_uchar const * const version) { t_uchar * category = arch_parse_package_name (arch_ret_category, 0, version); t_uchar * branch = arch_parse_package_name (arch_ret_package, 0, version); t_uchar * archive_path = file_name_in_vicinity (0, lib, archive); t_uchar * category_path = file_name_in_vicinity (0, archive_path, category); t_uchar * branch_path = file_name_in_vicinity (0, category_path, branch); t_uchar * version_path = file_name_in_vicinity (0, branch_path, version); int answer; answer = !safe_access (version_path, F_OK); lim_free (0, category); lim_free (0, branch); lim_free (0, archive_path); lim_free (0, category_path); lim_free (0, branch_path); lim_free (0, version_path); return answer; } t_uchar * arch_library_revision_dir_in_lib (t_uchar const * const lib, arch_patch_id * patch_id) { t_uchar * branch = arch_parse_package_name (arch_ret_package, 0, arch_patch_id_revision (patch_id)); t_uchar * category = arch_parse_package_name (arch_ret_category, 0, arch_patch_id_revision (patch_id)); t_uchar * archive_path = file_name_in_vicinity (0, lib, arch_patch_id_archive (patch_id)); t_uchar * category_path = file_name_in_vicinity (0, archive_path, category); t_uchar * branch_path = file_name_in_vicinity (0, category_path, branch); t_uchar * version_path = file_name_in_vicinity (0, branch_path, arch_patch_id_version (patch_id)); t_uchar * revision_path = file_name_in_vicinity (0, version_path, arch_patch_id_revision (patch_id)); lim_free (0, branch); lim_free (0, category); lim_free (0, archive_path); lim_free (0, category_path); lim_free (0, branch_path); lim_free (0, version_path); return revision_path; } int arch_library_is_greedy (t_uchar * lib) { t_uchar * greed_path = file_name_in_vicinity (0, lib, "=greedy"); int answer = 0; answer = !safe_access (greed_path, F_OK); lim_free (0, greed_path); return answer; } void arch_set_library_greediness (t_uchar * lib, int setting) { t_uchar * greed_path = file_name_in_vicinity (0, lib, "=greedy"); if (setting) { int fd; fd = safe_open (greed_path, O_RDONLY | O_CREAT, 0666); safe_close (fd); } else { if (!safe_access (greed_path, F_OK)) safe_unlink (greed_path); } lim_free (0, greed_path); } int arch_library_is_sparse (t_uchar * lib) { t_uchar * sparse_path = file_name_in_vicinity (0, lib, "=sparse"); int answer = 0; answer = !safe_access (sparse_path, F_OK); lim_free (0, sparse_path); return answer; } void arch_set_library_sparseness (t_uchar * lib, int setting) { t_uchar * sparse_path = file_name_in_vicinity (0, lib, "=sparse"); if (setting) { int fd; fd = safe_open (sparse_path, O_RDONLY | O_CREAT, 0666); safe_close (fd); } else { if (!safe_access (sparse_path, F_OK)) safe_unlink (sparse_path); } lim_free (0, sparse_path); } void arch_verify_is_library (t_uchar * lib) { rel_table lib_path = 0; int x; lib_path = arch_my_library_path (arch_library_path_search_order); for (x = 0; x < rel_n_records (lib_path); ++x) { if (names_same_inode (lib, lib_path[x][0])) return; } safe_printfmt (2, "baz: indicated library is not on library path\n dir %s\n", lib); exit (2); } /* tag: Tom Lord Wed May 21 13:56:29 2003 (libraries.c) */