/* 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) */