/* * Compare two timestamps * * Return 0 on success, < 0 otherwise * * On success, res_d will be set as: * -1, if date in ts1 is before that of ts2; * 0, if date in ts1 is the same as that of ts2; * 1, if date in ts1 is after that of ts2; * * res_t will be set in a similar manner */ int timestamp_compare(const char *ts1, const char *ts2, int *res_d, int *res_t) { char *date1 = NULL, *time1 = NULL; char *date2 = NULL, *time2 = NULL; int ret = -1; assert(ts1 && ts2); if (timestamp_split(ts1, &date1, &time1) < 0 || timestamp_split(ts2, &date2, &time2) < 0) { log_error("Failed to get dates and times from %s and %s", ts1, ts2); goto failed; } if (time_compare(date1, date2, res_d, '-') < 0 || time_compare(time1, time2, res_t, ':') < 0) { log_error("Failed to compare dates or times in %s and %s", ts1, ts2); } else { ret = 0; /* Success */ } /* Fall through */ failed: if (date1) { free(date1); } if (date2) { free(date2); } if (time1) { free(time1); } if (time2) { free(time2); } return ret; }
static rev_commit * rev_commit_locate_date (rev_ref *branch, time_t date) { rev_commit *commit; for (commit = branch->commit; commit; commit = commit->parent) { if (time_compare (commit->date, date) <= 0) return commit; } return NULL; }
int rev_commit_later (rev_commit *a, rev_commit *b) { long t; assert (a != b); t = time_compare (a->date, b->date); if (t > 0) return 1; if (t < 0) return 0; if ((uintptr_t) a > (uintptr_t) b) return 1; return 0; }
static int rev_commit_date_compare (const void *av, const void *bv) { const rev_commit *a = *(const rev_commit **) av; const rev_commit *b = *(const rev_commit **) bv; int t; /* * NULL entries sort last */ if (!a && !b) return 0; else if (!a) return 1; else if (!b) return -1; #if 0 /* * Entries with no files sort next */ if (a->nfiles != b->nfiles) return b->nfiles - a->nfiles; #endif /* * tailed entries sort next */ if (a->tailed != b->tailed) return a->tailed - b->tailed; /* * Newest entries sort first */ t = -time_compare (a->date, b->date); if (t) return t; /* * Ensure total order by ordering based on file address */ if ((uintptr_t) a->file > (uintptr_t) b->file) return -1; if ((uintptr_t) a->file < (uintptr_t) b->file) return 1; return 0; }
int rev_file_later (rev_file *af, rev_file *bf) { long t; /* * When merging file lists, we should never see the same * object in both trees */ assert (af != bf); t = time_compare (af->date, bf->date); if (t > 0) return 1; if (t < 0) return 0; if ((uintptr_t) af > (uintptr_t) bf) return 1; return 0; }
int main (int argc, const char *argv[]) { int c; int i; int i_bad = 0; char dst[100]; char *dst_p; int achars[] = {'!', '"', '%', '&', '(', ')', '*', '+', ',', '-', '.', '/', '?', '<', '=', '>'}; /********************************************* * Test ACHAR and DCHAR *********************************************/ for (c='A'; c<='Z'; c++ ) { if (!iso9660_is_dchar(c)) { printf("Failed iso9660_is_dchar test on %c\n", c); i_bad++; } if (!iso9660_is_achar(c)) { printf("Failed iso9660_is_achar test on %c\n", c); i_bad++; } } if (i_bad) return i_bad; for (c='0'; c<='9'; c++ ) { if (!iso9660_is_dchar(c)) { printf("Failed iso9660_is_dchar test on %c\n", c); i_bad++; } if (!iso9660_is_achar(c)) { printf("Failed iso9660_is_achar test on %c\n", c); i_bad++; } } if (i_bad) return i_bad; for (i=0; i<=13; i++ ) { c=achars[i]; if (iso9660_is_dchar(c)) { printf("Should not pass iso9660_is_dchar test on %c\n", c); i_bad++; } if (!iso9660_is_achar(c)) { printf("Failed iso9660_is_achar test on symbol %c\n", c); i_bad++; } } if (i_bad) return i_bad; /********************************************* * Test iso9660_strncpy_pad *********************************************/ dst_p = iso9660_strncpy_pad(dst, "1_3", 5, ISO9660_DCHARS); if ( 0 != strncmp(dst, "1_3 ", 5) ) { printf("Failed iso9660_strncpy_pad DCHARS\n"); return 31; } dst_p = iso9660_strncpy_pad(dst, "ABC!123", 2, ISO9660_ACHARS); if ( 0 != strncmp(dst, "AB", 2) ) { printf("Failed iso9660_strncpy_pad ACHARS truncation\n"); return 32; } /********************************************* * Test iso9660_dirname_valid_p *********************************************/ if ( iso9660_dirname_valid_p("/NOGOOD") ) { printf("/NOGOOD should fail iso9660_dirname_valid_p\n"); return 33; } if ( iso9660_dirname_valid_p("LONGDIRECTORY/NOGOOD") ) { printf("LONGDIRECTORY/NOGOOD should fail iso9660_dirname_valid_p\n"); return 34; } if ( !iso9660_dirname_valid_p("OKAY/DIR") ) { printf("OKAY/DIR should pass iso9660_dirname_valid_p\n"); return 35; } if ( iso9660_dirname_valid_p("OKAY/FILE.EXT") ) { printf("OKAY/FILENAME.EXT should fail iso9660_dirname_valid_p\n"); return 36; } /********************************************* * Test iso9660_pathname_valid_p *********************************************/ if ( !iso9660_pathname_valid_p("OKAY/FILE.EXT") ) { printf("OKAY/FILE.EXT should pass iso9660_dirname_valid_p\n"); return 37; } if ( iso9660_pathname_valid_p("OKAY/FILENAMETOOLONG.EXT") ) { printf("OKAY/FILENAMETOOLONG.EXT should fail iso9660_dirname_valid_p\n"); return 38; } if ( iso9660_pathname_valid_p("OKAY/FILE.LONGEXT") ) { printf("OKAY/FILE.LONGEXT should fail iso9660_dirname_valid_p\n"); return 39; } dst_p = iso9660_pathname_isofy ("this/file.ext", 1); if ( 0 != strncmp(dst_p, "this/file.ext;1", 16) ) { printf("Failed iso9660_pathname_isofy\n"); free(dst_p); return 40; } free(dst_p); /********************************************* * Test get/set date *********************************************/ { struct tm *p_tm, tm; iso9660_dtime_t dtime; time_t now = time(NULL); memset(&dtime, 0, sizeof(dtime)); p_tm = localtime(&now); iso9660_set_dtime(p_tm, &dtime); iso9660_get_dtime(&dtime, true, &tm); p_tm = gmtime(&now); iso9660_set_dtime_with_timezone(p_tm, 0, &dtime); if (!iso9660_get_dtime(&dtime, false, &tm)) { printf("Error returned by iso9660_get_dtime_with_timezone\n"); return 41; } if ( !time_compare(p_tm, &tm) ) { printf("GMT time retrieved with iso9660_get_dtime_with_timezone() not same as that\n"); printf("set with iso9660_set_dtime().\n"); return 42; } #ifdef HAVE_TM_GMTOFF if ( !time_compare(p_tm, &tm) ) { return 43; } p_tm = gmtime(&now); iso9660_set_dtime(p_tm, &dtime); if (!iso9660_get_dtime(&dtime, false, &tm)) { printf("Error returned by iso9660_get_dtime\n"); return 44; } if ( !time_compare(p_tm, &tm) ) { printf("GMT time retrieved with iso9660_get_dtime() not same as that\n"); printf("set with iso9660_set_dtime().\n"); return 45; } { iso9660_ltime_t ltime; p_tm = localtime(&now); iso9660_set_ltime(p_tm, <ime); if (!iso9660_get_ltime(<ime, &tm)) { printf("Problem running iso9660_get_ltime\n"); return 46; } if ( ! time_compare(p_tm, &tm) ) { printf("local time retrieved with iso9660_get_ltime() not\n"); printf("same as that set with iso9660_set_ltime().\n"); return 47; } p_tm = gmtime(&now); iso9660_set_ltime(p_tm, <ime); iso9660_get_ltime(<ime, &tm); if ( ! time_compare(p_tm, &tm) ) { printf("GMT time retrieved with iso9660_get_ltime() not\n"); printf("same as that set with iso9660_set_ltime().\n"); return 48; } } #endif } return 0; }
/* * Construct a branch using CVS revision numbers */ static rev_commit * rev_branch_cvs (cvs_file *cvs, cvs_number *branch) { cvs_number n; rev_commit *head = NULL; rev_commit *c, *p, *gc; Node *node; n = *branch; n.n[n.c-1] = -1; for (node = cvs_find_version (cvs, &n); node; node = node->next) { cvs_version *v = node->v; cvs_patch *p = node->p; rev_commit *c; if (!v) continue; c = calloc (1, sizeof (rev_commit)); c->date = v->date; c->commitid = v->commitid; c->author = v->author; if (p) c->log = p->log; if (v->dead) c->nfiles = 0; else c->nfiles = 1; /* leave this around so the branch merging stuff can find numbers */ c->file = rev_file_rev (cvs->name, &v->number, v->date); if (!v->dead) { node->file = c->file; c->file->mode = cvs->mode; } c->parent = head; head = c; } /* * Make sure the dates along the branch are well ordered. As we * want to preserve current data, push previous versions back to * align with newer revisions. */ for (c = head, gc = NULL; (p = c->parent); gc = c, c = p) { if (time_compare (p->file->date, c->file->date) > 0) { fprintf (stderr, "Warning: %s:", cvs->name); dump_number_file (stderr, " ", &p->file->number); dump_number_file (stderr, " is newer than", &c->file->number); /* Try to catch an odd one out, such as a commit with the * clock set wrong. Dont push back all commits for that, * just fix up the current commit instead of the * parent. */ if (gc && time_compare (p->file->date, gc->file->date) <= 0) { dump_number_file (stderr, ", adjusting", &c->file->number); c->file->date = p->file->date; c->date = p->date; } else { dump_number_file (stderr, ", adjusting", &c->file->number); p->file->date = c->file->date; p->date = c->date; } fprintf (stderr, "\n"); } } return head; }
static void rev_list_graft_branches (rev_list *rl, cvs_file *cvs) { rev_ref *h; rev_commit *c; cvs_version *cv; cvs_branch *cb; /* * Glue branches together */ for (h = rl->heads; h; h = h->next) { /* * skip master branch; it "can't" join * any other branches and it may well end with a vendor * branch revision of the file, which will then create * a loop back to the recorded branch point */ if (h == rl->heads) continue; if (h->tail) continue; /* * Find last commit on branch */ for (c = h->commit; c && c->parent; c = c->parent) if (c->tail) { c = NULL; /* already been done, skip */ break; } if (c) { /* * Walk the version tree, looking for the branch location. * Note that in the presense of vendor branches, the * branch location may actually be out on that vendor branch */ for (cv = cvs->versions; cv; cv = cv->next) { for (cb = cv->branches; cb; cb = cb->next) { if (cvs_number_compare (&cb->number, &c->file->number) == 0) { c->parent = rev_find_cvs_commit (rl, &cv->number); c->tail = 1; break; } } if (c->parent) { #if 0 /* * check for a parallel vendor branch */ for (cb = cv->branches; cb; cb = cb->next) { if (cvs_is_vendor (&cb->number)) { cvs_number v_n; rev_commit *v_c, *n_v_c; fprintf (stderr, "Found merge into vendor branch\n"); v_n = cb->number; v_c = NULL; /* * Walk to head of vendor branch */ while ((n_v_c = rev_find_cvs_commit (rl, &v_n))) { /* * Stop if we reach a date after the * branch version date */ if (time_compare (n_v_c->date, c->date) > 0) break; v_c = n_v_c; v_n.n[v_n.c - 1]++; } if (v_c) { fprintf (stderr, "%s: rewrite branch", cvs->name); dump_number_file (stderr, " branch point", &v_c->file->number); dump_number_file (stderr, " branch version", &c->file->number); fprintf (stderr, "\n"); c->parent = v_c; } } } #endif break; } } } } }
/* * "Vendor branches" (1.1.x) are created by importing sources from * an external source. In X.org, this was from XFree86 and DRI. When * these trees are imported, cvs sets the 'default' branch in each ,v file * to point along this branch. This means that tags made between * the time the vendor branch is imported and when a new revision * is committed to the head branch are placed on the vendor branch * In addition, any files without such a commit appear to adopt * the vendor branch as 'head'. We fix this by merging these two * branches together as if they were the same */ static void rev_list_patch_vendor_branch (rev_list *rl, cvs_file *cvs) { rev_ref *trunk = NULL; rev_ref *vendor = NULL; rev_ref *h; rev_commit *t, **tp, *v, **vp; rev_commit *vlast; rev_ref **h_p; int delete_head; trunk = rl->heads; for (h_p = &rl->heads; (h = *h_p);) { delete_head = 0; if (h->commit && cvs_is_vendor (&h->commit->file->number)) { /* * Find version 1.2 on the trunk. * This will reset the default branch set * when the initial import was done. * Subsequent imports will *not* set the default * branch, and should be on their own branch */ vendor = h; t = trunk->commit; v = vendor->commit; for (vlast = vendor->commit; vlast; vlast = vlast->parent) if (!vlast->parent) break; tp = &trunk->commit; /* * Find the latest trunk revision older than * the entire vendor branch */ while ((t = *tp)) { if (!t->parent || time_compare (vlast->file->date, t->parent->file->date) >= 0) { break; } tp = &t->parent; } if (t) { /* * If the first commit is older than the last element * of the vendor branch, paste them together and * nuke the vendor branch */ if (time_compare (vlast->file->date, t->file->date) >= 0) { delete_head = 1; } else { /* * Splice out any portion of the vendor branch * newer than a the next trunk commit after * the oldest branch commit. */ for (vp = &vendor->commit; (v = *vp); vp = &v->parent) if (time_compare (v->date, t->date) <= 0) break; if (vp == &vendor->commit) { /* * Nothing newer, nuke vendor branch */ delete_head = 1; } else { /* * Some newer stuff, patch parent */ *vp = NULL; } } } else delete_head = 1; /* * Patch up the remaining vendor branch pieces */ if (!delete_head) { rev_commit *vr; if (!vendor->name) { char rev[CVS_MAX_REV_LEN]; char name[MAXPATHLEN]; cvs_number branch; branch = vlast->file->number; branch.c--; cvs_number_string (&branch, rev); snprintf (name, sizeof (name), "import-%s", rev); vendor->name = atom (name); vendor->parent = trunk; vendor->degree = vlast->file->number.c; } for (vr = vendor->commit; vr; vr = vr->parent) { if (!vr->parent) { vr->tail = 1; vr->parent = v; break; } } } /* * Merge two branches based on dates */ while (t && v) { if (time_compare (v->file->date, t->file->date) >= 0) { *tp = v; tp = &v->parent; v = v->parent; } else { *tp = t; tp = &t->parent; t = t->parent; } } if (t) *tp = t; else *tp = v; } if (delete_head) { *h_p = h->next; free (h); } else { h_p = &(h->next); } } #if DEBUG fprintf (stderr, "%s spliced:\n", cvs->name); for (t = trunk->commit; t; t = t->parent) { dump_number_file (stderr, "\t", &t->file->number); fprintf (stderr, "\n"); } #endif }
/* * Merge a set of per-file branches into a global branch */ static void rev_branch_merge (rev_ref **branches, int nbranch, rev_ref *branch, rev_list *rl) { int nlive; int n; rev_commit *prev = NULL; rev_commit *head = NULL, **tail = &head; rev_commit **commits; rev_commit *commit; rev_commit *latest; rev_commit **p; int lazy = 0; time_t start = 0; ALLOC((commits = calloc (nbranch, sizeof (rev_commit *))), "rev_branch_merge"); nlive = 0; // printf("rev_branch_merge: nbranch=%d\n", nbranch); for (n = 0; n < nbranch; n++) { rev_commit *c; /* * Initialize commits to head of each branch */ c = commits[n] = branches[n]->commit; /* * Compute number of branches with remaining entries */ if (!c) continue; if (branches[n]->tail) { c->tailed = 1; continue; } nlive++; while (c && !c->tail) { if (!start || time_compare(c->date, start) < 0) { // printf(" 1:setting start=%ld:%s (from %s)\n", start, ctime_nonl(&start), c->file->name); start = c->date; } c = c->parent; } if (c && (c->file || c->date != c->parent->date)) { if (!start || time_compare(c->date, start) < 0) { // printf(" 2:setting start=%ld:%s (from %s)\n", start, ctime_nonl(&start), c->file->name); start = c->date; } } } for (n = 0; n < nbranch; n++) { rev_commit *c = commits[n]; #if 0 printf("Doing commit %p: @ %ld\n", c, c->date); if (c->file) printf(" %s\n", c->file->name); #endif if (!c->tailed) continue; if (!start || time_compare(start, c->date) >= 0) continue; if (c->file) { /* This case can occur if files have been added to a branch since it's creation. */ printf( "Warning: %s too late date %s through branch %s (%ld:%ld=%ld)\n", c->file->name, ctime_nonl(&c->date), branch->name, start, c->date, start-c->date); continue; } commits[n] = NULL; } /* * Walk down branches until each one has merged with the * parent branch */ while (nlive > 0 && nbranch > 0) { for (n = 0, p = commits, latest = NULL; n < nbranch; n++) { rev_commit *c = commits[n]; if (!c) continue; *p++ = c; if (c->tailed) continue; if (!latest || time_compare(latest->date, c->date) < 0) latest = c; } nbranch = p - commits; /* * Construct current commit */ if (!lazy) { commit = rev_commit_build (commits, latest, nbranch); if (rev_mode == ExecuteGit) lazy = 1; } else { commit = create_tree(latest); } /* * Step each branch */ nlive = 0; for (n = 0; n < nbranch; n++) { rev_commit *c = commits[n]; rev_commit *to; /* already got to parent branch? */ if (c->tailed) continue; /* not affected? */ if (c != latest && !rev_commit_match(c, latest)) { if (c->parent || c->file) nlive++; continue; } to = c->parent; /* starts here? */ if (!to) goto Kill; if (c->tail) { /* * Adding file independently added on another * non-trunk branch. */ if (!to->parent && !to->file) goto Kill; /* * If the parent is at the beginning of trunk * and it is younger than some events on our * branch, we have old CVS adding file * independently * added on another branch. */ if (start && time_compare(start, to->date) < 0) goto Kill; /* * XXX: we still can't be sure that it's * not a file added on trunk after parent * branch had forked off it but before * our branch's creation. */ to->tailed = 1; } else if (to->file) { nlive++; } else { /* * See if it's recent CVS adding a file * independently added on another branch. */ if (!to->parent) goto Kill; if (to->tail && to->date == to->parent->date) goto Kill; nlive++; } if (to->file) set_commit(to); else delete_commit(c); commits[n] = to; continue; Kill: delete_commit(c); commits[n] = NULL; } *tail = commit; tail = &commit->parent; prev = commit; } /* * Connect to parent branch */ nbranch = rev_commit_date_sort (commits, nbranch); if (nbranch && branch->parent ) { rev_ref *lost; int present; // present = 0; for (present = 0; present < nbranch; present++) if (commits[present]->file) { /* * Skip files which appear in the repository after * the first commit along the branch */ if (prev && commits[present]->date > prev->date && commits[present]->date == rev_commit_first_date (commits[present])) { fprintf (stderr, "Warning: file %s appears after branch %s date\n", commits[present]->file->name, branch->name); continue; } break; } if (present == nbranch) *tail = NULL; else if ((*tail = rev_commit_locate_one (branch->parent, commits[present]))) { if (prev && time_compare ((*tail)->date, prev->date) > 0) { fprintf (stderr, "Warning: branch point %s -> %s later than branch\n", branch->name, branch->parent->name); fprintf (stderr, "\ttrunk(%3d): %s %s", n, ctime_nonl (&commits[present]->date), commits[present]->file ? " " : "D" ); if (commits[present]->file) dump_number_file (stderr, commits[present]->file->name, &commits[present]->file->number); fprintf (stderr, "\n"); fprintf (stderr, "\tbranch(%3d): %s ", n, prev->file?ctime_nonl (&prev->file->date):"no file"); if (prev->file) { dump_number_file (stderr, prev->file->name, &prev->file->number); } fprintf (stderr, "\n"); } } else if ((*tail = rev_commit_locate_date (branch->parent, commits[present]->date))) fprintf (stderr, "Warning: branch point %s -> %s matched by date\n", branch->name, branch->parent->name); else { fprintf (stderr, "Error: branch point %s -> %s not found.", branch->name, branch->parent->name); if ((lost = rev_branch_of_commit (rl, commits[present]))) fprintf (stderr, " Possible match on %s.", lost->name); fprintf (stderr, "\n"); } if (*tail) { if (prev) prev->tail = 1; } else *tail = rev_commit_build (commits, commits[0], nbranch); } for (n = 0; n < nbranch; n++) if (commits[n]) commits[n]->tailed = 0; free (commits); branch->commit = head; }