build/contrib/detpax/build | 2 +- build/contrib/detpax/ent.h | 3 ++- build/contrib/detpax/err.h | 2 +- build/contrib/detpax/link.c | 22 ---------------------- build/contrib/detpax/link.h | 7 ++----- build/contrib/detpax/main.c | 469 ++++++++++++++++++++++++----------------------------- build/contrib/detpax/mempool.c | 1 - build/contrib/detpax/path.h | 2 +- build/contrib/detpax/scratch.c | 2 +- build/contrib/detpax/str.c | 68 ++++++++++++++++++++++++----------------------------- build/contrib/detpax/str.h | 32 +++++++++++++++----------------- build/contrib/detpax/tar.c | 4 +++- build/contrib/detpax/test.t | 31 +++++++++++++++++-------------- diff --git a/build/contrib/detpax/build b/build/contrib/detpax/build index b87603bcb89eb0e0d9a99f148ee54873d505e8dda872219cfd27c62a267ce761..c13f717649efdaf6ea2fddd5e48598ca7579ab33a76de22feabc74e41610079a 100755 --- a/build/contrib/detpax/build +++ b/build/contrib/detpax/build @@ -1,6 +1,6 @@ #!/bin/sh -ex -c="err.c link.c main.c mempool.c path.c scratch.c stdout.c str.c tar.c" +c="err.c main.c mempool.c path.c scratch.c stdout.c str.c tar.c" ${CC:-cc} -std=c99 -pedantic -fstrict-aliasing -fwrapv -pipe -fPIC \ -fno-omit-frame-pointer $CFLAGS \ -ffunction-sections -fdata-sections \ diff --git a/build/contrib/detpax/ent.h b/build/contrib/detpax/ent.h index 316a1dba883582ade9a0bbea5daf31c255456b0ec221b6332c6ed3735facd213..8fb8995a430cfb117639b51e396f6aca1f617acbcc9fd8c77618d8f06a300829 100644 --- a/build/contrib/detpax/ent.h +++ b/build/contrib/detpax/ent.h @@ -6,10 +6,11 @@ #include #include "link.h" #include "path.h" +#include "str.h" struct Ent { struct Path path; - struct Path link; + struct Str link; size_t size; struct Inode inode; diff --git a/build/contrib/detpax/err.h b/build/contrib/detpax/err.h index 27f1a7b2baabb002d57198f9d89379bc75daa33d98526b5c741f719df8c5c134..3c84d3388acab0039e3c56e6def96c80c52e6a13ab3f6de9b73e1e804b3de917 100644 --- a/build/contrib/detpax/err.h +++ b/build/contrib/detpax/err.h @@ -7,6 +7,6 @@ void err2(const char *where1, const char *where2); void -memEnough(const char *where, const bool v); +memEnough(const char *where, const bool ok); #endif // DETAX_ERR_H diff --git a/build/contrib/detpax/link.c b/build/contrib/detpax/link.c deleted file mode 100644 index 64f295270715aa93d555150bb14e49656db97e4b41d57a6a21ec7d1d2e20942c..0000000000000000000000000000000000000000 --- a/build/contrib/detpax/link.c +++ /dev/null @@ -1,22 +0,0 @@ -#include "link.h" - -// Used in search of sort functions to arrange according to the inode. -int -byInode(const void *ap, const void *bp) -{ - const struct Link *a = (const struct Link *)ap; - const struct Link *b = (const struct Link *)bp; - if (a->inode.dev < b->inode.dev) { - return -1; - } - if (a->inode.dev > b->inode.dev) { - return 1; - } - if (a->inode.ino < b->inode.ino) { - return -1; - } - if (a->inode.ino > b->inode.ino) { - return 1; - } - return 0; -} diff --git a/build/contrib/detpax/link.h b/build/contrib/detpax/link.h index fd3bf4736efbc032f4535eb468976e7517388985de84d291f5f431b0806a8a81..0ab1b625bafa23dd81060c26576f43061c3b2da31d83d384ebc7f0511638038c 100644 --- a/build/contrib/detpax/link.h +++ b/build/contrib/detpax/link.h @@ -3,7 +3,7 @@ #define DETAX_LINK_H #include -#include "path.h" +#include "str.h" struct Inode { dev_t dev; @@ -12,10 +12,7 @@ }; struct Link { struct Inode inode; - struct Path *path; + struct Str fn; }; - -int -byInode(const void *ap, const void *bp); #endif // DETAX_LINK_H diff --git a/build/contrib/detpax/main.c b/build/contrib/detpax/main.c index 4bfa7792c5af92bcef449b2e7c53366070a6da7c9d93d3ed1fd0475e6c80a4de..aa8c25e376a257115bbabc405a0558cf07a87e684b4a0529a3c3f3889de0a558 100644 --- a/build/contrib/detpax/main.c +++ b/build/contrib/detpax/main.c @@ -33,19 +33,19 @@ #include "stdout.h" #include "str.h" #include "tar.h" -static struct KEKSMemPoolHdr Ents = { - .size = sizeof(struct Ent), - .cap = 1024, - .align = 8}; // memory pool for found entries - -static struct KEKSMemPoolHdr DirEnts = { +static bool DryRun = false; +static struct KEKSMemPoolHdr Names = { .size = sizeof(struct Str), .cap = 64, - .align = 8}; // memory pool for found entries - -static size_t LinksLen = 0; // hardlinks count -static size_t DirsLen = 0; // directories count -static size_t SymlinksLen = 0; // symlinks count + .align = 8}; +static struct KEKSMemPoolHdr Links = { + .size = sizeof(struct Link), + .cap = 64, + .align = 8}; +static size_t Ctr = 0; +static struct StrPool StrPoolNames = {0}; +static struct StrPool StrPoolDirs = {0}; +static struct StrPool StrPoolLinks = {0}; static bool isDots(const char *fn, const size_t fnLen) @@ -59,12 +59,152 @@ } return false; } +static struct Link * +findLink(const dev_t dev, const ino_t ino) +{ + struct KEKSMemPoolIterState iter = KEKSMemPoolIter(&Links); + for (;;) { + struct Link *link = KEKSMemPoolIterNext(&iter); + if (link == NULL) { + break; + } + if ((link->inode.dev == dev) && (link->inode.ino == ino)) { + return link; + } + } + return NULL; +} + +static char * +path2scratch(const struct Path *p, size_t *len) +{ + Scratch[ScratchLen - 1] = 0; + *len = PathMarshal((char *)Scratch, ScratchLen - 1, p); + return (char *)Scratch + ScratchLen - 1 - *len; +} + +static void +printv(const struct Ent *ent) +{ + size_t fnLen = 0; + char *fn = path2scratch(&(ent->path), &fnLen); + char mode[] = "-r--r--r--"; + if (S_ISDIR(ent->mode)) { + mode[0] = 'd'; + } else if (S_ISLNK(ent->mode)) { + mode[0] = 'l'; + } else if (StrLen(&(ent->link)) > 0) { + mode[0] = 'h'; + } + if (ent->mode & S_IWUSR) { + mode[2] = 'w'; + mode[5] = 'w'; + mode[8] = 'w'; + } + if (ent->mode & S_IXUSR) { + mode[3] = 'x'; + mode[6] = 'x'; + mode[9] = 'x'; + } + if (ent->mode & S_ISUID) { + mode[3] = 'S'; + } + if (ent->mode & S_ISGID) { + mode[6] = 'S'; + } + if (ent->mode & S_ISVTX) { + mode[9] = 't'; + } + while (fn[0] == '/') { + fn++; + } + printf("%s\t%zu\t%s", mode, ent->size, fn); + if (StrLen(&(ent->link)) > 0) { + const char *link = StrPtrR(&(ent->link)); + if (!S_ISLNK(ent->mode)) { + while (link[0] == '/') { + link++; + } + } + printf(" -> %s\n", link); + } else { + puts(""); + } +} + +static void +fill(struct Ent *ent, const bool follow) +{ + size_t fnLen = 0; + char *fn = path2scratch(&(ent->path), &fnLen); + struct stat sb = {0}; + int rc = follow ? stat(fn, &sb) : lstat(fn, &sb); + if (rc != 0) { + err2("stat", fn); + } + ent->mode = sb.st_mode; + if (S_ISREG(ent->mode)) { + ent->size = (size_t)sb.st_size; + if (sb.st_nlink > 1) { + struct Link *link = findLink(sb.st_dev, sb.st_ino); + if (link == NULL) { + link = KEKSMemPoolGet(&Links); + memEnough("Links", link != NULL); + link->inode.dev = sb.st_dev; + link->inode.ino = sb.st_ino; + link->fn = StrNewVal(&StrPoolLinks, fn, fnLen); + } else { + ent->link = link->fn; + ent->size = 0; + } + } + } else if (S_ISDIR(ent->mode)) { + } else if (S_ISLNK(ent->mode)) { + ssize_t s = readlink(fn, (char *)Scratch, ScratchLen); + if (s < 0) { + err2("readlink", fn); + } + ent->link = StrNewVal(&StrPoolLinks, (char *)Scratch, (size_t)s); + } else { + fprintf(stderr, "%s: unsupported type, skip\n", fn); + return; + } + Ctr++; + if (DryRun) { + printv(ent); + } else { + TarHdrWrite(Ctr, ent); + if (!S_ISREG(ent->mode) || (ent->size == 0)) { + return; + } + fnLen = 0; + fn = path2scratch(&(ent->path), &fnLen); + int fd = open(fn, O_RDONLY); + if (fd < 0) { + err2("open", fn); + } + for (;;) { + ssize_t n = read(fd, Scratch, ScratchLen); + if (n < 0) { + fnLen = 0; + fn = path2scratch(&(ent->path), &fnLen); + err2("read", fn); + } + if (n == 0) { + break; + } + StdoutWrite("file data", Scratch, (size_t)n); + } + close(fd); + TarHdrPadWrite("file pad", ent->size); + } +} + static void walk(const struct Path *dir) { - Scratch[ScratchLen - 1] = 0; - size_t curLen = PathMarshal((char *)Scratch, ScratchLen - 1, dir); - char *cur = (char *)Scratch + ScratchLen - 1 - curLen; + size_t curLen = 0; + char *cur = path2scratch(dir, &curLen); { char *fn = NULL; size_t fnLen = 0; @@ -95,9 +235,9 @@ fnLen = e->d_namlen; if (isDots(fn, fnLen)) { continue; } - strp = KEKSMemPoolGet(&DirEnts); - memEnough("dirEnt", strp != NULL); - *strp = StrNewVal(fn, fnLen); + strp = KEKSMemPoolGet(&Names); + memEnough("name", strp != NULL); + *strp = StrNewVal(&StrPoolNames, fn, fnLen); } } close(d); @@ -120,87 +260,67 @@ fnLen = strlen(fn); if (isDots(fn, fnLen)) { continue; } - strp = KEKSMemPoolGet(&DirEnts); - memEnough("dirEnt", strp != NULL); - *strp = StrNewVal(fn, fnLen); + strp = KEKSMemPoolGet(&Names); + memEnough("name", strp != NULL); + *strp = StrNewVal(&StrPoolNames, fn, fnLen); } closedir(d); #endif // WITH_GETDENTS } - const size_t pathsLen = DirEnts.len; - struct Str *paths = calloc(pathsLen, sizeof(struct Str)); - memEnough("paths", paths != NULL); + const size_t namesLen = Names.len; + if (namesLen == 0) { + return; + } + struct Str *names = calloc(namesLen, sizeof(struct Str)); + memEnough("names", names != NULL); { struct Str *strp = NULL; - struct KEKSMemPoolIterState iter = KEKSMemPoolIter(&DirEnts); + struct KEKSMemPoolIterState iter = KEKSMemPoolIter(&Names); size_t i = 0; for (;;) { strp = KEKSMemPoolIterNext(&iter); if (strp == NULL) { break; } - paths[i] = *strp; + names[i] = *strp; i++; } - assert(i == pathsLen); + assert(i == namesLen); } - qsort(paths, pathsLen, sizeof(struct Str), StrCmpForSort); - KEKSMemPoolClear(&DirEnts); - { - struct stat sb = {0}; - int rc = -1; - struct Ent *ent = NULL; - struct Path path = {0}; - for (size_t i = 0; i < pathsLen; i++) { - path.fn = paths[i]; - path.dir = dir; - curLen = PathMarshal((char *)Scratch, ScratchLen - 1, &path); - cur = (char *)Scratch + ScratchLen - 1 - curLen; - rc = lstat(cur, &sb); - if (rc != 0) { - err2("stat", cur); - } - if (!(S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode) || S_ISLNK(sb.st_mode))) { - fprintf(stderr, "%s: unsupported type, skip\n", cur); - continue; - } - ent = KEKSMemPoolGet(&Ents); - memEnough("ent", ent != NULL); - ent->path = path; - ent->mode = sb.st_mode; - if (S_ISREG(sb.st_mode)) { - ent->size = (size_t)sb.st_size; - if (sb.st_nlink > 1) { - ent->inode.dev = sb.st_dev; - ent->inode.ino = sb.st_ino; - LinksLen++; - } - } else if (S_ISDIR(sb.st_mode)) { - DirsLen++; - walk(&(ent->path)); - } else if (S_ISLNK(sb.st_mode)) { - SymlinksLen++; - ssize_t s = readlink(cur, (char *)Scratch, ScratchLen); - if (s < 0) { - err2("readlink", cur); - } - ent->link.fn = StrNewVal((char *)Scratch, (size_t)s); - } else { - assert(false); - } + qsort(names, namesLen, sizeof(struct Str), StrCmpForSort); + KEKSMemPoolClear(&Names); + for (size_t i = 0; i < namesLen; i++) { + struct Ent ent = {0}; + ent.path.fn = names[i]; + ent.path.dir = dir; + fill(&ent, false); + if (S_ISDIR(ent.mode)) { + names[i] = + StrNewVal(&StrPoolDirs, StrPtrR(&(names[i])), StrLen(&(names[i]))); + } else { + memset(&(names[i]), 0, sizeof(struct Str)); + } + } + StrPoolClear(&StrPoolNames); + for (size_t i = 0; i < namesLen; i++) { + if (StrLen(&(names[i])) == 0) { + continue; } - free(paths); + struct Ent ent = {0}; + ent.path.fn = names[i]; + ent.path.dir = dir; + walk(&(ent.path)); } + free(names); } static void usage() { fputs( - "Usage: detpax [-n] [-s] [-p] {FILE|DIR} [...] >tar\n" + "Usage: detpax [-n] [-p] {FILE|DIR} [...] >tar\n" "If FILE is a symlink, then it will be followed\n" "-n is a dry-run, that prints what fill be archived.\n" - "-s show some internal statistics.\n" "-p does not add tar final padding.\n", stderr); exit(1); @@ -214,16 +334,16 @@ usage(); } Scratch = calloc(1, ScratchLen); memEnough("Scratch", Scratch != NULL); - KEKSMemPoolInit(&Ents); - memEnough("Ents", Ents.last != NULL); - KEKSMemPoolInit(&DirEnts); - memEnough("DirEnts", DirEnts.last != NULL); - StrsPoolInit(); - bool dryRun = false; - bool showStats = false; + KEKSMemPoolInit(&Names); + memEnough("Names", Names.last != NULL); + KEKSMemPoolInit(&Links); + memEnough("Links", Links.last != NULL); + StrPoolInit(&StrPoolNames); + StrPoolInit(&StrPoolDirs); + StrPoolInit(&StrPoolLinks); bool noPad = false; for (int c = -1;;) { - c = getopt(argc, argv, "hnps"); + c = getopt(argc, argv, "hnp"); if (c == -1) { break; } @@ -232,201 +352,40 @@ case 'h': usage(); break; case 'n': - dryRun = true; + DryRun = true; break; case 'p': noPad = true; - break; - case 's': - showStats = true; break; default: break; } } for (int opti = optind; opti < argc; opti++) { - DirsLen = 0; - SymlinksLen = 0; - StrStatsAlloc = 0; - StrStatsEmbed = 0; - StrStatsCmp = 0; - StrStatsCmpLens = 0; - StrStatsCmpEmbeds = 0; - StrStatsCmpPrefix = 0; - LinksLen = 0; - struct stat sb = {0}; char *fn = argv[opti]; size_t fnLen = strlen(fn); while (fn[fnLen - 1] == '/') { fnLen--; } - int rc = stat(fn, &sb); - if (rc != 0) { - err2("stat", fn); - } - struct Ent *ent = KEKSMemPoolGet(&Ents); - memEnough("ent", ent != NULL); - ent->path.fn = StrNewVal(fn, fnLen); - ent->mode = sb.st_mode; - if (S_ISDIR(ent->mode)) { - walk(&(ent->path)); - } else if (S_ISREG(sb.st_mode)) { - ent->size = (size_t)sb.st_size; - if (sb.st_nlink > 1) { - ent->inode.dev = sb.st_dev; - ent->inode.ino = sb.st_ino; - } - LinksLen++; + struct Ent ent = {0}; + ent.path.fn = StrNewVal(&StrPoolDirs, fn, fnLen); + fill(&ent, true); + if (S_ISDIR(ent.mode)) { + walk(&(ent.path)); + } else if (S_ISREG(ent.mode)) { } else { err2("bad file type", fn); } - struct Link *links = calloc(LinksLen, sizeof(struct Link)); - memEnough("links", links != NULL); - LinksLen = 0; - struct KEKSMemPoolIterState iter = KEKSMemPoolIter(&Ents); - for (;;) { - ent = KEKSMemPoolIterNext(&iter); - if (ent == NULL) { - break; - } - if (S_ISREG(ent->mode) && (ent->inode.dev != 0) && (ent->inode.ino != 0)) { - links[LinksLen].inode.dev = ent->inode.dev; - links[LinksLen].inode.ino = ent->inode.ino; - LinksLen++; - } - } - qsort(links, LinksLen, sizeof(struct Link), byInode); - struct Link linkKey = {0}; - struct Link *link = NULL; - int fd = -1; - ssize_t n = -1; - iter = KEKSMemPoolIter(&Ents); - for (size_t i = 0;; i++) { - ent = KEKSMemPoolIterNext(&iter); - if (ent == NULL) { - break; - } - if (S_ISREG(ent->mode) && (ent->inode.dev != 0) && (ent->inode.ino != 0)) { - linkKey.inode.dev = ent->inode.dev; - linkKey.inode.ino = ent->inode.ino; - link = bsearch(&linkKey, links, LinksLen, sizeof(struct Link), byInode); - if (link->path == NULL) { - link->path = &(ent->path); - } else { - ent->link = *(link->path); - ent->size = 0; - } - } - fnLen = PathMarshal((char *)Scratch, ScratchLen - 1, &(ent->path)); - fn = (char *)Scratch + ScratchLen - 1 - fnLen; - if (dryRun) { - char mode[] = "-r--r--r--"; - if (S_ISDIR(ent->mode)) { - mode[0] = 'd'; - } else if (S_ISLNK(ent->mode)) { - mode[0] = 'l'; - } else if (StrLen(&(ent->link.fn)) > 0) { - mode[0] = 'h'; - } - if (ent->mode & S_IWUSR) { - mode[2] = 'w'; - mode[5] = 'w'; - mode[8] = 'w'; - } - if (ent->mode & S_IXUSR) { - mode[3] = 'x'; - mode[6] = 'x'; - mode[9] = 'x'; - } - if (ent->mode & S_ISUID) { - mode[3] = 'S'; - } - if (ent->mode & S_ISGID) { - mode[6] = 'S'; - } - if (ent->mode & S_ISVTX) { - mode[9] = 't'; - } - while (fn[0] == '/') { - fn++; - } - printf("%s\t%zu\t%s", mode, ent->size, fn); - if (StrLen(&(ent->link.fn)) > 0) { - fnLen = PathMarshal((char *)Scratch, ScratchLen - 1, &(ent->link)); - fn = (char *)Scratch + ScratchLen - 1 - fnLen; - if (!S_ISLNK(ent->mode)) { - while (fn[0] == '/') { - fn++; - } - } - printf(" -> %s\n", fn); - } else { - puts(""); - } - continue; - } - TarHdrWrite(i, ent); - if (!S_ISREG(ent->mode)) { - continue; - } - if (ent->size == 0) { - continue; - } - fd = open(fn, O_RDONLY); - if (fd < 0) { - err2("open", fn); - } - for (;;) { - n = read(fd, Scratch, ScratchLen); - if (n < 0) { - fnLen = PathMarshal((char *)Scratch, ScratchLen - 1, &(ent->path)); - fn = (char *)Scratch + ScratchLen - fnLen; - err2("read", fn); - } - if (n == 0) { - break; - } - StdoutWrite("file data", Scratch, (size_t)n); - } - close(fd); - TarHdrPadWrite("file pad", ent->size); - } - if (showStats) { - fprintf( - stderr, - "ents chunks/all/dirs/links/symlinks: %zu / %zu / %zu / %zu / %zu\n", - Ents.chunks, - Ents.len, - DirsLen, - LinksLen, - SymlinksLen); - fprintf( - stderr, - "str chunks/allocs/embeds: %zu / %zu / %zu\n", - StrsPool.chunks, - StrStatsAlloc, - StrStatsEmbed); - fprintf( - stderr, - "str cmp all/v/lens/embeds/prefix: %zu / %zu / %zu / %zu\n", - StrStatsCmp, - StrStatsCmpLens, - StrStatsCmpEmbeds, - StrStatsCmpPrefix); - } - free(links); - KEKSMemPoolClear(&Ents); - KEKSMemPoolClear(&StrsPool); } - - if (!dryRun && !noPad) { + if (!DryRun && !noPad) { memset(Scratch, 0, sizeof(struct TarHdr) * 2); StdoutWrite("tar pad", Scratch, sizeof(struct TarHdr) * 2); } - - KEKSMemPoolFree(&Ents); - KEKSMemPoolFree(&DirEnts); - KEKSMemPoolFree(&StrsPool); + KEKSMemPoolFree(&Links); + KEKSMemPoolFree(&Names); + KEKSMemPoolFree(&(StrPoolLinks.pool)); + KEKSMemPoolFree(&(StrPoolDirs.pool)); + KEKSMemPoolFree(&(StrPoolNames.pool)); free(Scratch); return 0; } diff --git a/build/contrib/detpax/mempool.c b/build/contrib/detpax/mempool.c index 6b0761315189d35ff220289fea3bece7947fb98eba49da798e5d59bc4c8eac81..dc3bea3e1c043a8e19db67d18886577354bb89c1f57cfd6bcb079f65ff647c2b 100644 --- a/build/contrib/detpax/mempool.c +++ b/build/contrib/detpax/mempool.c @@ -90,7 +90,6 @@ pool->size = ceilTo(pool->size, pool->align); pool->cap = ceilTo(pool->cap, 64); pool->first = keksMemPoolChunkNew(pool); pool->last = pool->first; - return; } void * diff --git a/build/contrib/detpax/path.h b/build/contrib/detpax/path.h index dd2eb88d718828c5a07b8130acf3a750a6243215ad7b8cae445b2c396509758f..ee7bc16830c226d70da48b089b932807c76b568e6969d77f7dee4b79c1d15362 100644 --- a/build/contrib/detpax/path.h +++ b/build/contrib/detpax/path.h @@ -12,6 +12,6 @@ }; // Place constructed path in the dst size_t -PathMarshal(char *dst, const size_t cap, const struct Path *tail); +PathMarshal(char *dst, const size_t cap, const struct Path *p); #endif // DETAX_PATH_H diff --git a/build/contrib/detpax/scratch.c b/build/contrib/detpax/scratch.c index e48eed1726e0856e6c0782f7dfa447af8533bec1c5d3b5db098bf296815f756c..9aefbc37405a5cee1570979b14e32062702d40af141a5eca085b7413d981fbde 100644 --- a/build/contrib/detpax/scratch.c +++ b/build/contrib/detpax/scratch.c @@ -3,4 +3,4 @@ #include "scratch.h" unsigned char *Scratch = NULL; -const size_t ScratchLen = 128 * 1024; +const size_t ScratchLen = (size_t)128 * 1024; diff --git a/build/contrib/detpax/str.c b/build/contrib/detpax/str.c index 3c1324c8d977b92c9824c7f17e5ede0de6f6751ccab0cac95606e6f0ccc57c80..1b80bdb988302a9b128c59267d47341351201e753c19928309011df077976cd6 100644 --- a/build/contrib/detpax/str.c +++ b/build/contrib/detpax/str.c @@ -20,27 +20,6 @@ #include "err.h" #include "mempool.h" #include "str.h" -size_t StrStatsAlloc = 0; -size_t StrStatsEmbed = 0; -size_t StrStatsCmp = 0; -size_t StrStatsCmpLens = 0; -size_t StrStatsCmpEmbeds = 0; -size_t StrStatsCmpPrefix = 0; - -struct KEKSMemPoolHdr StrsPool = {.size = StrMaxLen, .cap = 1, .align = 8}; -char *StrsChunk = NULL; -size_t StrsOff = 0; - -void -StrsPoolInit() -{ - KEKSMemPoolInit(&StrsPool); - memEnough("StrsPool", StrsPool.last != NULL); - StrsChunk = KEKSMemPoolGet(&StrsPool); - memEnough("StrsChunk", StrsChunk != NULL); - StrsOff = 0; -} - size_t StrLen(const struct Str *str) { @@ -78,24 +57,19 @@ int StrCmp(const struct Str *a, const struct Str *b) { - StrStatsCmp++; size_t aLen = StrLen(a); size_t bLen = StrLen(b); if (aLen < bLen) { - StrStatsCmpLens++; return -1; } if (aLen > bLen) { - StrStatsCmpLens++; return 1; } if (StrIsEmbed(a) && StrIsEmbed(b)) { - StrStatsCmpEmbeds++; return memcmp(StrPtrR(a), StrPtrR(b), aLen); } int rc = memcmp(a->v + 2, b->v + 2, (aLen > StrPrefixLen) ? StrPrefixLen : aLen); if (rc != 0) { - StrStatsCmpPrefix++; return rc; } return memcmp(StrPtrR(a), StrPtrR(b), aLen); @@ -120,33 +94,53 @@ } memcpy(str->v + 2, StrPtrW(str), len); } +void +StrPoolInit(struct StrPool *pool) +{ + pool->pool.size = StrMaxLen; + pool->pool.cap = 1; + pool->pool.align = 8; + KEKSMemPoolInit(&(pool->pool)); + memEnough("StrPool", pool->pool.last != NULL); + pool->chunk = KEKSMemPoolGet(&(pool->pool)); + memEnough("StrChunk", pool->chunk != NULL); + pool->off = 0; +} + +void +StrPoolClear(struct StrPool *pool) +{ + KEKSMemPoolClear(&(pool->pool)); + pool->chunk = KEKSMemPoolGet(&(pool->pool)); + pool->off = 0; +} + struct Str -StrNew(const size_t len) +StrNew(struct StrPool *pool, const size_t len) { + assert(pool != NULL); assert(len < StrMaxLen); - StrStatsAlloc++; struct Str str = {0}; str.v[0] = (unsigned char)(len >> 8); str.v[1] = (unsigned char)(len & 0xFF); if (len <= StrEmbedLen) { - StrStatsEmbed++; return str; } - if ((StrsOff + len) > StrMaxLen) { - StrsChunk = KEKSMemPoolGet(&StrsPool); - memEnough("StrsChunk", StrsChunk != NULL); - StrsOff = 0; + if ((pool->off + len) > StrMaxLen) { + pool->chunk = KEKSMemPoolGet(&(pool->pool)); + memEnough("StrsChunk", pool->chunk != NULL); + pool->off = 0; } - const char *p = StrsChunk + StrsOff; - StrsOff += len; + const char *p = pool->chunk + pool->off; + pool->off += len; memcpy(str.v + 8, &p, 8); return str; } struct Str -StrNewVal(const char *v, const size_t len) +StrNewVal(struct StrPool *pool, const char *v, const size_t len) { - struct Str s = StrNew(len); + struct Str s = StrNew(pool, len); memcpy(StrPtrW(&s), v, len); StrPrefixUpdate(&s); return s; diff --git a/build/contrib/detpax/str.h b/build/contrib/detpax/str.h index d37ee9ed6032dae39e735763748949ae8629e26335df9ba8e0cd3a29cf938747..d0351bb5a1223339b9028fee9b876a4acbf44a40db1accedef58c6a7a69a1176 100644 --- a/build/contrib/detpax/str.h +++ b/build/contrib/detpax/str.h @@ -12,21 +12,6 @@ StrEmbedLen = 16 - 2, // length of the embedded space StrPrefixLen = 16 - 2 - 8, // length of the prefix space }; -extern size_t StrStatsAlloc; // how many StrNew was called -extern size_t StrStatsEmbed; // how many embedded strings were created -extern size_t StrStatsCmp; // how many times StrCmp was called -extern size_t StrStatsCmpLens; // how many times length was different -extern size_t StrStatsCmpEmbeds; // how many times embedded strings were compared -extern size_t StrStatsCmpPrefix; // how many times we made only on prefix comparison - -extern struct KEKSMemPoolHdr StrsPool; // pool of allocated string -extern char *StrsChunk; // current chunk where strings are allocated -extern size_t StrsOff; // offset of the newly created string - -// Initialise strings pool -void -StrsPoolInit(void); - // This is "German string". Its first 2 bytes hold big-endian length of // the string. If it is StrEmbedLen short enough, then remaining space // is used for the string itself. Otherwise StrPrefixLen bytes are used @@ -60,13 +45,26 @@ // Update prefix contents void StrPrefixUpdate(struct Str *str); +struct StrPool { + struct KEKSMemPoolHdr pool; // pool of allocated string + char *chunk; // current chunk where strings are allocated + size_t off; // offset of the newly created string +}; + +// Initialise strings pool +void +StrPoolInit(struct StrPool *); + +void +StrPoolClear(struct StrPool *); + // Create a new string. You are expected to call StrPtrW to get the // writable buffer you should fill with the desired data. Then call // StrPrefixUpdate if you are going to use it with StrCmp. struct Str -StrNew(const size_t len); +StrNew(struct StrPool *pool, const size_t len); struct Str -StrNewVal(const char *v, const size_t len); +StrNewVal(struct StrPool *pool, const char *v, const size_t len); #endif // DETAX_STR_H diff --git a/build/contrib/detpax/tar.c b/build/contrib/detpax/tar.c index 6c3f20717d21d860fba588891d55cecebcbf482994e4b1d4100fed45315f7def..9a383664418ad3d34141da35d0b6734be982cef8d0e9f3eab2ab0e81a8d33bbe 100644 --- a/build/contrib/detpax/tar.c +++ b/build/contrib/detpax/tar.c @@ -23,6 +23,7 @@ #include "ent.h" #include "path.h" #include "scratch.h" #include "stdout.h" +#include "str.h" #include "tar.h" static const size_t TarSizeMax = 8589934591; @@ -165,8 +166,9 @@ size_t pathLen = PathMarshal(path, ScratchLen - 1, &(ent->path)); path = (char *)Scratch + ScratchLen - 1 - pathLen; char *link = (char *)Scratch; link[ScratchLen - 1 - pathLen - 1] = 0; - size_t linkLen = PathMarshal(link, ScratchLen - 1 - pathLen - 1, &(ent->link)); + size_t linkLen = StrLen(&(ent->link)); link = (char *)Scratch + ScratchLen - 1 - pathLen - 1 - linkLen; + memcpy(link, StrPtrR(&(ent->link)), linkLen); while (path[0] == '/') { path++; pathLen--; diff --git a/build/contrib/detpax/test.t b/build/contrib/detpax/test.t index 48af1d369ed230a6370d6086d46290bd6c9711205a7ba3dd3d948a7a3adf3b2b..60c14b0f67e4f83308a1154429092d828f2751fcd1ead8e5c90c59c83857f5a8 100755 --- a/build/contrib/detpax/test.t +++ b/build/contrib/detpax/test.t @@ -53,19 +53,15 @@ truncate -s $(( 10 * 1024 * 1024 * 1024 )) too-big-to-fit-and-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-long cd .. echo world >just-a-file-longer-than-dir -detpax just-a-file-longer-than-dir prefix/// | list prefix >their +ln -s prefix/rw root-symlink +detpax root-symlink just-a-file-longer-than-dir prefix/// | list prefix >their cat >our < unexistent -hrw-rw-rw- prefix/dir/hw-linked link to prefix/dir/hw -lrwxrwxrwx prefix/dir/hw-symlinked -> hw -rw-rwSrw- prefix/guid -rwSrw-rw- prefix/suid -rwSrwSrw- prefix/sguid @@ -77,22 +73,23 @@ -rw-rw-rw- prefix/too-big-to-fit -rw-rw-rw- prefix/\\320\\272\\320\\270\\321\\200\\320\\270\\320\\273\\320\\273\\320\\270\\321\\206\\320\\260 -rw-rw-rw- prefix/very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very long file -rw-rw-rw- prefix/too-big-to-fit-and-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-long +-rw-rw-rw- prefix/dir/hw +drwxrwxrwx prefix/dir/subdir +lrwxrwxrwx prefix/dir/symlink -> unexistent +hrw-rw-rw- prefix/dir/hw-linked link to prefix/dir/hw +lrwxrwxrwx prefix/dir/hw-symlinked -> hw +hrw-rw-rw- prefix/dir/subdir/hw-linked link to prefix/dir/hw EOF test_expect_success "tar tf" "test_cmp our their" -detpax -n just-a-file-longer-than-dir prefix/// >their +detpax -n root-symlink just-a-file-longer-than-dir prefix/// >their cat >our < prefix/dir/hw -lrwxrwxrwx 0 prefix/dir/symlink -> unexistent -hrw-rw-rw- 0 prefix/dir/hw-linked -> prefix/dir/hw -lrwxrwxrwx 0 prefix/dir/hw-symlinked -> hw -rw-rwSrw- 0 prefix/guid -rwSrw-rw- 0 prefix/suid -rwSrwSrw- 0 prefix/sguid @@ -104,6 +101,12 @@ -rw-rw-rw- 10737418240 prefix/too-big-to-fit -rw-rw-rw- 0 prefix/кириллица -rw-rw-rw- 123 prefix/very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very long file -rw-rw-rw- 10737418240 prefix/too-big-to-fit-and-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-very-long +-rw-rw-rw- 6 prefix/dir/hw +drwxrwxrwx 0 prefix/dir/subdir +lrwxrwxrwx 0 prefix/dir/symlink -> unexistent +hrw-rw-rw- 0 prefix/dir/hw-linked -> prefix/dir/hw +lrwxrwxrwx 0 prefix/dir/hw-symlinked -> hw +hrw-rw-rw- 0 prefix/dir/subdir/hw-linked -> prefix/dir/hw EOF test_expect_success "-n" "test_cmp our their"