/* 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)
*/
syntax highlighted by Code2HTML, v. 0.9.1