commit 7d283eeedcc17429a90e21e179a6bb5183ffe3c8 from: Stefan Sperling date: Wed Nov 29 16:11:11 2017 UTC add and test basic blob diffing functionality commit - 574ed2c37db77eb4cb0b8ad77c01c093651da655 commit + 7d283eeedcc17429a90e21e179a6bb5183ffe3c8 blob - ae0f38629814f9c9648b74a1a15ef0a6500e7e9e blob + 398a3f922562de268369987a6e63de7130ec0fc9 --- include/got_error.h +++ include/got_error.h @@ -28,6 +28,7 @@ #define GOT_ERR_BAD_OBJ_HDR 0x0010 #define GOT_ERR_OBJ_TYPE 0x0011 #define GOT_ERR_BAD_OBJ_DATA 0x0012 +#define GOT_ERR_FILE_OPEN 0x0013 static const struct got_error { int code; @@ -46,6 +47,7 @@ static const struct got_error { { GOT_ERR_BAD_OBJ_HDR, "bad object header" }, { GOT_ERR_OBJ_TYPE, "wrong type of object" }, { GOT_ERR_BAD_OBJ_DATA, "bad object data" }, + { GOT_ERR_FILE_OPEN, "could not open file" }, }; const struct got_error * got_error(int code); blob - /dev/null blob + 1ae21b46afc122743b77b445adb5894aa04b1b8b (mode 644) --- /dev/null +++ include/got_diff.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2017 Stefan Sperling + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +const struct got_error * +got_diff_blob(struct got_blob_object *, struct got_blob_object *, FILE *); blob - b96bf6e63fbfc72d14e2b594437e9ce8b5c6ad44 blob + bdb83fceee0df5c7676df45f010fcf7eb142e276 --- include/got_object.h +++ include/got_object.h @@ -31,6 +31,7 @@ struct got_object_id { struct got_blob_object { FILE *f; struct got_zstream_buf zb; + size_t hdrlen; }; struct got_tree_entry { blob - 3a36222419a80834c5bd0d3c3c208cce1131a850 blob + 3f0e7f186d7c57e9a03d09d0121817515a1fbb9d --- lib/diff.h +++ lib/diff.h @@ -89,7 +89,7 @@ extern struct excludes *excludes_list; extern regex_t ignore_re; char *splice(char *, char *); -int diffreg(char *, char *, int); +const struct got_error *got_diffreg(int *, char *, char *, int); int easprintf(char **, const char *, ...); void *emalloc(size_t); void *erealloc(void *, size_t); blob - /dev/null blob + 4df08a9f67a515fb78e4dcc271a34dfb0de02f38 (mode 644) --- /dev/null +++ lib/diff.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2017 Stefan Sperling + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include + +#include "got_repository.h" +#include "got_object.h" +#include "got_error.h" + +#include "diff.h" + +static const struct got_error * +open_tempfile(FILE **sfp, char **sfn) +{ + static const int sfnlen = 20; + int fd; + + *sfn = calloc(sizeof(char), sfnlen); + if (*sfn == NULL) + return got_error(GOT_ERR_NO_MEM); + strlcpy(*sfn, "/tmp/got.XXXXXXXXXX", sfnlen); + if ((fd = mkstemp(*sfn)) == -1 || + ((*sfp) = fdopen(fd, "w+")) == NULL) { + if (fd != -1) { + unlink(*sfn); + close(fd); + } + free(*sfn); + return got_error(GOT_ERR_FILE_OPEN); + } + return NULL; +} + +const struct got_error * +got_diff_blob(struct got_blob_object *blob1, struct got_blob_object *blob2, + FILE *outfile) +{ + const struct got_error *err = NULL; + FILE *f1, *f2; + char *n1, *n2; + size_t len, hdrlen; + int res; + + err = open_tempfile(&f1, &n1); + if (err != NULL) + return err; + + err = open_tempfile(&f2, &n2); + if (err != NULL) { + fclose(f1); + free(n1); + return err; + } + + + hdrlen = blob1->hdrlen; + do { + err = got_object_blob_read_block(blob1, &len); + if (err) + goto done; + /* Skip blob object header first time around. */ + fwrite(blob1->zb.outbuf + hdrlen, len - hdrlen, 1, f1); + hdrlen = 0; + } while (len != 0); + + hdrlen = blob2->hdrlen; + do { + err = got_object_blob_read_block(blob2, &len); + if (err) + goto done; + /* Skip blob object header first time around. */ + fwrite(blob2->zb.outbuf + hdrlen, len - hdrlen, 1, f2); + hdrlen = 0; + } while (len != 0); + + fflush(f1); + fflush(f2); + + err = got_diffreg(&res, n1, n2, 0); +done: + unlink(n1); + unlink(n2); + fclose(f1); + fclose(f2); + free(n1); + free(n2); + return err; +} blob - 35d61c349cbfe211fbf8ea145150ee0e3dcb4796 blob + c2f476a91925fffd9c98f83da921dcdc62aadd0d --- lib/diffreg.c +++ lib/diffreg.c @@ -66,6 +66,7 @@ #include #include +#include #include #include @@ -79,7 +80,13 @@ #include #include #include +#include +#include +#include "got_error.h" +#include "got_object.h" +#include "got_diff.h" + #include "diff.h" #include "xmalloc.h" @@ -230,7 +237,12 @@ static char lastbuf[FUNCTION_CONTEXT_SIZE]; static int lastline; static int lastmatchline; +int Nflag, Pflag, rflag, sflag, Tflag; +int diff_format, diff_context, status; +char *start, *ifdefname, *diffargs, *label[2], *ignore_pats; +struct stat stb1, stb2; + /* * chrtran points to one of 2 translation tables: cup2low if folding upper to * lower case clow2low if not folding case @@ -289,14 +301,27 @@ u_char cup2low[256] = { 0xfd, 0xfe, 0xff }; -int -diffreg(char *file1, char *file2, int flags) +const struct got_error * +got_diffreg(int *rval, char *file1, char *file2, int flags) { + const struct got_error *err = NULL; FILE *f1, *f2; - int i, rval; + int i; + diff_format = D_UNIFIED; + + if (strcmp(file1, "-") == 0) + fstat(STDIN_FILENO, &stb1); + else if (stat(file1, &stb1) != 0) + return got_error(GOT_ERR_BAD_PATH); + + if (strcmp(file2, "-") == 0) + fstat(STDIN_FILENO, &stb2); + else if (stat(file2, &stb2) != 0) + return got_error(GOT_ERR_BAD_PATH); + f1 = f2 = NULL; - rval = D_SAME; + *rval = D_SAME; anychange = 0; lastline = 0; lastmatchline = 0; @@ -305,8 +330,10 @@ diffreg(char *file1, char *file2, int flags) chrtran = cup2low; else chrtran = clow2low; - if (S_ISDIR(stb1.st_mode) != S_ISDIR(stb2.st_mode)) - return (S_ISDIR(stb1.st_mode) ? D_MISMATCH1 : D_MISMATCH2); + if (S_ISDIR(stb1.st_mode) != S_ISDIR(stb2.st_mode)) { + *rval = (S_ISDIR(stb1.st_mode) ? D_MISMATCH1 : D_MISMATCH2); + return NULL; + } if (strcmp(file1, "-") == 0 && strcmp(file2, "-") == 0) goto closem; @@ -316,7 +343,6 @@ diffreg(char *file1, char *file2, int flags) if (!S_ISREG(stb1.st_mode)) { if ((f1 = opentemp(file1)) == NULL || fstat(fileno(f1), &stb1) < 0) { - warn("%s", file1); status |= 2; goto closem; } @@ -326,7 +352,6 @@ diffreg(char *file1, char *file2, int flags) f1 = fopen(file1, "r"); } if (f1 == NULL) { - warn("%s", file1); status |= 2; goto closem; } @@ -337,7 +362,6 @@ diffreg(char *file1, char *file2, int flags) if (!S_ISREG(stb2.st_mode)) { if ((f2 = opentemp(file2)) == NULL || fstat(fileno(f2), &stb2) < 0) { - warn("%s", file2); status |= 2; goto closem; } @@ -347,7 +371,6 @@ diffreg(char *file1, char *file2, int flags) f2 = fopen(file2, "r"); } if (f2 == NULL) { - warn("%s", file2); status |= 2; goto closem; } @@ -365,7 +388,7 @@ diffreg(char *file1, char *file2, int flags) if ((flags & D_FORCEASCII) == 0 && (!asciifile(f1) || !asciifile(f2))) { - rval = D_BINARY; + *rval = D_BINARY; status |= 1; goto closem; } @@ -378,41 +401,71 @@ diffreg(char *file1, char *file2, int flags) member = (int *)file[1]; equiv(sfile[0], slen[0], sfile[1], slen[1], member); - member = xreallocarray(member, slen[1] + 2, sizeof(*member)); + member = reallocarray(member, slen[1] + 2, sizeof(*member)); + if (member == NULL) { + err = got_error(GOT_ERR_NO_MEM); + goto closem; + } class = (int *)file[0]; unsort(sfile[0], slen[0], class); - class = xreallocarray(class, slen[0] + 2, sizeof(*class)); + class = reallocarray(class, slen[0] + 2, sizeof(*class)); + if (class == NULL) { + err = got_error(GOT_ERR_NO_MEM); + goto closem; + } - klist = xcalloc(slen[0] + 2, sizeof(*klist)); + klist = calloc(slen[0] + 2, sizeof(*klist)); + if (klist == NULL) { + err = got_error(GOT_ERR_NO_MEM); + goto closem; + } clen = 0; clistlen = 100; - clist = xcalloc(clistlen, sizeof(*clist)); + clist = calloc(clistlen, sizeof(*clist)); + if (clist == NULL) { + err = got_error(GOT_ERR_NO_MEM); + goto closem; + } i = stone(class, slen[0], member, klist, flags); free(member); free(class); - J = xreallocarray(J, len[0] + 2, sizeof(*J)); + J = reallocarray(J, len[0] + 2, sizeof(*J)); + if (J == NULL) { + err = got_error(GOT_ERR_NO_MEM); + goto closem; + } unravel(klist[i]); free(clist); + clist = NULL; free(klist); + klist = NULL; - ixold = xreallocarray(ixold, len[0] + 2, sizeof(*ixold)); - ixnew = xreallocarray(ixnew, len[1] + 2, sizeof(*ixnew)); + ixold = reallocarray(ixold, len[0] + 2, sizeof(*ixold)); + if (ixold == NULL) { + err = got_error(GOT_ERR_NO_MEM); + goto closem; + } + ixnew = reallocarray(ixnew, len[1] + 2, sizeof(*ixnew)); + if (ixnew == NULL) { + err = got_error(GOT_ERR_NO_MEM); + goto closem; + } check(f1, f2, flags); output(file1, f1, file2, f2, flags); closem: if (anychange) { status |= 1; - if (rval == D_SAME) - rval = D_DIFFER; + if (*rval == D_SAME) + *rval = D_DIFFER; } if (f1 != NULL) fclose(f1); if (f2 != NULL) fclose(f2); - return (rval); + return (err); } /* @@ -941,11 +994,7 @@ preadline(int fd, size_t rlen, off_t off) static int ignoreline(char *line) { - int ret; - - ret = regexec(&ignore_re, line, 0, NULL, 0); - free(line); - return (ret == 0); /* if it matched, it should be ignored. */ + return 0; /* do not ignore any lines */ } /* blob - a48d2da75fb713c02727e94d82ccc5cf85f6b8d4 blob + 9f51ba2b9750d803ffa4a14f0064cdd5da775840 --- lib/object.c +++ lib/object.c @@ -663,6 +663,9 @@ got_object_blob_open(struct got_blob_object **blob, if (obj->type != GOT_OBJ_TYPE_BLOB) return got_error(GOT_ERR_OBJ_TYPE); + if (blocksize < obj->hdrlen) + return got_error(GOT_ERR_NO_SPACE); + err = object_path(&path, &obj->id, repo); if (err) return err; @@ -688,6 +691,8 @@ got_object_blob_open(struct got_blob_object **blob, return err; } + (*blob)->hdrlen = obj->hdrlen; + free(path); return err; } blob - de7eb21b21c7823a753261aadf7cba35c9580fbf blob + a1ba1ae04dbeb9acd6336f78e076f480d6b3b871 --- regress/repository/Makefile +++ regress/repository/Makefile @@ -1,7 +1,8 @@ .PATH:${.CURDIR}/../../lib PROG = repository_test -SRCS = path.c repository.c error.c refs.c object.c sha1.c repository_test.c +SRCS = path.c repository.c error.c refs.c object.c sha1.c diff.c \ + diffreg.c xmalloc.c repository_test.c CPPFLAGS = -I${.CURDIR}/../../include LDADD = -lutil -lz blob - e5867e0a5aae93c78d3d5ba2dd7e3ade9b54f54b blob + 926fc74d1f0638380b45f2cbac120b175a884b69 --- regress/repository/repository_test.c +++ regress/repository/repository_test.c @@ -227,6 +227,63 @@ repo_read_blob(const char *repo_path) got_object_blob_close(blob); got_object_close(obj); + got_repo_close(repo); + return (err == NULL); +} + +static int +repo_diff_blob(const char *repo_path) +{ + const char *blob1_sha1 = "141f5fdc96126c1f4195558560a3c915e3d9b4c3"; + const char *blob2_sha1 = "de7eb21b21c7823a753261aadf7cba35c9580fbf"; + const struct got_error *err; + struct got_repository *repo; + struct got_object_id id1; + struct got_object_id id2; + struct got_object *obj1; + struct got_object *obj2; + struct got_blob_object *blob1; + struct got_blob_object *blob2; + char hex[SHA1_DIGEST_STRING_LENGTH]; + int i; + size_t len; + + if (!got_parse_sha1_digest(id1.sha1, blob1_sha1)) + return 0; + if (!got_parse_sha1_digest(id2.sha1, blob2_sha1)) + return 0; + + err = got_repo_open(&repo, repo_path); + if (err != NULL || repo == NULL) + return 0; + + err = got_object_open(&obj1, repo, &id1); + if (err != NULL || obj1 == NULL) + return 0; + if (obj1->type != GOT_OBJ_TYPE_BLOB) + return 0; + err = got_object_open(&obj2, repo, &id2); + if (err != NULL || obj2 == NULL) + return 0; + if (obj2->type != GOT_OBJ_TYPE_BLOB) + return 0; + + err = got_object_blob_open(&blob1, repo, obj1, 512); + if (err != NULL) + return 0; + + err = got_object_blob_open(&blob2, repo, obj2, 512); + if (err != NULL) + return 0; + + putchar('\n'); + got_diff_blob(blob1, blob2, repo); + putchar('\n'); + + got_object_blob_close(blob1); + got_object_blob_close(blob2); + got_object_close(obj1); + got_object_close(obj2); got_repo_close(repo); return (err == NULL); } @@ -248,6 +305,7 @@ main(int argc, const char *argv[]) RUN_TEST(repo_read_log(repo_path), "read_log"); RUN_TEST(repo_read_blob(repo_path), "read_blob"); + RUN_TEST(repo_diff_blob(repo_path), "diff_blob"); return failure ? 1 : 0; }