aboutsummaryrefslogtreecommitdiff
path: root/flx/check.c
diff options
context:
space:
mode:
Diffstat (limited to 'flx/check.c')
-rw-r--r--flx/check.c556
1 files changed, 556 insertions, 0 deletions
diff --git a/flx/check.c b/flx/check.c
new file mode 100644
index 0000000..cbc8639
--- /dev/null
+++ b/flx/check.c
@@ -0,0 +1,556 @@
+/*
+ * Signfs version 0.6, Copyright Benoit DOLEZ, 2002
+ */
+
+/* command line is:
+ * ./flx check [options] input1 input2
+ * ./flx check [options] [inputs1] , [inputs2]
+ * options are :
+ * -h,--help : this help
+ * --ignore-mode : ignore file mode
+ * --ignore-owner : ignore owner (user, group)
+ * --ignore-dev : ignore device type
+ * --ignore-size : ignore file size
+ * --ignore-sum : ignore checksum (md5)
+ * --ignore-date : ignore date
+ * --ignore-link : ignore link
+ * --ignore-ldate : ignore links date
+ * --show-new : show only new files
+ * --show-old : show only removed files
+ * --show-all : show all files (sames and differs)
+ */
+
+
+#include <string.h>
+#include <stdio.h>
+
+#include "flx.h"
+#include "check.h"
+#include "input.h"
+#include "output.h"
+#include "output_file.h"
+#include "input_file.h"
+#include "input_fs.h"
+
+static POOL_INIT(t_file_diff);
+
+#define O_HELP 1
+#define O_SH_HR 5
+#define O_SH_ALL 6
+#define O_SH_NEW 7
+#define O_SH_OLD 8
+#define O_IGN_MODE 9
+#define O_IGN_OWNER 10
+#define O_IGN_SUM 11
+#define O_IGN_SIZE 12
+#define O_IGN_DATE 13
+#define O_IGN_LINK 14
+#define O_IGN_LDATE 15
+#define O_REWRITE_SRC1 16
+#define O_REWRITE_SRC2 17
+#define O_OUTPUT 18
+#define O_IGN_DOT 19
+
+t_param flxcheck_poptions[] = {
+ { 'h', "help", O_HELP, 0,
+ "-h,--help show this help"},
+ { 0, "ignore-mode", O_IGN_MODE, 0,
+ "--ignore-mode ignore mode" },
+ { 0, "ignore-owner", O_IGN_OWNER, 0,
+ "--ignore-owner ignore uid/gid" },
+ { 0, "ignore-sum", O_IGN_SUM, 0,
+ "--ignore-sum ignore checksum" },
+ { 0, "ignore-size", O_IGN_SIZE, 0,
+ "--ignore-size ignore size" },
+ { 'd', "ignore-date", O_IGN_DATE, 0,
+ "--ignore-date ignore date" },
+ { 0, "ignore-link", O_IGN_LINK, 0,
+ "-d,--ignore-link ignore link" },
+ { 0, "ignore-ldate", O_IGN_LDATE, 0,
+ "--ignore-ldate ignore date on links" },
+ { 0, "ignore-dot", O_IGN_DOT, 0,
+ "--ignore-dot do not compare '.' and '..'" },
+ { 0, "show-all", O_SH_ALL, 0,
+ "--show-all show all files (same and differs)" },
+ { 0, "only-new", O_SH_NEW, 0,
+ "--only-new show only new files"},
+ { 0, "only-old", O_SH_OLD, 0,
+ "--only-old show only old files"},
+ { 0, "human-readable", O_SH_HR, 0,
+ "--human-readable show long format"},
+ { 0, "rw1", O_REWRITE_SRC1, 1,
+ "--rw1 <string> string before first source path"},
+ { 0, "rw2", O_REWRITE_SRC2, 1,
+ "--rw2 <string> string before second source path"},
+ { 0, "op", O_OUTPUT, 1,
+ "--op <string> all output prefix"},
+ { 0, NULL, 0 }
+} ;
+
+static int output_diff_fcntl(t_file_status *env, int cmd);
+static int output_diff_write(t_file_status *spec, t_ft *tree, int number);
+
+
+static t_source_type InputTypes[] = {
+ { "fs",
+ (void*)input_fs_open, (void*)input_fs_read, NULL, (void*)input_fs_close,
+ (void*)input_fs_fcntl },
+ { "file",
+ (void*)input_file_open, (void*)input_file_read, NULL, (void*)input_file_close,
+ (void*)input_file_fcntl },
+ { "stdin",
+ (void*)input_stdin_open, (void*)input_file_read, NULL, (void*)input_file_close,
+ (void*)input_file_fcntl },
+ { NULL }
+};
+
+static t_source_type OutputTypes[] = {
+ { "stdout",
+ (void*)output_stdout_open, NULL, (void*)output_diff_write, (void*)output_file_close,
+ (void*)output_diff_fcntl},
+ { NULL }
+};
+
+
+
+static void *InputSrc1, *InputSrc2, *Output;
+static char *Rewrite_Src1 = NULL, *Rewrite_Src2 = NULL, *Output_Str = NULL;
+
+
+/* cette fonction permet de repérer toutes les données communes à deux sources et de
+ * les inserer dans un autre arbre
+ * cette fonction retourne le nombre d'éléments sortis des arbres sources
+ */
+int ft_find_diff(t_ft *src1, t_ft *src2, t_ft *dst) {
+ int count = 0, ret, diff;
+ t_file_diff *desc;
+ t_ft *next1, *next2;
+
+ /* on démarre du fils de chaque arbre en créant au besoin les
+ éléments manquant dans l'arbre destination */
+
+ if (!src1 || !src2 || !src1->subtree || !src2->subtree) return (0);
+
+ if (dst && !dst->subtree) {
+ dst->subtree = NEWDIR(dst);
+ }
+
+ src1 = src1->subtree->next;
+ src2 = src2->subtree->next;
+ dst = dst->subtree->next;
+
+ while (!IS(src1->status, BASE) && !IS(src2->status, BASE)) {
+ /* look for next same data */
+ while ((ret = strcmp(src1->filename, src2->filename))) {
+ if (ret < 0) src1 = src1->next;
+ if (ret > 0) src2 = src2->next;
+ /* no element found return */
+ if (IS(src1->status, BASE) || IS(src2->status, BASE))
+ return (count);
+ }
+
+ /* backup next pointers */
+ next1 = src1->next; next2 = src2->next;
+
+ /* place dst to best previous position */
+ while (!IS(dst->status, BASE) && strcmp(src1->filename, dst->filename) <= 0)
+ dst = dst->next;
+ dst = dst->prev;
+
+ /* only if they are filled */
+ if (IS(src1->status, FILLED) && IS(src2->status, FILLED)) {
+ /* pass '.' and '..' when IGNORE_DOT option */
+ //REM if ((!IS(Options, GOPT_IGNORE_DOT) || !IS_DOTF(src1->filename)) &&
+ if ((diff = files_are_the_same(src1->desc, src2->desc, Diff, NULL)) || IS(Options, SHOW_ALL)) {
+ /* should be place before current dst, but at the good place */
+ dst = ft_add(dst, src1->filename, NULL, NULL);
+
+ /* remove usage of c1->filename, in src1 if used by dst */
+ if (src1->filename == dst->filename)
+ dst->filename = strdup(src1->filename);
+
+ /* else already exist */
+ if (dst->desc) {
+ /* a test can be made with dst->desc ..., probably an
+ * error in source data */
+ warning("duplicate entry in sources");
+ }
+ else {
+ /* create difference description structure */
+ dst->desc = desc = POOL_ALLOC(t_file_diff);
+ desc->diff = diff;
+ desc->src1 = src1->desc; src1->desc = NULL;
+ desc->src2 = src2->desc; src2->desc = NULL;
+
+ /* mark changed */
+ SET(dst->status, FILLED);
+ SET_PARENT(dst, CHANGED);
+ /* update counter */
+ count++;
+ }
+ }
+ /* mark already seen */
+ UNSET(src1->status, FILLED);
+ UNSET(src2->status, FILLED);
+
+ // printf("%s treated\n", src2->filename);
+
+ // if (!src1->subtree) ft_del(src1, NULL, NULL);
+ // if (!src2->subtree) ft_del(src2, NULL, NULL);
+
+ }
+ /* if directory, run into */
+ if (src1->subtree && src2->subtree &&
+ (IS(src1->status, CHANGED) || IS(src2->status, CHANGED)) &&
+ !IS_PDOTF(src1) && !IS_PDOTF(src2)) {
+ /* get directory in dst or create it */
+ dst = ft_add(dst, src1->filename, NULL, NULL);
+ if (src1->filename == dst->filename)
+ dst->filename = strdup(dst->filename);
+
+ count += ft_find_diff(src1, src2, dst);
+ }
+
+ /* go to next */
+ src1 = next1; src2 = next2;
+ }
+ return (count);
+}
+
+/* cette fonction permet de déplacer le contenu d'un premier arbre dans un
+ * deuxième arbre
+ */
+void ft_move(t_ft *src, t_ft *dst) {
+ t_ft *next;
+ int ret;
+
+ if (!src || !dst || !src->subtree) return;
+
+ /* move full subtree */
+ if (!dst->subtree && src->subtree) {
+ t_ft *cur;
+
+ /* change parent */
+ src->subtree->parent = dst;
+ for (cur = src->subtree->next; !IS(cur->status, BASE); cur = cur->next) {
+ if (IS_PDOTDOT(cur))
+ cur->subtree = dst->parent->subtree;
+ cur->parent = dst;
+ }
+ /* change from src to dst */
+ dst->subtree = src->subtree;
+ src->subtree = NULL;
+ return ;
+ }
+
+ src = src->subtree->next;
+ dst = dst->subtree->next;
+
+ while (!IS(src->status, BASE)) {
+ /* backup next position */
+ next = src->next;
+
+ ret = 1;
+ /* search for it in dst */
+ while (!IS(dst->status, BASE) &&
+ (ret = strcmp(dst->filename, src->filename)) < 0)
+ dst = dst->next;
+
+ if (ret == 0) {
+ /* element exist */
+ /* need to move description */
+ if (src->desc && IS(src->status, FILLED) && !dst->desc) {
+ dst->desc = src->desc;
+ src->desc = NULL;
+ }
+ /* need to run into */
+ if (src->subtree) {
+ if (IS_PDOT(src)) {
+ dst->subtree = dst->parent->subtree;
+ src->subtree = NULL;
+ }
+ else if (IS_PDOTDOT(src)) {
+ dst->subtree = dst->parent->parent->subtree;
+ src->subtree = NULL;
+ }
+ else {
+ ft_move(src, dst);
+ }
+ }
+ ft_del(src, NULL, NULL);
+ }
+ else {
+ dst = dst->prev; /* go back to the previous one */
+ /* unchain from source tree */
+ LIST_UNCHAIN(src);
+ /* chain to destination tree */
+ LIST_CHAIN(dst, src, dst->next);
+
+ /* change parent hierarchy */
+ if (IS_PDOT(src))
+ src->subtree = dst->parent->subtree;
+ else if (IS_PDOTDOT(src))
+ src->subtree = dst->parent->parent->subtree;
+ else if (src->subtree) {
+ t_ft *cur;
+
+ for (cur = src->subtree->next; !IS(cur->status, BASE); cur = cur->next) {
+ if (IS_PDOTDOT(cur))
+ cur->subtree = dst->parent->subtree;
+ }
+ }
+ src->parent = dst->parent;
+
+ /* change destination current location */
+ dst = src;
+ }
+ src = next;
+ }
+}
+
+/* cette fonction permet de déplacer le contenu de deux arbres dans un troisième
+ */
+void ft_diff_move(t_ft *src, t_ft *dst, int opt) {
+ t_ft *next;
+ t_file_diff *new = NULL;
+
+ if (!src || !dst || !src->subtree) return;
+
+ if (!dst->subtree) dst->subtree = NEWDIR(dst);
+
+ src = src->subtree->next;
+ dst = dst->subtree->next;
+
+ while (!IS(src->status, BASE)) {
+ /* backup next position */
+ next = src->next;
+
+ if (IS(src->status, FILLED) || src->subtree) {
+ /* should find or create a new element */
+ dst = ft_add(dst, src->filename, NULL, NULL);
+ if (src->filename == dst->filename) src->filename = NULL;
+ }
+
+ if (IS(src->status, FILLED) && src->desc) {
+ /* need to move description */
+ if (!(new = dst->desc)) {
+ dst->desc = new = MALLOC(sizeof(*new));
+ bzero(new, sizeof(*new));
+ new->diff = 0xFFFF;
+ }
+ if (opt == ONLY_SRC1) new->src1 = src->desc;
+ if (opt == ONLY_SRC2) new->src2 = src->desc;
+ src->desc = NULL;
+ SET(dst->status, FILLED);
+ SET_PARENT(dst, CHANGED);
+ UNSET(src->status, FILLED);
+ }
+
+ /* need to run into */
+ if (src->subtree) {
+ if (IS_PDOT(src))
+ dst->subtree = dst->parent->subtree;
+ else if (IS_PDOTDOT(src))
+ dst->subtree = dst->parent->parent->subtree;
+ else
+ ft_diff_move(src, dst, opt);
+ }
+
+ ft_del(src, NULL, NULL);
+
+ src = next;
+ }
+}
+
+/* cette fonction permet d'initialiser la structure donnée en paramêtre
+ */
+void ft_init(t_ft *d) {
+ bzero(d, sizeof(*d));
+ d->prev = d->next = d;
+ d->parent = d;
+ SET(d->status, BASE);
+}
+
+t_file_diff *fct_free_diff_desc(void *data, t_file_diff *desc) {
+ if (desc->src1) fct_free_file_desc(data, desc->src1);
+ if (desc->src2) fct_free_file_desc(data, desc->src2);
+ free(desc);
+ return (NULL);
+}
+
+char *build_diff_line(char *path, char *filename, t_file_diff *info) {
+ static char tmp[BUFFER_LENGTH];
+ static char opath[BUFFER_LENGTH];
+ char *s = tmp;
+ char *ppath;
+
+ *s = 0;
+ if (info->diff == 0) {
+ ppath = opath;
+ if (Output_Str) ppath += sprintf(ppath, "%s/", Output_Str);
+ if (Rewrite_Src1) ppath += sprintf(ppath, "%s/", Rewrite_Src1);
+ sprintf(ppath, "%s", path);
+ s += sprintf(s, "= %s", build_line(opath, filename, info->src1));
+ return (tmp);
+ }
+
+ if (info->src1 && IS(Options, SHOW_OLD)) {
+ ppath = opath;
+ if (Output_Str) ppath += sprintf(ppath, "%s/", Output_Str);
+ if (Rewrite_Src1) ppath += sprintf(ppath, "%s/", Rewrite_Src1);
+ sprintf(ppath, "%s", path);
+
+ if (!info->src2)
+ s += sprintf(s, "- %s", build_line(opath, filename, info->src1));
+ else
+ s += sprintf(s, IS(Options, SHOW_NEW)?"< %s\n":"< %s",
+ build_line(opath, filename, info->src1));
+ }
+ if (info->src2 && IS(Options, SHOW_NEW)) {
+ ppath = opath;
+ if (Output_Str) ppath += sprintf(ppath, "%s/", Output_Str);
+ if (Rewrite_Src2) ppath += sprintf(ppath, "%s/", Rewrite_Src2);
+ sprintf(ppath, "%s", path);
+
+ if (!info->src1)
+ s += sprintf(s, "+ %s", build_line(opath, filename, info->src2));
+ else
+ s += sprintf(s, "> %s", build_line(opath, filename, info->src2));
+ }
+ if (*tmp) return (tmp);
+ return (NULL);
+}
+
+int output_diff_write(t_file_status *desc, t_ft *tree, int number) {
+ return (output_file_write_(desc, tree, number, build_diff_line));
+}
+
+/* traduct a string options descriptions to flags
+ */
+int output_diff_fcntl(t_file_status *env, int cmd) {
+ return (0);
+}
+
+
+
+/* cette fonction se base sur les différents paramêtres pour
+ * déterminer les différences entre les signatures de deux types de sources.
+ * Aux types de sources sont associées des fonctions spécialisées. Cette
+ * définition est valable de la même manière pour la destination
+ */
+int flxcheck_main(int argc, char **argv) {
+ /* tree for each source */
+ t_ft src1 = { &src1, &src1, &src1, NULL, NULL, NULL, BASE };
+ t_ft src2 = { &src2, &src2, &src2, NULL, NULL, NULL, BASE };
+ /* tree for destination */
+ t_ft dst = { &dst, &dst, &dst, NULL, NULL, NULL, BASE|CHANGED };
+ t_ft tmp1, tmp2; /* les bases temporaires */
+ int nb1 = 0, nb2 = 0;
+
+ /* il faut initialiser les structures de manière à définir les
+ * fonctions associées aux sources */
+ /* on initialise un premier type de source à partir d'un premier pointeur
+ * sur arbre et vice-versa
+ */
+ if (!InputSrc1 || !InputSrc2) {
+ arg_usage(flxcheck_poptions, "{source1 source2 | source1 [...] , source2 [...]}");
+ }
+
+ if (!Output) Output = output_alloc();
+ output_add(Output, "stdout:", OutputTypes);
+
+ /* il faut initialiser les bases temporaires à partir des bases originales */
+ ft_init(&tmp1);
+ ft_init(&tmp2);
+
+ while (!input_eof(InputSrc1) || !input_eof(InputSrc2)) {
+ /* la comparaison s'effectue sur les deux sources simultanément */
+
+ /* on lit des données dans chacune des entrées vers un tampon */
+ nb1 += input_read(InputSrc1, &src1);
+ nb2 += input_read(InputSrc2, &src2);
+
+ /* on compare les données deux à deux afin de compléter 'dst' */
+ ft_find_diff(&src1, &src2, &dst);
+ ft_find_diff(&src1, &tmp2, &dst);
+ ft_find_diff(&src2, &tmp1, &dst);
+
+ /* toutes les données identiques ont été détectée pour la partie
+ * déterminée, on déplace le contenu de la source vers les tampons */
+ ft_move(&src1, &tmp1);
+ ft_move(&src2, &tmp2);
+
+
+ /* visualiser les différences si possible */
+ // ft_diff_move(&tmp1, &dst, ONLY_SRC1);
+ // ft_diff_move(&tmp2, &dst, ONLY_SRC2);
+ // output_write(output, &dst);
+ // ft_free(&dst, (void*)fct_free_diff_desc, NULL);
+
+ /* les sources sont vidées, il est possible de recommencer l'opération */
+ }
+
+
+ /* il n'y a plus de différences détectables
+ * le reste sont des différences uniques */
+ ft_diff_move(&tmp1, &dst, ONLY_SRC1);
+ ft_diff_move(&tmp2, &dst, ONLY_SRC2);
+
+ /* visualiser les différences */
+ output_write(Output, &dst, 0);
+ ft_free(&dst, (void*)fct_free_diff_desc, NULL);
+
+ /* close all interface */
+ input_free(InputSrc1);
+ input_free(InputSrc2);
+ output_free(Output);
+
+ return (0);
+}
+
+
+
+int flxcheck_pfct(int opt, t_param *param, char **flag, char **argv) {
+ static int status = 1; /* source 1 or source 2 */
+
+ if (opt == O_HELP) arg_usage(flxcheck_poptions, NULL);
+ else if (opt == O_SH_ALL) SET(Options, SHOW_SAME|SHOW_OLD|SHOW_NEW);
+ else if (opt == O_SH_OLD) UNSET(Options, SHOW_SAME|SHOW_NEW);
+ else if (opt == O_SH_NEW) UNSET(Options, SHOW_SAME|SHOW_OLD);
+ else if (opt == O_IGN_MODE) UNSET(Diff, DIFF_MODE);
+ else if (opt == O_IGN_OWNER) UNSET(Diff, DIFF_OWNER);
+ else if (opt == O_IGN_SUM) UNSET(Diff, DIFF_CHECKSUM);
+ else if (opt == O_IGN_SIZE) UNSET(Diff, DIFF_SIZE);
+ else if (opt == O_IGN_DATE) UNSET(Diff, DIFF_TIME);
+ else if (opt == O_IGN_LINK) UNSET(Diff, DIFF_LINK);
+ else if (opt == O_IGN_LDATE) UNSET(Diff, DIFF_LDATE);
+ else if (opt == O_SH_HR) SET(Options, GOPT_HUMAN_READABLE);
+ else if (opt == O_REWRITE_SRC1) Rewrite_Src1 = strdup(*(argv+1));
+ else if (opt == O_REWRITE_SRC2) Rewrite_Src2 = strdup(*(argv+1));
+ else if (opt == O_OUTPUT) Output_Str = strdup(*(argv+1));
+ else if (opt == O_IGN_DOT) SET(Options, GOPT_IGNORE_DOT);
+ else if (opt == -1) {
+ if (!strcmp(*argv, ",")) status = 3;
+ else if (status == 1 || status == 2) {
+ /* add new source to source 1 */
+ if (!InputSrc1) InputSrc1 = input_alloc();
+ input_add(InputSrc1, *argv, InputTypes);
+
+ if (status == 1) { /* search alone ',' in others parameters */
+ char **ptr = argv;
+ while (*ptr && strcmp(*ptr, ",")) ptr++;
+ if (*ptr) status = 2;
+ else status = 3;
+ }
+ }
+ else { /* status == 3 */
+ /* add new source to source 2 */
+ if (!InputSrc2) InputSrc2 = input_alloc();
+ input_add(InputSrc2, *argv, InputTypes);
+ }
+ }
+ else return (-1);
+ return (param ? param->minarg : 0);
+}
+
+