/* remove duplicate hashes from the fullfile creation list */ static GList *get_deduplicated_fullfile_list(struct manifest *manifest) { GList *list; GList *outfiles = NULL; struct file *file; struct file *prev = NULL; struct file *tmp; // presort by hash for easy deduplication list = manifest->files = g_list_sort(manifest->files, file_sort_hash); for (; list; list = g_list_next(list)) { tmp = list->data; // find first new file if (tmp->last_change == manifest->version) { prev = tmp; outfiles = g_list_prepend(outfiles, tmp); break; } } for (; list; list = g_list_next(list)) { file = list->data; // add any new file having a unique hash //FIXME: rename logic will be needed here if (file->is_deleted || (file->last_change != manifest->version)) { continue; } if (!hash_compare(prev->hash, file->hash)) { outfiles = g_list_prepend(outfiles, file); prev = file; } } // don't want sort by hash else hash[0] locks will be very conflicted outfiles = g_list_sort(outfiles, file_sort_filename); return outfiles; }
/* * compare the variable a with the variable b * returns * -1 a < b * +1 a > b * 0 a = b */ int v_compare(var_t *a, var_t *b) { var_num_t dt; var_int_t di; int i, ci; var_t *ea, *eb; if (a == 0 || b == 0) { err_evsyntax(); return 0; } if (a->type == V_INT && b->type == V_INT) { di = (a->v.i - b->v.i); i = di < 0 ? -1 : di > 0 ? 1 : 0; return i; } else if ((a->type == V_INT || a->type == V_NUM) && (b->type == V_INT || b->type == V_NUM)) { var_num_t left = (a->type == V_NUM) ? a->v.n : a->v.i; var_num_t right = (b->type == V_NUM) ? b->v.n : b->v.i; dt = (left - right); i = dt < 0.0 ? -1 : dt > 0.0 ? 1 : 0; return i; } if ((a->type == V_STR) && (b->type == V_STR)) { return strcmp(a->v.p.ptr, b->v.p.ptr); } if ((a->type == V_STR) && (b->type == V_NUM)) { if (a->v.p.ptr[0] == '\0' || is_number((char *) a->v.p.ptr)) { // compare // nums dt = v_getval(a); return (dt < b->v.n) ? -1 : ((dt == b->v.n) ? 0 : 1);} return 1; } if ((a->type == V_NUM) && (b->type == V_STR)) { if (b->v.p.ptr[0] == '\0' || is_number((char *) b->v.p.ptr)) { // compare // nums dt = v_getval(b); return (dt < a->v.n) ? 1 : ((dt == a->v.n) ? 0 : -1);}return - 1; } if ((a->type == V_STR) && (b->type == V_INT)) { if (a->v.p.ptr[0] == '\0' || is_number((char *) a->v.p.ptr)) { // compare // nums di = v_igetval(a); return (di < b->v.i) ? -1 : ((di == b->v.i) ? 0 : 1);} return 1; } if ((a->type == V_INT) && (b->type == V_STR)) { if (b->v.p.ptr[0] == '\0' || is_number((char *) b->v.p.ptr)) { // compare // nums di = v_igetval(b); return (di < a->v.i) ? 1 : ((di == a->v.i) ? 0 : -1);}return - 1; } if ((a->type == V_ARRAY) && (b->type == V_ARRAY)) { // check size if (a->v.a.size != b->v.a.size) { if (a->v.a.size < b->v.a.size) { return -1; } return 1; } // check every element for (i = 0; i < a->v.a.size; i++) { ea = (var_t *) (a->v.a.ptr + sizeof(var_t) * i); eb = (var_t *) (b->v.a.ptr + sizeof(var_t) * i); if ((ci = v_compare(ea, eb)) != 0) { return ci; } } return 0; // equal } if (a->type == V_UDS && b->type == V_UDS) { return uds_compare(a, b); } if (a->type == V_HASH && b->type == V_HASH) { return hash_compare(a, b); } err_evtype(); // ndc 01/08/2001 return 1; }
int match_manifests(struct manifest *m1, struct manifest *m2) { GList *list1, *list2; struct file *file1, *file2; int must_sort = 0; int count = 0; int first = 1; if (!m1) { printf("Matching manifests up failed: No old manifest!\n"); return -1; } if (!m2) { printf("Matching manifests up failed: No new manifest!\n"); return -1; } m1->files = g_list_sort(m1->files, file_sort_filename); m2->files = g_list_sort(m2->files, file_sort_filename); list1 = g_list_first(m1->files); list2 = g_list_first(m2->files); while (list1 && list2) { int ret; file1 = list1->data; file2 = list2->data; file1->peer = NULL; file2->peer = NULL; ret = strcmp(file1->filename, file2->filename); if (ret == 0) { if (file1->is_deleted && file2->is_deleted && file1->is_rename) { file2->is_rename = file1->is_rename; hash_assign(file1->hash, file2->hash); } if (hash_compare(file1->hash, file2->hash) && file1->is_dir == file2->is_dir && file1->is_link == file2->is_link && file1->is_deleted == file2->is_deleted && file1->is_file == file2->is_file && file1->is_config == file2->is_config && file1->is_state == file2->is_state && file1->is_boot == file2->is_boot && file1->last_change >= minversion) { file2->last_change = file1->last_change; file2->is_rename = file1->is_rename; } else { account_changed_file(); if (first) { LOG(file1, "file changed", ""); first = 0; } count++; } if (!file1->is_deleted || file2->is_deleted) { file1->peer = file2; file2->peer = file1; } list1 = g_list_next(list1); list2 = g_list_next(list2); continue; } if (first) { LOG(file1, "file added? ", "(file2 is %s)", file2->filename); first = 0; } if (ret < 0) { struct file *file3; /* * if we get here, file1 got deleted... what we must do * is add a file entry for it in the target list. * However, since we're currently walking the list we * HAVE to prepend the entry.. and mark for sort at the * end. */ file3 = calloc(1, sizeof(struct file)); if (file3 == NULL) { assert(0); } file3->filename = strdup(file1->filename); hash_set_zeros(file3->hash); file3->is_deleted = 1; file3->is_config = file1->is_config; file3->is_state = file1->is_state; file3->is_boot = file1->is_boot; if (!file1->is_deleted) { file3->last_change = m2->version; } else { file3->last_change = file1->last_change; file3->is_rename = file1->is_rename; hash_assign(file1->hash, file3->hash); } file3->peer = file1; file1->peer = file3; list1 = g_list_next(list1); m2->files = g_list_prepend(m2->files, file3); m2->count++; if (!file1->is_deleted) { account_deleted_file(); count++; if (first) { LOG(file1, "file got deleted", ""); first = 0; } } must_sort = 1; continue; } /* if we get here, ret is > 0, which means this is a new file added */ /* all we do is advance the pointer */ account_new_file(); list2 = g_list_next(list2); count++; } /* now deal with the tail ends */ while (list1) { file1 = list1->data; struct file *file3; if (first) { LOG(file1, "file changed tail", ""); first = 0; } count++; /* * if we get here, file1 got deleted... what we must do is add * a file entry for it in the target list. However, since * we're currently walking the list we HAVE to prepend the * entry.. and mark for sort at the end. */ file3 = calloc(1, sizeof(struct file)); if (file3 == NULL) { assert(0); } file3->filename = strdup(file1->filename); hash_set_zeros(file3->hash); file3->is_deleted = 1; file3->is_config = file1->is_config; file3->is_state = file1->is_state; file3->is_boot = file1->is_boot; if (!file1->is_deleted) { file3->last_change = m2->version; } else { file3->last_change = file1->last_change; file3->is_rename = file1->is_rename; hash_assign(file1->hash, file3->hash); } file3->peer = file1; file1->peer = file3; list1 = g_list_next(list1); m2->files = g_list_prepend(m2->files, file3); m2->count++; if (!file1->is_deleted) { account_deleted_file(); } must_sort = 1; } while (list2) { account_new_file(); list2 = g_list_next(list2); if (first) { first = 0; } count++; } if (must_sort) { m2->files = g_list_sort(m2->files, file_sort_filename); } return count; }