/* changeset-report.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/panic.h"
#include "hackerlab/char/str.h"
#include "hackerlab/fs/file-names.h"
#include "hackerlab/mem/mem.h"
#include "hackerlab/vu/safe.h"
#include "hackerlab/arrays/ar.h"
#include "hackerlab/char/pika-escaping-utils.h"
#include "libfsutils/read-line.h"
#include "libawk/relassoc.h"
#include "libfsutils/find-utils.h"
#include "libfsutils/ensure-dir.h"
#include "libfsutils/copy-file.h"
#include "libarch/diffs.h"
#include "libarch/changeset-utils.h"
#include "libarch/changeset-report.h"
/* __STDC__ prototypes for static functions */
static void fix_mod_locs (assoc_table loc_of, rel_table table);
static void arch_print_file_metadata_diffs (int out_fd,
struct arch_changeset_report * report,
int escape_classes);
static void arch_print_dir_metadata_diffs (int out_fd,
struct arch_changeset_report * report,
int escape_classes);
static void print_custom_diffs(struct arch_changeset_report * report,
t_uchar * orig_dir, t_uchar * mod_dir,
t_uchar ** opts);
static void arch_print_file_diffs (struct arch_changeset_report * report);
static void arch_print_added_file_diffs (struct arch_changeset_report * report);
static void
print_removed_file_diffs (struct arch_changeset_report * report,
t_uchar ** opts);
static void print_file_metadata (int out_fd,
struct arch_changeset_report * report,
int escape_classes);
static void print_dir_metadata (int out_fd,
struct arch_changeset_report * report,
int escape_classes);
static void print_diffs_new(struct arch_changeset_report * report);
static void report_unique_files_and_symlinks (rel_table * files, rel_table * symlinks,
rel_table index,
t_uchar * archive_dir, t_uchar * archive_basename);
static void find_renames (rel_table * out, rel_table common, assoc_table orig_dir_id_of, assoc_table mod_dir_id_of);
int
arch_any_changes (struct arch_changeset_report * report)
{
return (report->removed_dirs
|| report->added_dirs
|| report->removed_files
|| report->added_files
|| report->removed_symlinks
|| report->added_symlinks
|| report->renamed_files
|| report->renamed_dirs
|| report->patched_regular_files
|| report->patched_symlinks
|| report->patched_binaries
|| report->file_metadata_changed
|| report->dir_metadata_changed
|| report->symlink_to_file
|| report->file_to_symlink);
}
void
arch_evaluate_changeset (struct arch_changeset_report * report, t_uchar * path)
{
t_uchar * orig_files_index_path = 0;
t_uchar * orig_dirs_index_path = 0;
t_uchar * mod_files_index_path = 0;
t_uchar * mod_dirs_index_path = 0;
rel_table removed_dirs_index = 0;
rel_table added_dirs_index = 0;
rel_table removed_files_and_symlinks_index = 0;
rel_table added_files_and_symlinks_index = 0;
rel_table common_files_index = 0; /* [0] origloc [1] modloc [2] id */
rel_table common_dirs_index = 0; /* [0] origloc [1] modloc [2] id */
assoc_table orig_dir_loc_of = 0;
assoc_table orig_dir_id_of = 0;
assoc_table orig_file_loc_of = 0;
assoc_table orig_file_id_of = 0;
assoc_table mod_dir_loc_of = 0;
assoc_table mod_dir_id_of = 0;
assoc_table mod_file_loc_of = 0;
assoc_table mod_file_id_of = 0;
orig_files_index_path = file_name_in_vicinity (0, path, "orig-files-index");
orig_dirs_index_path = file_name_in_vicinity (0, path, "orig-dirs-index");
mod_files_index_path = file_name_in_vicinity (0, path, "mod-files-index");
mod_dirs_index_path = file_name_in_vicinity (0, path, "mod-dirs-index");
report->orig_files_index = arch_read_changeset_index (orig_files_index_path);
report->orig_dirs_index = arch_read_changeset_index (orig_dirs_index_path);
report->mod_files_index = arch_read_changeset_index (mod_files_index_path);
report->mod_dirs_index = arch_read_changeset_index (mod_dirs_index_path);
/* just to be sure:
*/
rel_sort_table_by_field (0, report->orig_files_index, 1);
rel_sort_table_by_field (0, report->orig_dirs_index, 1);
rel_sort_table_by_field (0, report->mod_files_index, 1);
rel_sort_table_by_field (0, report->mod_dirs_index, 1);
orig_dir_id_of = rel_to_assoc (report->orig_dirs_index, 0, 1);
orig_dir_loc_of = rel_to_assoc (report->orig_dirs_index, 1, 0);
orig_file_id_of = rel_to_assoc (report->orig_files_index, 0, 1);
orig_file_loc_of = rel_to_assoc (report->orig_files_index, 1, 0);
mod_dir_id_of = rel_to_assoc (report->mod_dirs_index, 0, 1);
mod_dir_loc_of = rel_to_assoc (report->mod_dirs_index, 1, 0);
mod_file_id_of = rel_to_assoc (report->mod_files_index, 0, 1);
mod_file_loc_of = rel_to_assoc (report->mod_files_index, 1, 0);
/****************************************************************
* Removed and added directories
*/
{
t_uchar * original_only_dir_metadata_file = 0;
t_uchar * modified_only_dir_metadata_file = 0;
rel_table original_only_dir_metadata = 0;
rel_table modified_only_dir_metadata = 0;
rel_table orig_dirs_by_name = 0;
rel_table mod_dirs_by_name = 0;
rel_table t; /* [0] name [1] id -- sort 0*/
rel_table t2; /* [0] name [1] id [2] name -- sort 0 -- of dirs sans perms */
original_only_dir_metadata_file = file_name_in_vicinity (0, path, "original-only-dir-metadata");
modified_only_dir_metadata_file = file_name_in_vicinity (0, path, "modified-only-dir-metadata");
original_only_dir_metadata = arch_read_changeset_dir_metadata (original_only_dir_metadata_file);
modified_only_dir_metadata = arch_read_changeset_dir_metadata (modified_only_dir_metadata_file);
orig_dirs_by_name = rel_copy_table (report->orig_dirs_index);
rel_sort_table_by_field (0, orig_dirs_by_name, 0);
mod_dirs_by_name = rel_copy_table (report->mod_dirs_index);
rel_sort_table_by_field (0, mod_dirs_by_name, 0);
removed_dirs_index = rel_join (1, rel_join_output (1,0, 1,1, -1), 1, 1, report->orig_dirs_index, report->mod_dirs_index);
added_dirs_index = rel_join (2, rel_join_output (2,0, 2,1, -1), 1, 1, report->orig_dirs_index, report->mod_dirs_index);
t = rel_copy_table (removed_dirs_index);
rel_sort_table_by_field (0, t, 0);
report->removed_dirs = rel_join (-1, rel_join_output (1,0, 1,1, 2,1, -1), 0, 0, t, original_only_dir_metadata);
t2 = rel_join (1, rel_join_output (1,0, 1,1, 1,0, -1), 0, 0, t, original_only_dir_metadata);
rel_append_x (&report->removed_dirs, t2);
rel_sort_table_by_field (0, report->removed_dirs, 0);
rel_free_table (t);
rel_free_table (t2);
invariant (rel_n_records (report->removed_dirs) == rel_n_records (removed_dirs_index));
t = rel_copy_table (added_dirs_index);
rel_sort_table_by_field (0, t, 0);
report->added_dirs = rel_join (-1, rel_join_output (1,0, 1,1, 2,1, -1), 0, 0, t, modified_only_dir_metadata);
t2 = rel_join (1, rel_join_output (1,0, 1,1, 1,0, -1), 0, 0, t, modified_only_dir_metadata);
rel_append_x (&report->added_dirs, t2);
rel_sort_table_by_field (0, report->added_dirs, 0);
rel_free_table (t);
rel_free_table (t2);
invariant (rel_n_records (report->added_dirs) == rel_n_records (added_dirs_index));
lim_free (0, original_only_dir_metadata_file);
lim_free (0, modified_only_dir_metadata_file);
rel_free_table (original_only_dir_metadata);
rel_free_table (modified_only_dir_metadata);
rel_free_table (orig_dirs_by_name);
rel_free_table (mod_dirs_by_name);
}
/****************************************************************
* Removed and added filenames and symlinks
*/
removed_files_and_symlinks_index = rel_join (1, rel_join_output (1,0, 1,1, -1), 1, 1, report->orig_files_index, report->mod_files_index);
added_files_and_symlinks_index = rel_join (2, rel_join_output (2,0, 2,1, -1), 1, 1, report->orig_files_index, report->mod_files_index);
report_unique_files_and_symlinks (&report->removed_files, &report->removed_symlinks,
removed_files_and_symlinks_index,
path, "removed-files-archive");
report_unique_files_and_symlinks (&report->added_files, &report->added_symlinks,
added_files_and_symlinks_index,
path, "new-files-archive");
/****************************************************************
* renamed files and dirs
*/
common_dirs_index = rel_join (-1, rel_join_output (1,0, 2,0, 1,1, -1), 1, 1, report->orig_dirs_index, report->mod_dirs_index);
common_files_index = rel_join (-1, rel_join_output (1,0, 2,0, 1,1, -1), 1, 1, report->orig_files_index, report->mod_files_index);
find_renames (&report->renamed_dirs, common_dirs_index, orig_dir_id_of, mod_dir_id_of);
find_renames (&report->renamed_files, common_files_index, orig_dir_id_of, mod_dir_id_of);
/****************************************************************
* Identify patches
*/
{
int lim;
int x;
int here_fd;
t_uchar * patches_root;
rel_table patches_files = 0;
assoc_table saw_patches_file = 0;
patches_root = file_name_in_vicinity (0, path, "patches");
here_fd = safe_open (".", O_RDONLY, 0);
safe_chdir (patches_root);
find_files (&patches_files, ".");
safe_fchdir (here_fd);
safe_close (here_fd);
saw_patches_file = rel_to_assoc (patches_files, 0, 0);
lim = rel_n_records (patches_files);
for (x = 0; x < lim; ++x)
{
t_uchar * patch_file = 0;
t_uchar * patch_file_tail = 0;
t_uchar * patch_file_suffix = 0;
t_uchar * patch_file_loc = 0;
rel_table * dest = 0;
t_uchar * complement_patch = 0;
t_uchar * patch_file_path = 0;
t_uchar * id = 0; /* not allocated */
patch_file = patches_files[x][0];
patch_file_suffix = str_chr_rindex (patch_file, '.');
patch_file_tail = file_name_tail (0, patch_file);
/* Compute the loc and the appropriate table for this
* this patch. (patch_file_loc and dest)
*/
if (!str_cmp (patch_file_tail, "=dir-meta-orig"))
{
patch_file_loc = file_name_directory_file (0, patch_file);
dest = &report->dir_metadata_changed;
id = assoc_ref (mod_dir_id_of, patch_file_loc);
}
else if (!str_cmp (patch_file_suffix, ".link-orig"))
{
patch_file_loc = str_save_n (0, patch_file, patch_file_suffix - patch_file);
complement_patch = str_alloc_cat (0, patch_file_loc, ".link-mod");
if (assoc_ref (saw_patches_file, complement_patch))
dest = &report->patched_symlinks;
else
dest = &report->symlink_to_file;
id = assoc_ref (mod_file_id_of, patch_file_loc);
}
else if (!str_cmp (patch_file_suffix, ".original"))
{
patch_file_loc = str_save_n (0, patch_file, patch_file_suffix - patch_file);
complement_patch = str_alloc_cat (0, patch_file_loc, ".modified");
if (assoc_ref (saw_patches_file, complement_patch))
dest = &report->patched_binaries;
else
dest = &report->file_to_symlink;
id = assoc_ref (mod_file_id_of, patch_file_loc);
}
else if (!str_cmp (patch_file_suffix, ".patch"))
{
patch_file_loc = str_save_n (0, patch_file, patch_file_suffix - patch_file);
dest = &report->patched_regular_files;
id = assoc_ref (mod_file_id_of, patch_file_loc);
}
else if (!str_cmp (patch_file_suffix, ".meta-orig"))
{
patch_file_loc = str_save_n (0, patch_file, patch_file_suffix - patch_file);
dest = &report->file_metadata_changed;
id = assoc_ref (mod_file_id_of, patch_file_loc);
}
if (dest && patch_file_loc)
{
patch_file_path = file_name_in_vicinity (0, patches_root, patch_file_loc);
rel_add_records (dest, rel_make_record (patch_file_loc, id, patch_file_path, 0), 0);
}
lim_free (0, patch_file_tail);
lim_free (0, patch_file_loc);
lim_free (0, complement_patch);
lim_free (0, patch_file_path);
}
lim_free (0, patches_root);
rel_free_table (patches_files);
free_assoc_table (saw_patches_file);
}
rel_sort_table_by_field (0, report->removed_dirs, 0);
rel_sort_table_by_field (0, report->added_dirs, 0);
rel_sort_table_by_field (0, report->removed_files, 0);
rel_sort_table_by_field (0, report->added_files, 0);
rel_sort_table_by_field (0, report->removed_symlinks, 0);
rel_sort_table_by_field (0, report->added_symlinks, 0);
rel_sort_table_by_field (0, report->renamed_files, 0);
rel_sort_table_by_field (0, report->renamed_dirs, 0);
rel_sort_table_by_field (0, report->patched_regular_files, 0);
rel_sort_table_by_field (0, report->patched_symlinks, 0);
rel_sort_table_by_field (0, report->patched_binaries, 0);
rel_sort_table_by_field (0, report->file_metadata_changed, 0);
rel_sort_table_by_field (0, report->dir_metadata_changed, 0);
rel_sort_table_by_field (0, report->symlink_to_file, 0);
rel_sort_table_by_field (0, report->file_to_symlink, 0);
lim_free (0, orig_files_index_path);
lim_free (0, orig_dirs_index_path);
lim_free (0, mod_files_index_path);
lim_free (0, mod_dirs_index_path);
rel_free_table (removed_dirs_index);
rel_free_table (added_dirs_index);
rel_free_table (removed_files_and_symlinks_index);
rel_free_table (added_files_and_symlinks_index);
free_assoc_table (orig_dir_loc_of);
free_assoc_table (orig_dir_id_of);
free_assoc_table (orig_file_loc_of);
free_assoc_table (orig_file_id_of);
free_assoc_table (mod_dir_loc_of);
free_assoc_table (mod_dir_id_of);
free_assoc_table (mod_file_loc_of);
free_assoc_table (mod_file_id_of);
rel_free_table (common_files_index);
rel_free_table (common_dirs_index);
}
void
arch_reverse_changeset (struct arch_changeset_report * report)
{
rel_table t;
int x;
assoc_table new_mod_file_loc_of = 0;
assoc_table new_mod_dir_loc_of = 0;
t = report->orig_files_index;
report->orig_files_index = report->mod_files_index;
report->mod_files_index = t;
t = report->orig_dirs_index;
report->orig_dirs_index = report->mod_dirs_index;
report->mod_dirs_index = t;
t = report->removed_dirs;
report->removed_dirs = report->added_dirs;
report->added_dirs = t;
t = report->removed_files;
report->removed_files = report->added_files;
report->added_files = t;
t = report->removed_symlinks;
report->removed_symlinks = report->added_symlinks;
report->added_symlinks = t;
for (x = 0; x < rel_n_records (report->renamed_files); ++x)
{
rel_replace_record (report->renamed_files, x,
rel_make_record (report->renamed_files[x][1],
report->renamed_files[x][0],
report->renamed_files[x][2],
NULL));
}
for (x = 0; x < rel_n_records (report->renamed_dirs); ++x)
{
rel_replace_record (report->renamed_dirs, x,
rel_make_record (report->renamed_dirs[x][1],
report->renamed_dirs[x][0],
report->renamed_dirs[x][2],
NULL));
}
new_mod_file_loc_of = rel_to_assoc (report->mod_files_index, 1, 0);
new_mod_dir_loc_of = rel_to_assoc (report->mod_dirs_index, 1, 0);
fix_mod_locs (new_mod_file_loc_of, report->patched_regular_files);
fix_mod_locs (new_mod_file_loc_of, report->patched_symlinks);
fix_mod_locs (new_mod_file_loc_of, report->patched_binaries);
fix_mod_locs (new_mod_file_loc_of, report->file_metadata_changed);
fix_mod_locs (new_mod_dir_loc_of, report->dir_metadata_changed);
fix_mod_locs (new_mod_file_loc_of, report->symlink_to_file);
fix_mod_locs (new_mod_file_loc_of, report->file_to_symlink);
}
static void
fix_mod_locs (assoc_table loc_of, rel_table table)
{
int x;
for (x = 0; x < rel_n_records (table); ++x)
{
t_uchar * new_loc = 0;
t_uchar * id;
id = table[x][1];
new_loc = assoc_ref (loc_of, id);
if (new_loc)
new_loc = str_save (0, new_loc);
rel_replace_record (table, x, rel_make_record
(new_loc,
table[x][1],
table[x][2],
NULL));
}
}
static void
arch_print_file_metadata_diffs (int out_fd,
struct arch_changeset_report * report,
int escape_classes)
{
int x;
for (x = 0; x < rel_n_records (report->file_metadata_changed); ++x)
{
t_uchar * orig_meta_path = 0;
t_uchar * mod_meta_path = 0;
t_uchar * orig_meta = 0;
t_uchar * mod_meta = 0;
t_uchar * file_metadata_changed = 0;
file_metadata_changed = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->file_metadata_changed[x][0]);
safe_printfmt (out_fd, " %s\n", file_metadata_changed);
orig_meta_path = str_alloc_cat (0, report->file_metadata_changed[x][2], ".meta-orig");
mod_meta_path = str_alloc_cat (0, report->file_metadata_changed[x][2], ".meta-mod");
orig_meta = read_line_from_file (orig_meta_path);
mod_meta = read_line_from_file (mod_meta_path);
safe_printfmt (out_fd, " %s\n => %s\n", orig_meta, mod_meta);
lim_free (0, file_metadata_changed);
lim_free (0, orig_meta_path);
lim_free (0, mod_meta_path);
lim_free (0, orig_meta);
lim_free (0, mod_meta);
}
}
static void
arch_print_dir_metadata_diffs (int out_fd,
struct arch_changeset_report * report,
int escape_classes)
{
int x;
for (x = 0; x < rel_n_records (report->dir_metadata_changed); ++x)
{
t_uchar * orig_meta_path = 0;
t_uchar * mod_meta_path = 0;
t_uchar * orig_meta = 0;
t_uchar * mod_meta = 0;
t_uchar * dir_metadata_changed = 0;
dir_metadata_changed = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->dir_metadata_changed[x][0]);
safe_printfmt (out_fd, " %s\n", dir_metadata_changed);
orig_meta_path = file_name_in_vicinity (0, report->dir_metadata_changed[x][2], "=dir-meta-orig");
mod_meta_path = file_name_in_vicinity (0, report->dir_metadata_changed[x][2], "=dir-meta-mod");
orig_meta = read_line_from_file (orig_meta_path);
mod_meta = read_line_from_file (mod_meta_path);
safe_printfmt (out_fd, " %s\n => %s\n", orig_meta, mod_meta);
lim_free (0, dir_metadata_changed);
lim_free (0, orig_meta_path);
lim_free (0, mod_meta_path);
lim_free (0, orig_meta);
lim_free (0, mod_meta);
}
}
static void
arch_print_file_diffs (struct arch_changeset_report * report)
{
int x;
for (x = 0; x < rel_n_records (report->patched_regular_files); ++x)
{
t_uchar * patch_file;
int in_fd;
patch_file = str_alloc_cat (0, report->patched_regular_files[x][2], ".patch");
in_fd = safe_open (patch_file, O_RDONLY, 0);
copy_fd (in_fd, 1);
safe_printfmt (1, "\n\n");
safe_close (in_fd);
lim_free (0, patch_file);
}
}
static void
arch_print_added_file_diffs (struct arch_changeset_report * report)
{
int x;
for (x = 0; x < rel_n_records (report->added_files); ++x)
{
arch_really_invoke_diff (1, "/dev/null", NULL, report->added_files[x][2], report->added_files[x][0], NULL);
}
}
static void print_file_metadata (int out_fd, struct arch_changeset_report *
report, int escape_classes)
{
if (report->file_metadata_changed)
{
safe_printfmt (out_fd, "* file metadata changed\n\n");
arch_print_file_metadata_diffs (out_fd, report, escape_classes);
safe_printfmt (out_fd, "\n");
}
}
static void print_dir_metadata (int out_fd,
struct arch_changeset_report * report,
int escape_classes)
{
if (report->dir_metadata_changed)
{
safe_printfmt (out_fd, "* dir metadata changed\n\n");
arch_print_dir_metadata_diffs (out_fd, report, escape_classes);
safe_printfmt (out_fd, "\n");
}
}
static void print_diffs_new(struct arch_changeset_report * report)
{
if (report->patched_regular_files)
{
safe_printfmt (1, "* modified files\n\n");
arch_print_file_diffs (report);
safe_printfmt (1, "\n");
}
if (report->added_files)
{
safe_printfmt (1, "* added files\n\n");
arch_print_added_file_diffs (report);
safe_printfmt (1, "\n");
}
print_removed_file_diffs(report, NULL);
}
/**
* \brief Write custom diffs for to a file descriptor
*
* The changeset report is used to determine which files to diff, and the
* partial file paths. The orig_dir and mod_dir are used to produce full
* paths. diff is invoked to produce the output.
*
* \param report The report to use for output
* \param orig_dir The path to a copy of the ORIG tree
* \param mod_dir The path to a copy of the MOD tree
*/
static void
print_custom_diffs (struct arch_changeset_report * report, t_uchar * orig_dir, t_uchar * mod_dir, t_uchar ** opts)
{
if (report->patched_regular_files)
{
int x;
assoc_table orig_paths = rel_to_assoc (report->orig_files_index, 1, 0);
safe_printfmt (1, "* modified files\n\n");
for (x = 0; x < rel_n_records (report->patched_regular_files); ++x)
{
t_uchar * id = report->patched_regular_files[x][1];
t_uchar * orig_part_path = assoc_ref(orig_paths, id);
t_uchar * orig_path = file_name_in_vicinity(0, orig_dir, orig_part_path);
t_uchar * mod_path = file_name_in_vicinity(0, mod_dir, report->patched_regular_files[x][0]);
arch_really_invoke_diff (1, orig_path, orig_part_path, mod_path, report->patched_regular_files[x][0], (char **)opts);
lim_free(0, mod_path);
lim_free(0, orig_path);
}
safe_printfmt (1, "\n");
free_assoc_table (orig_paths);
}
if (report->added_files)
{
int x;
safe_printfmt (1, "* added files\n\n");
for (x = 0; x < rel_n_records (report->added_files); ++x)
{
arch_really_invoke_diff (1, "/dev/null", NULL, report->added_files[x][2], report->added_files[x][0], (char**)opts);
}
safe_printfmt (1, "\n");
}
print_removed_file_diffs (report, opts);
}
/**
* \brief Print the diffs for any removed files to output.
*
* If no files were removed, no output is produced
* \param report The changeset report to generate results for
* \param opts Additional parameters to pass to diff, or NULL
*/
static void
print_removed_file_diffs (struct arch_changeset_report * report, t_uchar ** opts)
{
if (report->removed_files)
{
int x;
safe_printfmt (1, "* removed files\n\n");
for (x = 0; x < rel_n_records (report->removed_files); ++x)
{
arch_really_invoke_diff (1, report->removed_files[x][2], report->removed_files[x][0], "/dev/null", NULL, (char**)opts);
}
safe_printfmt (1, "\n");
}
}
/**
* \brief Write a changeset report with custom diffs to a file descriptor
*
* \param report The report to use for output
* \param orig_dir The path to a copy of the ORIG tree
* \param mod_dir The path to a copy of the MOD tree
* \param escape_classes The types of characters that should be escaped
* \todo Consider reimplementing so that a custom changeset is generated, not
* custom diffs.
*/
void
arch_print_changeset_custom_diffs (struct arch_changeset_report * report, t_uchar * orig_dir, t_uchar * mod_dir, t_uchar ** opts, int escape_classes)
{
print_file_metadata (1, report, escape_classes);
print_dir_metadata (1, report, escape_classes);
if (opts == NULL)
print_diffs_new (report);
else
print_custom_diffs (report, orig_dir, mod_dir, opts);
}
void
arch_print_changeset (struct arch_changeset_report * report, int diffs, int escape_classes)
{
int x;
int out_fd = 1;
if (report->removed_dirs)
{
safe_printfmt (1, "* removed directories\n\n");
for (x = 0; x < rel_n_records (report->removed_dirs); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->removed_dirs[x][0]);
safe_printfmt (1, " %s\n", no_dot (item));
lim_free (0, item);
}
safe_printfmt (1, "\n");
}
if (report->added_dirs)
{
safe_printfmt (1, "* added directories\n\n");
for (x = 0; x < rel_n_records (report->added_dirs); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->added_dirs[x][0]);
safe_printfmt (1, " %s\n", no_dot (item));
lim_free (0, item);
}
safe_printfmt (1, "\n");
}
if (report->removed_files)
{
safe_printfmt (out_fd, "* removed files\n\n");
for (x = 0; x < rel_n_records (report->removed_files); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->removed_files[x][0]);
safe_printfmt (out_fd, " %s\n", no_dot (item));
lim_free (0, item);
}
safe_printfmt (out_fd, "\n");
}
if (report->removed_symlinks)
{
safe_printfmt (out_fd, "* removed symlinks\n\n");
for (x = 0; x < rel_n_records (report->removed_symlinks); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->removed_symlinks[x][0]);
safe_printfmt (out_fd, " %s\n", no_dot (item));
lim_free (0, item);
}
safe_printfmt (out_fd, "\n");
}
if (report->added_symlinks)
{
safe_printfmt (out_fd, "* added symlinks\n\n");
for (x = 0; x < rel_n_records (report->added_symlinks); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->added_symlinks[x][0]);
safe_printfmt (out_fd, " %s\n", no_dot (item));
lim_free (0, item);
}
safe_printfmt (out_fd, "\n");
}
if (report->renamed_files)
{
safe_printfmt (out_fd, "* renamed files and symlinks\n\n");
for (x = 0; x < rel_n_records (report->renamed_files); ++x)
{
t_uchar * item1;
t_uchar * item2;
item1 = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->renamed_files[x][0]);
item2 = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->renamed_files[x][1]);
safe_printfmt (out_fd, " %s\n => %s\n\n", no_dot (item1), no_dot (item2));
lim_free (0, item2);
lim_free (0, item1);
}
}
if (report->renamed_dirs)
{
safe_printfmt (out_fd, "* renamed directories\n\n");
for (x = 0; x < rel_n_records (report->renamed_dirs); ++x)
{
t_uchar * item1;
t_uchar * item2;
item1 = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->renamed_dirs[x][0]);
item2 = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->renamed_dirs[x][1]);
safe_printfmt (out_fd, " %s\n => %s\n\n", no_dot (item1), no_dot (item2));
lim_free (0, item2);
lim_free (0, item1);
}
}
if (report->file_to_symlink)
{
safe_printfmt (out_fd, "* files replaced by symlinks \n\n");
for (x = 0; x < rel_n_records (report->file_to_symlink); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->file_to_symlink[x][0]);
safe_printfmt (out_fd, " %s\n", no_dot (item));
lim_free (0, item);
}
safe_printfmt (out_fd, "\n");
}
if (report->symlink_to_file)
{
safe_printfmt (out_fd, "* symlinks replaced by files\n\n");
for (x = 0; x < rel_n_records (report->symlink_to_file); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->symlink_to_file[x][0]);
safe_printfmt (out_fd, " %s\n", no_dot (item));
lim_free (0, item);
}
safe_printfmt (out_fd, "\n");
}
if (report->file_metadata_changed)
{
safe_printfmt (out_fd, "* file metadata changed\n\n");
if (diffs)
{
arch_print_file_metadata_diffs (out_fd, report, escape_classes);
}
else
{
for (x = 0; x < rel_n_records (report->file_metadata_changed); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->file_metadata_changed[x][0]);
safe_printfmt (out_fd, " %s\n", no_dot (item));
lim_free (0, item);
}
}
safe_printfmt (out_fd, "\n");
}
if (report->dir_metadata_changed)
{
safe_printfmt (out_fd, "* dir metadata changed\n\n");
if (diffs)
{
arch_print_dir_metadata_diffs (out_fd, report, escape_classes);
}
else
{
for (x = 0; x < rel_n_records (report->dir_metadata_changed); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->dir_metadata_changed[x][0]);
safe_printfmt (out_fd, " %s\n", no_dot (item));
lim_free (0, item);
}
}
safe_printfmt (out_fd, "\n");
}
if (report->patched_symlinks)
{
safe_printfmt (out_fd, "* retargeted symlinks\n\n");
for (x = 0; x < rel_n_records (report->patched_symlinks); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->patched_symlinks[x][0]);
safe_printfmt (out_fd, " %s\n", no_dot (item));
lim_free (0, item);
}
safe_printfmt (out_fd, "\n");
}
if (report->patched_binaries)
{
safe_printfmt (out_fd, "* modified binary files\n\n");
for (x = 0; x < rel_n_records (report->patched_binaries); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->patched_binaries[x][0]);
safe_printfmt (out_fd, " %s\n", no_dot (item));
lim_free (0, item);
}
safe_printfmt (out_fd, "\n");
}
if (report->added_files)
{
safe_printfmt (out_fd, "* added files\n\n");
for (x = 0; x < rel_n_records (report->added_files); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->added_files[x][0]);
safe_printfmt (out_fd, " %s\n", no_dot (item));
if (diffs)
{
arch_print_added_file_diffs (report);
}
lim_free (0, item);
}
safe_printfmt (out_fd, "\n");
}
if (report->patched_regular_files)
{
safe_printfmt (out_fd, "* modified files\n\n");
if (diffs)
{
arch_print_file_diffs (report);
}
else
{
for (x = 0; x < rel_n_records (report->patched_regular_files); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->patched_regular_files[x][0]);
safe_printfmt (out_fd, " %s\n", no_dot (item));
lim_free (0, item);
}
}
safe_printfmt (out_fd, "\n");
}
}
/*
* Print a changeset report in a compact format.
* column 1 is : A|D|R|S|F - add/delete/rename/file->symlink and symlink->file
* column 2 is : M - modified files | symlinks
*/
void
arch_changeset_report_print_compact (int out_fd, struct arch_changeset_report * report, int escape_classes)
{
int x;
if (report->removed_dirs)
{
for (x = 0; x < rel_n_records (report->removed_dirs); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->removed_dirs[x][0]);
safe_printfmt (out_fd, "D %s\n", no_dot (item));
lim_free (0, item);
}
}
if (report->added_dirs)
{
for (x = 0; x < rel_n_records (report->added_dirs); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->added_dirs[x][0]);
safe_printfmt (out_fd, "A %s\n", no_dot (item));
lim_free (0, item);
}
}
if (report->removed_files)
{
for (x = 0; x < rel_n_records (report->removed_files); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->removed_files[x][0]);
safe_printfmt (out_fd, "D %s\n", no_dot (item));
lim_free (0, item);
}
}
if (report->added_files)
{
for (x = 0; x < rel_n_records (report->added_files); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->added_files[x][0]);
safe_printfmt (out_fd, "A %s\n", no_dot (item));
lim_free (0, item);
}
}
if (report->removed_symlinks)
{
for (x = 0; x < rel_n_records (report->removed_symlinks); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->removed_symlinks[x][0]);
safe_printfmt (out_fd, "D %s\n", no_dot (item));
lim_free (0, item);
}
}
if (report->added_symlinks)
{
for (x = 0; x < rel_n_records (report->added_symlinks); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->added_symlinks[x][0]);
safe_printfmt (out_fd, "A %s\n", no_dot (item));
lim_free (0, item);
}
}
if (report->renamed_files)
{
for (x = 0; x < rel_n_records (report->renamed_files); ++x)
{
t_uchar * item1;
t_uchar * item2;
item1 = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->renamed_files[x][0]);
item2 = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->renamed_files[x][1]);
safe_printfmt (out_fd, "R %s => %s\n", no_dot (item1), no_dot (item2));
lim_free (0, item2);
lim_free (0, item1);
}
}
if (report->renamed_dirs)
{
for (x = 0; x < rel_n_records (report->renamed_dirs); ++x)
{
t_uchar * item1;
t_uchar * item2;
item1 = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->renamed_dirs[x][0]);
item2 = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->renamed_dirs[x][1]);
safe_printfmt (out_fd, "R %s => %s\n", no_dot (item1), no_dot (item2));
lim_free (0, item2);
lim_free (0, item1);
}
}
if (report->file_to_symlink)
{
for (x = 0; x < rel_n_records (report->file_to_symlink); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->file_to_symlink[x][0]);
safe_printfmt (out_fd, "S %s\n", no_dot (item));
lim_free (0, item);
}
}
if (report->symlink_to_file)
{
for (x = 0; x < rel_n_records (report->symlink_to_file); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->symlink_to_file[x][0]);
safe_printfmt (out_fd, "F %s\n", no_dot (item));
lim_free (0, item);
}
}
if (report->file_metadata_changed)
{
for (x = 0; x < rel_n_records (report->file_metadata_changed); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->file_metadata_changed[x][0]);
safe_printfmt (out_fd, " P %s\n", no_dot (item));
lim_free (0, item);
}
}
if (report->dir_metadata_changed)
{
for (x = 0; x < rel_n_records (report->dir_metadata_changed); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->dir_metadata_changed[x][0]);
safe_printfmt (out_fd, " P %s\n", no_dot (item));
lim_free (0, item);
}
}
if (report->patched_symlinks)
{
for (x = 0; x < rel_n_records (report->patched_symlinks); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->patched_symlinks[x][0]);
safe_printfmt (out_fd, " M %s\n", no_dot (item));
lim_free (0, item);
}
}
if (report->patched_binaries)
{
for (x = 0; x < rel_n_records (report->patched_binaries); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->patched_binaries[x][0]);
safe_printfmt (out_fd, " M %s\n", no_dot (item));
lim_free (0, item);
}
}
if (report->patched_regular_files)
{
for (x = 0; x < rel_n_records (report->patched_regular_files); ++x)
{
t_uchar * item;
item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
report->patched_regular_files[x][0]);
safe_printfmt (out_fd, " M %s\n", no_dot (item));
lim_free (0, item);
}
}
}
void
arch_free_changeset_report_data (struct arch_changeset_report * r)
{
rel_free_table (r->orig_files_index); r->orig_files_index = 0;
rel_free_table (r->orig_dirs_index); r->orig_dirs_index = 0;
rel_free_table (r->mod_files_index); r->mod_files_index = 0;
rel_free_table (r->mod_dirs_index); r->mod_dirs_index = 0;
rel_free_table (r->removed_dirs); r->removed_dirs = 0;
rel_free_table (r->added_dirs); r->added_dirs = 0;
rel_free_table (r->removed_files); r->removed_files = 0;
rel_free_table (r->added_files); r->added_files = 0;
rel_free_table (r->removed_symlinks); r->removed_symlinks = 0;
rel_free_table (r->added_symlinks); r->added_symlinks = 0;
rel_free_table (r->renamed_files); r->renamed_files = 0;
rel_free_table (r->renamed_dirs); r->renamed_dirs = 0;
rel_free_table (r->patched_regular_files); r->patched_regular_files = 0;
rel_free_table (r->patched_symlinks); r->patched_symlinks = 0;
rel_free_table (r->patched_binaries); r->patched_binaries = 0;
rel_free_table (r->file_metadata_changed); r->file_metadata_changed = 0;
rel_free_table (r->dir_metadata_changed); r->dir_metadata_changed = 0;
rel_free_table (r->symlink_to_file); r->symlink_to_file = 0;
rel_free_table (r->file_to_symlink); r->file_to_symlink = 0;
}
static void
report_unique_files_and_symlinks (rel_table * files, rel_table * symlinks,
rel_table index,
t_uchar * archive_dir, t_uchar * archive_basename)
{
t_uchar * archive = 0;
int lim;
int x;
archive = file_name_in_vicinity (0, archive_dir, archive_basename);
lim = rel_n_records (index);
for (x = 0; x < lim; ++x)
{
t_uchar * archive_path;
struct stat stat_buf;
archive_path = file_name_in_vicinity (0, archive, index[x][0]);
safe_lstat (archive_path, &stat_buf);
if (S_ISLNK (stat_buf.st_mode))
{
rel_add_records (symlinks, rel_make_record (index[x][0], index[x][1], archive_path, 0), 0);
}
else
{
rel_add_records (files, rel_make_record (index[x][0], index[x][1], archive_path, 0), 0);
}
lim_free (0, archive_path);
}
rel_sort_table_by_field (0, *files, 0);
rel_sort_table_by_field (0, *symlinks, 0);
lim_free (0, archive);
}
static void
find_renames (rel_table * out, rel_table common, assoc_table orig_dir_id_of, assoc_table mod_dir_id_of)
{
int lim;
int x;
lim = rel_n_records (common);
for (x = 0; x < lim; ++x)
{
t_uchar * orig_loc = 0;
t_uchar * mod_loc = 0;
t_uchar * id = 0;
t_uchar * orig_basename = 0;
t_uchar * mod_basename = 0;
t_uchar * orig_dir = 0;
t_uchar * mod_dir = 0;
t_uchar * orig_dir_id = 0;
t_uchar * mod_dir_id = 0;
orig_loc = common[x][0];
mod_loc = common[x][1];
id = common[x][2];
orig_basename = file_name_tail (0, orig_loc);
mod_basename = file_name_tail (0, mod_loc);
orig_dir = file_name_directory_file (0, orig_loc);
mod_dir = file_name_directory_file (0, mod_loc);
orig_dir_id = assoc_ref (orig_dir_id_of, orig_dir);
mod_dir_id = assoc_ref (mod_dir_id_of, mod_dir);
/* The conditional subexpression here attempts to identify renames
* even when the the changeset is missing locs and ids for
* one or both of the containing dirs of the object under consideration.
*
*/
if (str_cmp (orig_basename, mod_basename)
|| ((orig_dir_id && mod_dir_id)
? str_cmp (orig_dir_id, mod_dir_id)
: str_cmp (orig_dir, mod_dir)))
{
rel_add_records (out, rel_make_record (orig_loc, mod_loc, id, 0), 0);
}
lim_free (0, orig_basename);
lim_free (0, mod_basename);
lim_free (0, orig_dir);
lim_free (0, mod_dir);
}
}
void
arch_changeset_report_init (struct arch_changeset_report * changeset)
{
mem_set0 ((t_uchar *)changeset, sizeof (*changeset));
}
/* tag: Tom Lord Thu May 15 13:07:24 2003 (changeset-report.c)
*/
syntax highlighted by Code2HTML, v. 0.9.1