/* diffs.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/sys/wait.h"
#include "hackerlab/os/signal.h"
#include "hackerlab/mem/mem.h"
#include "hackerlab/char/str.h"
#include "hackerlab/arrays/ar.h"
#include "hackerlab/vu/safe.h"
#include "hackerlab/fs/file-names.h"
#include "libfsutils/link-target.h"
#include "libarch/exec.h"
#include "libarch/inode-sig.h"
#include "libarch/diffs.h"
int
arch_binary_files_differ (t_uchar * a, t_uchar * b, t_uchar * id, assoc_table inode_sig_shortcuts_of_b)
{
struct stat a_stat;
struct stat b_stat;
int answer;
safe_stat (a, &a_stat);
safe_stat (b, &b_stat);
answer = arch_file_stats_differ (&a_stat, &b_stat);
if (answer == 0)
return answer;
answer = arch_inode_sigs_differ (&b_stat, id, inode_sig_shortcuts_of_b);
if (answer == 0)
return answer;
return arch_filename_contents_differ (a, b);
}
int
arch_file_stats_differ (struct stat *a_stat, struct stat *b_stat)
{
if (a_stat->st_size != b_stat->st_size)
return 1;
if (a_stat->st_ino == b_stat->st_ino && a_stat->st_dev == b_stat->st_dev )
return 0;
return -1;
}
int
arch_inode_sigs_differ (struct stat *b_stat, t_uchar *id, assoc_table inode_sig_shortcuts_of_b)
{
if (id && inode_sig_shortcuts_of_b)
{
t_uchar * b_sig = arch_statb_inode_sig (b_stat);
t_uchar * b_goal = assoc_ref (inode_sig_shortcuts_of_b, id);
int shortcut_applies = !str_cmp (b_sig, b_goal);
lim_free (0, b_sig);
if (shortcut_applies)
return 0;
}
return -1;
}
int
arch_filename_contents_differ (t_uchar * a, t_uchar * b)
{
int a_fd;
int b_fd;
int answer;
a_fd = safe_open (a, O_RDONLY, 0);
b_fd = safe_open (b, O_RDONLY, 0);
answer = arch_file_contents_differ (a_fd, b_fd);
safe_close (a_fd);
safe_close (b_fd);
return answer;
}
int
arch_file_contents_differ (int a_fd, int b_fd)
{
static t_uchar a_buf[65536];
static t_uchar b_buf[sizeof (a_buf)];
long a_amt;
long b_amt;
int answer = 0;
while (1)
{
a_amt = safe_read_retry (a_fd, a_buf, sizeof (a_buf));
b_amt = safe_read_retry (b_fd, b_buf, sizeof (b_buf));
if ((a_amt != b_amt) || mem_cmp (a_buf, b_buf, a_amt))
{
answer = 1;
break;
}
if (!a_amt)
break;
}
return answer;
}
int
arch_invoke_diff (int output_fd,
char * orig_path, char * orig_loc,
char * mod_path, char * mod_loc,
t_uchar * id,
assoc_table inode_sig_shortcuts_of_mod)
{
if (!arch_binary_files_differ (orig_path, mod_path, id, inode_sig_shortcuts_of_mod))
return 0;
return arch_really_invoke_diff (output_fd, orig_path, orig_loc, mod_path, mod_loc, NULL);
}
int
arch_really_invoke_diff (int output_fd,
char * orig_path, char * orig_loc,
char * mod_path, char * mod_loc, char ** extraopts)
{
char * orig_label = 0;
char * mod_label = 0;
int pid;
if (orig_loc)
{
orig_label = file_name_in_vicinity (0, "orig", orig_loc + 2);
}
if (mod_loc)
{
mod_label = file_name_in_vicinity (0, "mod", mod_loc + 2);
}
safe_flush (output_fd);
pid = fork ();
if (pid == -1)
panic ("unable to fork for diff");
if (pid)
{
int status;
int wait_pid;
wait_pid = waitpid (pid, &status, 0);
if (wait_pid < 0)
{
panic_msg ("error waiting for subprocess");
kill (0, SIGKILL);
panic ("error waiting for subprocess");
}
if (WIFSIGNALED (status))
{
safe_printfmt (2, "\n");
safe_printfmt (2, "diff subprocess killed by signal %d\n", WTERMSIG (status));
safe_printfmt (2, "\n");
exit (2);
}
else if (!WIFEXITED (status))
{
panic_msg ("waitpid returned for a non-exited process");
kill (0, SIGKILL);
panic ("waitpid returned for a non-exited process");
}
else
{
int exit_status;
exit_status = WEXITSTATUS (status);
if (exit_status && (exit_status != 1) && (exit_status != 2))
{
safe_printfmt (2, "\n");
safe_printfmt (2, "encountered error diffing files\n");
safe_printfmt (2, " orig: %s\n", orig_path);
safe_printfmt (2, " mod: %s\n", mod_path);
safe_printfmt (2, " diff exit status: %d\n", exit_status);
safe_printfmt (2, "\n");
exit (2);
}
if (orig_label)
{
lim_free (0, orig_label);
}
if (mod_label)
{
lim_free (0, mod_label);
}
return exit_status;
}
}
else
{
int errn;
t_uchar ** argv = 0;
if (0 > vu_move_fd (&errn, output_fd, 1))
panic ("unable to redirect stdout for diff");
ar_push_uchar_star (&argv, cfg__gnu_diff);
ar_push_uchar_star (&argv, "--binary");
ar_push_uchar_star (&argv, "-u");
ar_push_uchar_star (&argv, "-L");
ar_push_uchar_star (&argv, orig_label ? orig_label : orig_path);
ar_push_uchar_star (&argv, "-L");
ar_push_uchar_star (&argv, mod_label ? mod_label : mod_path);
ar_push_uchar_star (&argv, orig_path);
ar_push_uchar_star (&argv, mod_path);
if (extraopts != NULL)
{
char ** opt;
for (opt = extraopts; *opt != NULL; ++opt)
{
ar_push_uchar_star (&argv, *opt);
}
}
ar_push_uchar_star (&argv, 0);
arch_util_execvp (cfg__gnu_diff, argv);
panic ("execvp for diff returned to caller");
exit (2);
}
panic ("arch_invoke_diff: not reached");
return 1;
}
int
arch_symlinks_differ (t_uchar * orig_path, t_uchar * mod_path)
{
t_uchar * orig_target = link_target (orig_path);
t_uchar * mod_target = link_target (mod_path);
int result = str_cmp (orig_target, mod_target);
lim_free (0, orig_target);
lim_free (0, mod_target);
return result;
}
/* tag: Tom Lord Mon May 19 18:00:23 2003 (diffs.c)
*/
syntax highlighted by Code2HTML, v. 0.9.1