1d9a9f23dSDag-Erling Smørgrav /* 2d9a9f23dSDag-Erling Smørgrav * Copyright (c) 2018 Martin Pieuchot 3d9a9f23dSDag-Erling Smørgrav * Copyright (c) 2020 Neels Hofmeyr <neels@hofmeyr.de> 4d9a9f23dSDag-Erling Smørgrav * 5d9a9f23dSDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any 6d9a9f23dSDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above 7d9a9f23dSDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies. 8d9a9f23dSDag-Erling Smørgrav * 9d9a9f23dSDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10d9a9f23dSDag-Erling Smørgrav * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11d9a9f23dSDag-Erling Smørgrav * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12d9a9f23dSDag-Erling Smørgrav * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13d9a9f23dSDag-Erling Smørgrav * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14d9a9f23dSDag-Erling Smørgrav * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15d9a9f23dSDag-Erling Smørgrav * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16d9a9f23dSDag-Erling Smørgrav */ 17d9a9f23dSDag-Erling Smørgrav 18d9a9f23dSDag-Erling Smørgrav #include <sys/types.h> 19eea5f8d4SDag-Erling Smørgrav #include <sys/capsicum.h> 20eea5f8d4SDag-Erling Smørgrav #ifndef DIFF_NO_MMAP 21eea5f8d4SDag-Erling Smørgrav #include <sys/mman.h> 22eea5f8d4SDag-Erling Smørgrav #endif 23eea5f8d4SDag-Erling Smørgrav #include <sys/stat.h> 24d9a9f23dSDag-Erling Smørgrav 25d9a9f23dSDag-Erling Smørgrav #include <capsicum_helpers.h> 26d9a9f23dSDag-Erling Smørgrav #include <err.h> 27d9a9f23dSDag-Erling Smørgrav #include <fcntl.h> 28eea5f8d4SDag-Erling Smørgrav #include <stdbool.h> 29d9a9f23dSDag-Erling Smørgrav #include <stdint.h> 30d9a9f23dSDag-Erling Smørgrav #include <stdio.h> 31d9a9f23dSDag-Erling Smørgrav #include <stdlib.h> 32d9a9f23dSDag-Erling Smørgrav #include <string.h> 33eea5f8d4SDag-Erling Smørgrav #include <time.h> 34d9a9f23dSDag-Erling Smørgrav #include <unistd.h> 35d9a9f23dSDag-Erling Smørgrav 36d9a9f23dSDag-Erling Smørgrav #include "diff.h" 37d9a9f23dSDag-Erling Smørgrav #include <arraylist.h> 38d9a9f23dSDag-Erling Smørgrav #include <diff_main.h> 39d9a9f23dSDag-Erling Smørgrav #include <diff_output.h> 40d9a9f23dSDag-Erling Smørgrav 41d9a9f23dSDag-Erling Smørgrav const char *format_label(const char *, struct stat *); 42d9a9f23dSDag-Erling Smørgrav 43d9a9f23dSDag-Erling Smørgrav enum diffreg_algo { 44d9a9f23dSDag-Erling Smørgrav DIFFREG_ALGO_MYERS_THEN_MYERS_DIVIDE = 0, 45d9a9f23dSDag-Erling Smørgrav DIFFREG_ALGO_MYERS_THEN_PATIENCE = 1, 46d9a9f23dSDag-Erling Smørgrav DIFFREG_ALGO_PATIENCE = 2, 47d9a9f23dSDag-Erling Smørgrav DIFFREG_ALGO_NONE = 3, 48d9a9f23dSDag-Erling Smørgrav }; 49d9a9f23dSDag-Erling Smørgrav 50d9a9f23dSDag-Erling Smørgrav int diffreg_new(char *, char *, int, int); 51d9a9f23dSDag-Erling Smørgrav FILE * openfile(const char *, char **, struct stat *); 52d9a9f23dSDag-Erling Smørgrav 53d9a9f23dSDag-Erling Smørgrav static const struct diff_algo_config myers_then_patience; 54d9a9f23dSDag-Erling Smørgrav static const struct diff_algo_config myers_then_myers_divide; 55d9a9f23dSDag-Erling Smørgrav static const struct diff_algo_config patience; 56d9a9f23dSDag-Erling Smørgrav static const struct diff_algo_config myers_divide; 57d9a9f23dSDag-Erling Smørgrav 58d9a9f23dSDag-Erling Smørgrav static const struct diff_algo_config myers_then_patience = (struct diff_algo_config){ 59d9a9f23dSDag-Erling Smørgrav .impl = diff_algo_myers, 60d9a9f23dSDag-Erling Smørgrav .permitted_state_size = 1024 * 1024 * sizeof(int), 61d9a9f23dSDag-Erling Smørgrav .fallback_algo = &patience, 62d9a9f23dSDag-Erling Smørgrav }; 63d9a9f23dSDag-Erling Smørgrav 64d9a9f23dSDag-Erling Smørgrav static const struct diff_algo_config myers_then_myers_divide = 65d9a9f23dSDag-Erling Smørgrav (struct diff_algo_config){ 66d9a9f23dSDag-Erling Smørgrav .impl = diff_algo_myers, 67d9a9f23dSDag-Erling Smørgrav .permitted_state_size = 1024 * 1024 * sizeof(int), 68d9a9f23dSDag-Erling Smørgrav .fallback_algo = &myers_divide, 69d9a9f23dSDag-Erling Smørgrav }; 70d9a9f23dSDag-Erling Smørgrav 71d9a9f23dSDag-Erling Smørgrav static const struct diff_algo_config patience = (struct diff_algo_config){ 72d9a9f23dSDag-Erling Smørgrav .impl = diff_algo_patience, 73d9a9f23dSDag-Erling Smørgrav /* After subdivision, do Patience again: */ 74d9a9f23dSDag-Erling Smørgrav .inner_algo = &patience, 75d9a9f23dSDag-Erling Smørgrav /* If subdivision failed, do Myers Divide et Impera: */ 76d9a9f23dSDag-Erling Smørgrav .fallback_algo = &myers_then_myers_divide, 77d9a9f23dSDag-Erling Smørgrav }; 78d9a9f23dSDag-Erling Smørgrav 79d9a9f23dSDag-Erling Smørgrav static const struct diff_algo_config myers_divide = (struct diff_algo_config){ 80d9a9f23dSDag-Erling Smørgrav .impl = diff_algo_myers_divide, 81d9a9f23dSDag-Erling Smørgrav /* When division succeeded, start from the top: */ 82d9a9f23dSDag-Erling Smørgrav .inner_algo = &myers_then_myers_divide, 83d9a9f23dSDag-Erling Smørgrav /* (fallback_algo = NULL implies diff_algo_none). */ 84d9a9f23dSDag-Erling Smørgrav }; 85d9a9f23dSDag-Erling Smørgrav 86d9a9f23dSDag-Erling Smørgrav static const struct diff_algo_config no_algo = (struct diff_algo_config){ 87d9a9f23dSDag-Erling Smørgrav .impl = diff_algo_none, 88d9a9f23dSDag-Erling Smørgrav }; 89d9a9f23dSDag-Erling Smørgrav 90d9a9f23dSDag-Erling Smørgrav /* If the state for a forward-Myers is small enough, use Myers, otherwise first 91d9a9f23dSDag-Erling Smørgrav * do a Myers-divide. */ 92d9a9f23dSDag-Erling Smørgrav static const struct diff_config diff_config_myers_then_myers_divide = { 93d9a9f23dSDag-Erling Smørgrav .atomize_func = diff_atomize_text_by_line, 94d9a9f23dSDag-Erling Smørgrav .algo = &myers_then_myers_divide, 95d9a9f23dSDag-Erling Smørgrav }; 96d9a9f23dSDag-Erling Smørgrav 97d9a9f23dSDag-Erling Smørgrav /* If the state for a forward-Myers is small enough, use Myers, otherwise first 98d9a9f23dSDag-Erling Smørgrav * do a Patience. */ 99d9a9f23dSDag-Erling Smørgrav static const struct diff_config diff_config_myers_then_patience = { 100d9a9f23dSDag-Erling Smørgrav .atomize_func = diff_atomize_text_by_line, 101d9a9f23dSDag-Erling Smørgrav .algo = &myers_then_patience, 102d9a9f23dSDag-Erling Smørgrav }; 103d9a9f23dSDag-Erling Smørgrav 104d9a9f23dSDag-Erling Smørgrav /* Directly force Patience as a first divider of the source file. */ 105d9a9f23dSDag-Erling Smørgrav static const struct diff_config diff_config_patience = { 106d9a9f23dSDag-Erling Smørgrav .atomize_func = diff_atomize_text_by_line, 107d9a9f23dSDag-Erling Smørgrav .algo = &patience, 108d9a9f23dSDag-Erling Smørgrav }; 109d9a9f23dSDag-Erling Smørgrav 110d9a9f23dSDag-Erling Smørgrav /* Directly force Patience as a first divider of the source file. */ 111d9a9f23dSDag-Erling Smørgrav static const struct diff_config diff_config_no_algo = { 112d9a9f23dSDag-Erling Smørgrav .atomize_func = diff_atomize_text_by_line, 113d9a9f23dSDag-Erling Smørgrav }; 114d9a9f23dSDag-Erling Smørgrav 115d9a9f23dSDag-Erling Smørgrav const char * 116d9a9f23dSDag-Erling Smørgrav format_label(const char *oldlabel, struct stat *stb) 117d9a9f23dSDag-Erling Smørgrav { 118d9a9f23dSDag-Erling Smørgrav const char *time_format = "%Y-%m-%d %H:%M:%S"; 119d9a9f23dSDag-Erling Smørgrav char *newlabel; 120d9a9f23dSDag-Erling Smørgrav char buf[256]; 121d9a9f23dSDag-Erling Smørgrav char end[10]; 122d9a9f23dSDag-Erling Smørgrav struct tm tm, *tm_ptr; 123d9a9f23dSDag-Erling Smørgrav int nsec = stb->st_mtim.tv_nsec; 124d9a9f23dSDag-Erling Smørgrav size_t newlabellen, timelen, endlen; 125d9a9f23dSDag-Erling Smørgrav tm_ptr = localtime_r(&stb->st_mtime, &tm); 126d9a9f23dSDag-Erling Smørgrav 127d9a9f23dSDag-Erling Smørgrav timelen = strftime(buf, 256, time_format, tm_ptr); 128d9a9f23dSDag-Erling Smørgrav endlen = strftime(end, 10, "%z", tm_ptr); 129d9a9f23dSDag-Erling Smørgrav 130d9a9f23dSDag-Erling Smørgrav /* 131d9a9f23dSDag-Erling Smørgrav * The new label is the length of the time, old label, timezone, 132d9a9f23dSDag-Erling Smørgrav * 9 characters for nanoseconds, and 4 characters for a period 133d9a9f23dSDag-Erling Smørgrav * and for formatting. 134d9a9f23dSDag-Erling Smørgrav */ 135d9a9f23dSDag-Erling Smørgrav newlabellen = timelen + strlen(oldlabel) + endlen + 9 + 4; 136d9a9f23dSDag-Erling Smørgrav newlabel = calloc(newlabellen, sizeof(char)); 137d9a9f23dSDag-Erling Smørgrav 138d9a9f23dSDag-Erling Smørgrav snprintf(newlabel, newlabellen ,"%s\t%s.%.9d %s\n", 139d9a9f23dSDag-Erling Smørgrav oldlabel, buf, nsec, end); 140d9a9f23dSDag-Erling Smørgrav 141d9a9f23dSDag-Erling Smørgrav return newlabel; 142d9a9f23dSDag-Erling Smørgrav } 143d9a9f23dSDag-Erling Smørgrav 144d9a9f23dSDag-Erling Smørgrav int 145d9a9f23dSDag-Erling Smørgrav diffreg_new(char *file1, char *file2, int flags, int capsicum) 146d9a9f23dSDag-Erling Smørgrav { 147d9a9f23dSDag-Erling Smørgrav char *str1, *str2; 148d9a9f23dSDag-Erling Smørgrav FILE *f1, *f2; 149d9a9f23dSDag-Erling Smørgrav struct stat st1, st2; 150d9a9f23dSDag-Erling Smørgrav struct diff_input_info info; 151d9a9f23dSDag-Erling Smørgrav struct diff_data left = {}, right = {}; 152d9a9f23dSDag-Erling Smørgrav struct diff_result *result = NULL; 153d9a9f23dSDag-Erling Smørgrav bool force_text, have_binary; 154d9a9f23dSDag-Erling Smørgrav int rc, atomizer_flags, rflags, diff_flags = 0; 155d9a9f23dSDag-Erling Smørgrav int context_lines = diff_context; 156d9a9f23dSDag-Erling Smørgrav const struct diff_config *cfg; 157d9a9f23dSDag-Erling Smørgrav enum diffreg_algo algo; 158d9a9f23dSDag-Erling Smørgrav cap_rights_t rights_ro; 159d9a9f23dSDag-Erling Smørgrav 160d9a9f23dSDag-Erling Smørgrav algo = DIFFREG_ALGO_MYERS_THEN_MYERS_DIVIDE; 161d9a9f23dSDag-Erling Smørgrav 162d9a9f23dSDag-Erling Smørgrav switch (algo) { 163d9a9f23dSDag-Erling Smørgrav default: 164d9a9f23dSDag-Erling Smørgrav case DIFFREG_ALGO_MYERS_THEN_MYERS_DIVIDE: 165d9a9f23dSDag-Erling Smørgrav cfg = &diff_config_myers_then_myers_divide; 166d9a9f23dSDag-Erling Smørgrav break; 167d9a9f23dSDag-Erling Smørgrav case DIFFREG_ALGO_MYERS_THEN_PATIENCE: 168d9a9f23dSDag-Erling Smørgrav cfg = &diff_config_myers_then_patience; 169d9a9f23dSDag-Erling Smørgrav break; 170d9a9f23dSDag-Erling Smørgrav case DIFFREG_ALGO_PATIENCE: 171d9a9f23dSDag-Erling Smørgrav cfg = &diff_config_patience; 172d9a9f23dSDag-Erling Smørgrav break; 173d9a9f23dSDag-Erling Smørgrav case DIFFREG_ALGO_NONE: 174d9a9f23dSDag-Erling Smørgrav cfg = &diff_config_no_algo; 175d9a9f23dSDag-Erling Smørgrav break; 176d9a9f23dSDag-Erling Smørgrav } 177d9a9f23dSDag-Erling Smørgrav 178d9a9f23dSDag-Erling Smørgrav f1 = openfile(file1, &str1, &st1); 179d9a9f23dSDag-Erling Smørgrav f2 = openfile(file2, &str2, &st2); 180d9a9f23dSDag-Erling Smørgrav 181d9a9f23dSDag-Erling Smørgrav if (capsicum) { 182d9a9f23dSDag-Erling Smørgrav cap_rights_init(&rights_ro, CAP_READ, CAP_FSTAT, CAP_SEEK); 183d9a9f23dSDag-Erling Smørgrav if (caph_rights_limit(fileno(f1), &rights_ro) < 0) 184d9a9f23dSDag-Erling Smørgrav err(2, "unable to limit rights on: %s", file1); 185d9a9f23dSDag-Erling Smørgrav if (caph_rights_limit(fileno(f2), &rights_ro) < 0) 186d9a9f23dSDag-Erling Smørgrav err(2, "unable to limit rights on: %s", file2); 187d9a9f23dSDag-Erling Smørgrav if (fileno(f1) == STDIN_FILENO || fileno(f2) == STDIN_FILENO) { 188d9a9f23dSDag-Erling Smørgrav /* stdin has already been limited */ 189d9a9f23dSDag-Erling Smørgrav if (caph_limit_stderr() == -1) 190d9a9f23dSDag-Erling Smørgrav err(2, "unable to limit stderr"); 191d9a9f23dSDag-Erling Smørgrav if (caph_limit_stdout() == -1) 192d9a9f23dSDag-Erling Smørgrav err(2, "unable to limit stdout"); 193d9a9f23dSDag-Erling Smørgrav } else if (caph_limit_stdio() == -1) 194d9a9f23dSDag-Erling Smørgrav err(2, "unable to limit stdio"); 195d9a9f23dSDag-Erling Smørgrav caph_cache_catpages(); 196d9a9f23dSDag-Erling Smørgrav caph_cache_tzdata(); 197d9a9f23dSDag-Erling Smørgrav if (caph_enter() < 0) 198d9a9f23dSDag-Erling Smørgrav err(2, "unable to enter capability mode"); 199d9a9f23dSDag-Erling Smørgrav } 200d9a9f23dSDag-Erling Smørgrav /* 201d9a9f23dSDag-Erling Smørgrav * If we have been given a label use that for the paths, if not format 202d9a9f23dSDag-Erling Smørgrav * the path with the files modification time. 203d9a9f23dSDag-Erling Smørgrav */ 204d9a9f23dSDag-Erling Smørgrav info.flags = 0; 205d9a9f23dSDag-Erling Smørgrav info.left_path = (label[0] != NULL) ? 206d9a9f23dSDag-Erling Smørgrav label[0] : format_label(file1, &stb1); 207d9a9f23dSDag-Erling Smørgrav info.right_path = (label[1] != NULL) ? 208d9a9f23dSDag-Erling Smørgrav label[1] : format_label(file2, &stb2); 209d9a9f23dSDag-Erling Smørgrav 210d9a9f23dSDag-Erling Smørgrav if (flags & D_FORCEASCII) 211d9a9f23dSDag-Erling Smørgrav diff_flags |= DIFF_FLAG_FORCE_TEXT_DATA; 212d9a9f23dSDag-Erling Smørgrav if (flags & D_IGNOREBLANKS) 213d9a9f23dSDag-Erling Smørgrav diff_flags |= DIFF_FLAG_IGNORE_WHITESPACE; 214d9a9f23dSDag-Erling Smørgrav if (flags & D_PROTOTYPE) 215d9a9f23dSDag-Erling Smørgrav diff_flags |= DIFF_FLAG_SHOW_PROTOTYPES; 216d9a9f23dSDag-Erling Smørgrav 217d9a9f23dSDag-Erling Smørgrav if (diff_atomize_file(&left, cfg, f1, (uint8_t *)str1, st1.st_size, diff_flags)) { 218d9a9f23dSDag-Erling Smørgrav rc = D_ERROR; 219d9a9f23dSDag-Erling Smørgrav goto done; 220d9a9f23dSDag-Erling Smørgrav } 221b780b650SDag-Erling Smørgrav if (left.atomizer_flags & DIFF_ATOMIZER_FILE_TRUNCATED) 222b780b650SDag-Erling Smørgrav warnx("%s truncated", file1); 223d9a9f23dSDag-Erling Smørgrav if (diff_atomize_file(&right, cfg, f2, (uint8_t *)str2, st2.st_size, diff_flags)) { 224d9a9f23dSDag-Erling Smørgrav rc = D_ERROR; 225d9a9f23dSDag-Erling Smørgrav goto done; 226d9a9f23dSDag-Erling Smørgrav } 227b780b650SDag-Erling Smørgrav if (right.atomizer_flags & DIFF_ATOMIZER_FILE_TRUNCATED) 228b780b650SDag-Erling Smørgrav warnx("%s truncated", file2); 229d9a9f23dSDag-Erling Smørgrav 230d9a9f23dSDag-Erling Smørgrav result = diff_main(cfg, &left, &right); 231d9a9f23dSDag-Erling Smørgrav if (result->rc != DIFF_RC_OK) { 232d9a9f23dSDag-Erling Smørgrav rc = D_ERROR; 233d9a9f23dSDag-Erling Smørgrav status |= 2; 234d9a9f23dSDag-Erling Smørgrav goto done; 235d9a9f23dSDag-Erling Smørgrav } 236d9a9f23dSDag-Erling Smørgrav /* 237d9a9f23dSDag-Erling Smørgrav * If there wasn't an error, but we don't have any printable chunks 238d9a9f23dSDag-Erling Smørgrav * then the files must match. 239d9a9f23dSDag-Erling Smørgrav */ 240d9a9f23dSDag-Erling Smørgrav if (!diff_result_contains_printable_chunks(result)) { 241d9a9f23dSDag-Erling Smørgrav rc = D_SAME; 242d9a9f23dSDag-Erling Smørgrav goto done; 243d9a9f23dSDag-Erling Smørgrav } 244d9a9f23dSDag-Erling Smørgrav 245d9a9f23dSDag-Erling Smørgrav atomizer_flags = (result->left->atomizer_flags | result->right->atomizer_flags); 246d9a9f23dSDag-Erling Smørgrav rflags = (result->left->root->diff_flags | result->right->root->diff_flags); 247d9a9f23dSDag-Erling Smørgrav force_text = (rflags & DIFF_FLAG_FORCE_TEXT_DATA); 248d9a9f23dSDag-Erling Smørgrav have_binary = (atomizer_flags & DIFF_ATOMIZER_FOUND_BINARY_DATA); 249d9a9f23dSDag-Erling Smørgrav 250d9a9f23dSDag-Erling Smørgrav if (have_binary && !force_text) { 251d9a9f23dSDag-Erling Smørgrav rc = D_BINARY; 252d9a9f23dSDag-Erling Smørgrav status |= 1; 253d9a9f23dSDag-Erling Smørgrav goto done; 254d9a9f23dSDag-Erling Smørgrav } 255d9a9f23dSDag-Erling Smørgrav 2564e859e67SDag-Erling Smørgrav if (color) 2574e859e67SDag-Erling Smørgrav diff_output_set_colors(color, del_code, add_code); 258d9a9f23dSDag-Erling Smørgrav if (diff_format == D_NORMAL) { 259d9a9f23dSDag-Erling Smørgrav rc = diff_output_plain(NULL, stdout, &info, result, false); 260d9a9f23dSDag-Erling Smørgrav } else if (diff_format == D_EDIT) { 261d9a9f23dSDag-Erling Smørgrav rc = diff_output_edscript(NULL, stdout, &info, result); 262d9a9f23dSDag-Erling Smørgrav } else { 263d9a9f23dSDag-Erling Smørgrav rc = diff_output_unidiff(NULL, stdout, &info, result, 264d9a9f23dSDag-Erling Smørgrav context_lines); 265d9a9f23dSDag-Erling Smørgrav } 266d9a9f23dSDag-Erling Smørgrav if (rc != DIFF_RC_OK) { 267d9a9f23dSDag-Erling Smørgrav rc = D_ERROR; 268d9a9f23dSDag-Erling Smørgrav status |= 2; 269d9a9f23dSDag-Erling Smørgrav } else { 270d9a9f23dSDag-Erling Smørgrav rc = D_DIFFER; 271d9a9f23dSDag-Erling Smørgrav status |= 1; 272d9a9f23dSDag-Erling Smørgrav } 273d9a9f23dSDag-Erling Smørgrav done: 274d9a9f23dSDag-Erling Smørgrav diff_result_free(result); 275d9a9f23dSDag-Erling Smørgrav diff_data_free(&left); 276d9a9f23dSDag-Erling Smørgrav diff_data_free(&right); 277eea5f8d4SDag-Erling Smørgrav #ifndef DIFF_NO_MMAP 278d9a9f23dSDag-Erling Smørgrav if (str1) 279d9a9f23dSDag-Erling Smørgrav munmap(str1, st1.st_size); 280d9a9f23dSDag-Erling Smørgrav if (str2) 281d9a9f23dSDag-Erling Smørgrav munmap(str2, st2.st_size); 282eea5f8d4SDag-Erling Smørgrav #endif 283d9a9f23dSDag-Erling Smørgrav fclose(f1); 284d9a9f23dSDag-Erling Smørgrav fclose(f2); 285d9a9f23dSDag-Erling Smørgrav 286d9a9f23dSDag-Erling Smørgrav return rc; 287d9a9f23dSDag-Erling Smørgrav } 288d9a9f23dSDag-Erling Smørgrav 289d9a9f23dSDag-Erling Smørgrav FILE * 290d9a9f23dSDag-Erling Smørgrav openfile(const char *path, char **p, struct stat *st) 291d9a9f23dSDag-Erling Smørgrav { 292d9a9f23dSDag-Erling Smørgrav FILE *f = NULL; 293d9a9f23dSDag-Erling Smørgrav 294d9a9f23dSDag-Erling Smørgrav if (strcmp(path, "-") == 0) 295d9a9f23dSDag-Erling Smørgrav f = stdin; 296d9a9f23dSDag-Erling Smørgrav else 297d9a9f23dSDag-Erling Smørgrav f = fopen(path, "r"); 298d9a9f23dSDag-Erling Smørgrav 299d9a9f23dSDag-Erling Smørgrav if (f == NULL) 300d9a9f23dSDag-Erling Smørgrav err(2, "%s", path); 301d9a9f23dSDag-Erling Smørgrav 302d9a9f23dSDag-Erling Smørgrav if (fstat(fileno(f), st) == -1) 303d9a9f23dSDag-Erling Smørgrav err(2, "%s", path); 304d9a9f23dSDag-Erling Smørgrav 305d9a9f23dSDag-Erling Smørgrav #ifndef DIFF_NO_MMAP 306d9a9f23dSDag-Erling Smørgrav *p = mmap(NULL, st->st_size, PROT_READ, MAP_PRIVATE, fileno(f), 0); 307d9a9f23dSDag-Erling Smørgrav if (*p == MAP_FAILED) 308d9a9f23dSDag-Erling Smørgrav #endif 309d9a9f23dSDag-Erling Smørgrav *p = NULL; /* fall back on file I/O */ 310d9a9f23dSDag-Erling Smørgrav 311d9a9f23dSDag-Erling Smørgrav return f; 312d9a9f23dSDag-Erling Smørgrav } 313d9a9f23dSDag-Erling Smørgrav 314d9a9f23dSDag-Erling Smørgrav bool 315d9a9f23dSDag-Erling Smørgrav can_libdiff(int flags) 316d9a9f23dSDag-Erling Smørgrav { 317*893839b1SDag-Erling Smørgrav /* libdiff's atomizer can only deal with files */ 318*893839b1SDag-Erling Smørgrav if (!S_ISREG(stb1.st_mode) || !S_ISREG(stb2.st_mode)) 319d9a9f23dSDag-Erling Smørgrav return false; 320d9a9f23dSDag-Erling Smørgrav 321d9a9f23dSDag-Erling Smørgrav /* Is this one of the supported input/output modes for diffreg_new? */ 322d9a9f23dSDag-Erling Smørgrav if ((flags == 0 || !(flags & ~D_NEWALGO_FLAGS)) && 323d9a9f23dSDag-Erling Smørgrav ignore_pats == NULL && ( 324d9a9f23dSDag-Erling Smørgrav diff_format == D_NORMAL || 325d9a9f23dSDag-Erling Smørgrav #if 0 326d9a9f23dSDag-Erling Smørgrav diff_format == D_EDIT || 327d9a9f23dSDag-Erling Smørgrav #endif 328d9a9f23dSDag-Erling Smørgrav diff_format == D_UNIFIED) && 329d9a9f23dSDag-Erling Smørgrav (diff_algorithm == D_DIFFMYERS || diff_algorithm == D_DIFFPATIENCE)) { 330d9a9f23dSDag-Erling Smørgrav return true; 331d9a9f23dSDag-Erling Smørgrav } 332d9a9f23dSDag-Erling Smørgrav 333d9a9f23dSDag-Erling Smørgrav /* Fallback to using stone. */ 334d9a9f23dSDag-Erling Smørgrav return false; 335d9a9f23dSDag-Erling Smørgrav } 336