From 43c39bb6b44cc96ac012c259e30c1466cfb23b48 Mon Sep 17 00:00:00 2001 From: midipix Date: Thu, 30 May 2024 03:52:14 +0000 Subject: core api: renamed tpax_archive_append() as tpax_archive_enqueue(). --- include/tpax/tpax.h | 2 +- project/common.mk | 2 +- src/driver/tpax_amain.c | 2 +- src/logic/tpax_archive_append.c | 475 --------------------------------------- src/logic/tpax_archive_enqueue.c | 475 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 478 insertions(+), 478 deletions(-) delete mode 100644 src/logic/tpax_archive_append.c create mode 100644 src/logic/tpax_archive_enqueue.c diff --git a/include/tpax/tpax.h b/include/tpax/tpax.h index 172c7ae..eb106d6 100644 --- a/include/tpax/tpax.h +++ b/include/tpax/tpax.h @@ -152,7 +152,7 @@ tpax_api int tpax_lib_get_driver_fdctx (const struct tpax_driver_ctx *, str tpax_api int tpax_lib_set_driver_fdctx (struct tpax_driver_ctx *, const struct tpax_fd_ctx *); /* core api */ -tpax_api int tpax_archive_append (const struct tpax_driver_ctx *, const struct tpax_unit_ctx *); +tpax_api int tpax_archive_enqueue (const struct tpax_driver_ctx *, const struct tpax_unit_ctx *); tpax_api int tpax_archive_write (const struct tpax_driver_ctx *); diff --git a/project/common.mk b/project/common.mk index 5ae4ea2..c934519 100644 --- a/project/common.mk +++ b/project/common.mk @@ -4,7 +4,7 @@ API_SRCS = \ src/driver/tpax_unit_ctx.c \ src/io/tpax_create_memory_snapshot.c \ src/io/tpax_create_tmpfs_snapshot.c \ - src/logic/tpax_archive_append.c \ + src/logic/tpax_archive_enqueue.c \ src/logic/tpax_archive_reset.c \ src/logic/tpax_archive_write.c \ src/logic/tpax_queue_vector.c \ diff --git a/src/driver/tpax_amain.c b/src/driver/tpax_amain.c index 61f53d1..429633e 100644 --- a/src/driver/tpax_amain.c +++ b/src/driver/tpax_amain.c @@ -54,7 +54,7 @@ static void tpax_perform_unit_actions( struct tpax_unit_ctx * uctx) { if (dctx->cctx->drvflags & TPAX_DRIVER_EXEC_MODE_WRITE) - tpax_archive_append(dctx,uctx); + tpax_archive_enqueue(dctx,uctx); } static void tpax_archive_write_and_seal( diff --git a/src/logic/tpax_archive_append.c b/src/logic/tpax_archive_append.c deleted file mode 100644 index 444ae7f..0000000 --- a/src/logic/tpax_archive_append.c +++ /dev/null @@ -1,475 +0,0 @@ -/**************************************************************/ -/* tpax: a topological pax implementation */ -/* Copyright (C) 2020--2024 SysDeer Technologies, LLC */ -/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */ -/**************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "tpax_driver_impl.h" -#include "tpax_getdents_impl.h" -#include "tpax_tmpfile_impl.h" -#include "tpax_errinfo_impl.h" - -static char * tpax_append_prefix_item( - const struct tpax_driver_ctx * dctx, - const char * prefix) -{ - struct tpax_driver_ctx_impl * ictx; - char ** prefv; - char ** psrc; - char ** pdst; - off_t elements; - char * pitem; - - ictx = tpax_get_driver_ictx(dctx); - - for (psrc=ictx->prefixv; *psrc; psrc++) - if (!strcmp(*psrc,prefix)) - return *psrc; - - if (ictx->prefixp == ictx->prefcap) { - elements = ictx->prefcap - ictx->prefixv; - elements += 256; - - if (!(prefv = calloc(elements,sizeof(char *)))) - return 0; - - for (psrc=ictx->prefixv,pdst=prefv; *psrc; psrc++,pdst++) - *pdst = *psrc; - - if (ictx->prefixv != ictx->prefptr) - free(ictx->prefixv); - - ictx->prefixv = prefv; - ictx->prefixp = pdst; - ictx->prefcap = &prefv[--elements]; - } - - if (!(pitem = strdup(prefix))) - return 0; - - *ictx->prefixp++ = pitem; - - return pitem; -} - -static char * tpax_append_prefix_item_from_path( - const struct tpax_driver_ctx * dctx, - const char * path, - const char * mark) -{ - off_t nbytes; - char pathbuf[PATH_MAX]; - - if ((nbytes = (mark - path)) >= (PATH_MAX - 1)) - return 0; - - memcpy(pathbuf,path,nbytes); - pathbuf[nbytes++] = '/'; - pathbuf[nbytes] = '\0'; - - return tpax_append_prefix_item(dctx,pathbuf); -} - -static struct tpax_dirent_buffer * tpax_dirent_buf_first_alloc( - const struct tpax_driver_ctx * dctx) -{ - void * addr; - struct tpax_driver_ctx_impl * ictx; - - addr = (struct tpax_dirent_buffer *)mmap( - 0,TPAX_DIRENT_BUFLEN, - PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANONYMOUS, - -1,0); - - if (addr == MAP_FAILED) - return 0; - - ictx = tpax_get_driver_ictx(dctx); - ictx->dirents = (struct tpax_dirent_buffer *)addr; - ictx->dirents->cdent = ictx->dirents->dbuf; - - ictx->dirents->size = TPAX_DIRENT_BUFLEN; - ictx->dirents->next = 0; - - ictx->dirents->nfree = TPAX_DIRENT_BUFLEN; - ictx->dirents->nfree -= offsetof(struct tpax_dirent_buffer,dbuf); - - return ictx->dirents; -} - -static struct tpax_dirent_buffer * tpax_dirent_buf_next_alloc( - struct tpax_dirent_buffer * current) -{ - void * addr; - - addr = (struct tpax_dirent_buffer *)mmap( - 0,TPAX_DIRENT_BUFLEN, - PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANONYMOUS, - -1,0); - - if (addr == MAP_FAILED) - return 0; - - current->next = (struct tpax_dirent_buffer *)addr; - current->next->cdent = current->next->dbuf; - - current->next->size = TPAX_DIRENT_BUFLEN; - current->next->next = 0; - - current->next->nfree = TPAX_DIRENT_BUFLEN; - current->next->nfree -= offsetof(struct tpax_dirent_buffer,dbuf); - - return current->next; -} - -static int tpax_archive_append_ret( - int ret, - struct tpax_unit_ctx * unit) -{ - if (unit) - tpax_lib_free_unit_ctx(unit); - - return ret; -} - -static int tpax_archive_append_queue_item( - const struct tpax_driver_ctx * dctx, - const struct dirent * dirent, - const struct tpax_dirent * parent, - const char * prefix, - int depth, - int flags, - int fdat, - bool * fkeep) -{ - struct tpax_dirent_buffer * dentbuf; - struct tpax_dirent * cdent; - const char * src; - char * dst; - char * cap; - size_t needed; - - if (!(dentbuf = tpax_get_driver_dirents(dctx))) - if (!(dentbuf = tpax_dirent_buf_first_alloc(dctx))) - return tpax_archive_append_ret( - TPAX_SYSTEM_ERROR(dctx), - 0); - - needed = dirent->d_reclen; - needed += offsetof(struct tpax_dirent,dirent); - needed += 0x7; - needed |= 0x7; - needed ^= 0x7; - - for (; dentbuf->next && (dentbuf->nfree < needed); ) - dentbuf = dentbuf->next; - - if (dentbuf->nfree < needed) - if (!(dentbuf = tpax_dirent_buf_next_alloc(dentbuf))) - return tpax_archive_append_ret( - TPAX_SYSTEM_ERROR(dctx), - 0); - - *fkeep = true; - cdent = dentbuf->cdent; - - cdent->fdat = fdat; - cdent->depth = depth; - cdent->flags = flags; - cdent->nsize = needed; - cdent->parent = parent; - cdent->prefix = prefix; - - memset(&cdent->dirent,0,offsetof(struct dirent,d_name)); - - cdent->dirent.d_ino = dirent->d_ino; - cdent->dirent.d_type = dirent->d_type; - cdent->dirent.d_reclen = dirent->d_reclen; - - src = dirent->d_name; - dst = cdent->dirent.d_name; - - cap = dst - offsetof(struct dirent,d_name); - cap -= offsetof(struct tpax_dirent,dirent); - cap += needed; - - for (; *src; ) - *dst++ = *src++; - - for (; dstcdent = (struct tpax_dirent *)cap; - dentbuf->nfree -= needed; - - tpax_set_driver_dirmark(dctx,cdent); - - return 0; -} - -static int tpax_archive_append_dir_entries( - const struct tpax_driver_ctx * dctx, - struct tpax_dirent * dent) -{ - int fd; - int fdat; - int depth; - bool fkeep; - long nbytes; - struct dirent * dirent; - struct dirent * dirents; - struct tpax_unit_ctx * uctx; - struct stat st; - uintptr_t addr; - - /* init */ - fdat = dent->fdat; - depth = dent->depth; - - /* uctx on the fly */ - if (tpax_lib_get_unit_ctx( - dctx,fdat, - dent->dirent.d_name, - &uctx) < 0) - return TPAX_NESTED_ERROR(dctx); - - /* verify that recursion item is still a directory */ - if (!S_ISDIR(uctx->st->st_mode)) - return tpax_archive_append_ret( - TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR), - uctx); - - /* obtain buffer for file-system directory entries */ - dirents = tpax_get_driver_getdents_buffer(dctx); - dirent = dirents; - fkeep = false; - nbytes = 0; - depth++; - - /* open directory and obtain first directory entries */ - if ((fd = openat(fdat,dent->dirent.d_name,O_RDONLY|O_DIRECTORY|O_CLOEXEC,0)) < 0) - return tpax_archive_append_ret( - TPAX_SYSTEM_ERROR(dctx), - uctx); - - nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN); - - while ((nbytes == -EINTR) || ((nbytes < 0) && (errno == EINTR))) - nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN); - - if (nbytes < 0) - return tpax_archive_append_ret( - TPAX_SYSTEM_ERROR(dctx), - uctx); - - /* iterate */ - for (; nbytes>0; ) { - if (!strcmp(dirent->d_name,".")) { - (void)0; - - } else if (!strcmp(dirent->d_name,"..")) { - (void)0; - - } else { - if (dirent->d_type == DT_UNKNOWN) { - if (fstatat(fd,dirent->d_name,&st,AT_SYMLINK_NOFOLLOW)) - return tpax_archive_append_ret( - TPAX_SYSTEM_ERROR(dctx), - uctx); - - if (S_ISDIR(st.st_mode)) { - dirent->d_type = DT_DIR; - } - } - - if (tpax_archive_append_queue_item( - dctx,dirent, - dent,0,depth, - TPAX_ITEM_IMPLICIT, - fd,&fkeep) < 0) - return tpax_archive_append_ret( - TPAX_NESTED_ERROR(dctx), - uctx); - } - - addr = (uintptr_t)dirent; - addr += dirent->d_reclen; - nbytes -= dirent->d_reclen; - dirent = (struct dirent *)addr; - - if (nbytes == 0) { - nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN); - - while ((nbytes == -EINTR) || ((nbytes < 0) && (errno == EINTR))) - nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN); - - if (nbytes < 0) - tpax_archive_append_ret( - TPAX_SYSTEM_ERROR(dctx), - uctx); - - dirent = dirents; - } - } - - /* all done */ - return tpax_archive_append_ret( - fkeep ? 0 : close(fd), - uctx); -} - -static const char * tpax_path_prefix_mark(const char * path) -{ - const char * src; - char * mark; - char pathbuf[PATH_MAX]; - - src = path; - mark = pathbuf; - - for (; *src; ) - *mark++ = *src++; - - for (--mark; (*mark == '/'); mark--) - (void)0; - - *++mark = '\0'; - - for (; (mark > pathbuf) && (mark[-1] != '/'); ) - mark--; - - return (mark <= pathbuf) ? 0 : &path[--mark-pathbuf]; -} - -static int tpax_dirent_init_from_uctx( - const struct stat * st, - const char * basename, - struct dirent * dirent) -{ - /* st_mode to d_type translation */ - if (S_ISREG(st->st_mode)) - dirent->d_type = DT_REG; - else if (S_ISLNK(st->st_mode)) - dirent->d_type = DT_LNK; - else if (S_ISDIR(st->st_mode)) - dirent->d_type = DT_DIR; - else if (S_ISCHR(st->st_mode)) - dirent->d_type = DT_CHR; - else if (S_ISBLK(st->st_mode)) - dirent->d_type = DT_CHR; - else if (S_ISFIFO(st->st_mode)) - dirent->d_type = DT_CHR; - else - return -1; - - /* d_off, d_ino */ - dirent->d_off = 0; - dirent->d_ino = st->st_ino; - - /* d_reclen */ - dirent->d_reclen = offsetof(struct dirent,d_name); - dirent->d_reclen += strlen(basename) + 1; - - dirent->d_reclen += 0x1; - dirent->d_reclen |= 0x1; - dirent->d_reclen ^= 0x1; - - /* d_name */ - strcpy(dirent->d_name,basename); - - return 0; -} - -int tpax_archive_append( - const struct tpax_driver_ctx * dctx, - const struct tpax_unit_ctx * uctx) -{ - int fdat; - uintptr_t addr; - const char * name; - const char * mark; - const char * prefix; - bool fkeep; - struct tpax_dirent_buffer * dentbuf; - struct tpax_dirent * cdent; - struct tpax_dirent * cnext; - struct dirent * dirent; - char entbuf[PATH_MAX + sizeof(struct dirent)]; - - /* init */ - fdat = tpax_driver_fdcwd(dctx); - dirent = (struct dirent *)entbuf; - prefix = 0; - - /* split path to prefix + basename */ - if ((mark = tpax_path_prefix_mark(*uctx->path))) - if (!(prefix = tpax_append_prefix_item_from_path( - dctx,*uctx->path,mark))) - return tpax_archive_append_ret( - TPAX_BUFFER_ERROR(dctx), - 0); - - name = mark ? ++mark : *uctx->path; - - if (prefix) - if ((fdat = openat(fdat,prefix,O_RDONLY|O_DIRECTORY|O_CLOEXEC,0)) < 0) - return tpax_archive_append_ret( - TPAX_SYSTEM_ERROR(dctx), - 0); - - /* explicit item directory entry */ - if (tpax_dirent_init_from_uctx(uctx->st,name,dirent) < 0) - return tpax_archive_append_ret( - TPAX_CUSTOM_ERROR( - dctx, - TPAX_ERR_FLOW_ERROR), - 0); - - /* add to queue */ - if (tpax_archive_append_queue_item( - dctx,dirent,0,prefix,0, - TPAX_ITEM_EXPLICIT, - fdat,&fkeep) < 0) - return tpax_archive_append_ret( - TPAX_NESTED_ERROR(dctx), - 0); - - /* queue directory child items */ - dentbuf = tpax_get_driver_dirents(dctx); - cdent = tpax_get_driver_dirmark(dctx); - - for (; cdent; ) { - if (cdent->dirent.d_type == DT_DIR) - if (dctx->cctx->drvflags & TPAX_DRIVER_DIR_MEMBER_RECURSE) - if (tpax_archive_append_dir_entries(dctx,cdent) < 0) - return TPAX_NESTED_ERROR(dctx); - - addr = (uintptr_t)cdent; - addr += cdent->nsize; - cnext = (struct tpax_dirent *)addr; - - if (cnext == dentbuf->cdent) { - dentbuf = dentbuf->next; - cnext = dentbuf ? dentbuf->dbuf : 0; - } - - cdent = cnext; - } - - return 0; -} diff --git a/src/logic/tpax_archive_enqueue.c b/src/logic/tpax_archive_enqueue.c new file mode 100644 index 0000000..222b0ad --- /dev/null +++ b/src/logic/tpax_archive_enqueue.c @@ -0,0 +1,475 @@ +/**************************************************************/ +/* tpax: a topological pax implementation */ +/* Copyright (C) 2020--2024 SysDeer Technologies, LLC */ +/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */ +/**************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "tpax_driver_impl.h" +#include "tpax_getdents_impl.h" +#include "tpax_tmpfile_impl.h" +#include "tpax_errinfo_impl.h" + +static char * tpax_add_prefix_item( + const struct tpax_driver_ctx * dctx, + const char * prefix) +{ + struct tpax_driver_ctx_impl * ictx; + char ** prefv; + char ** psrc; + char ** pdst; + off_t elements; + char * pitem; + + ictx = tpax_get_driver_ictx(dctx); + + for (psrc=ictx->prefixv; *psrc; psrc++) + if (!strcmp(*psrc,prefix)) + return *psrc; + + if (ictx->prefixp == ictx->prefcap) { + elements = ictx->prefcap - ictx->prefixv; + elements += 256; + + if (!(prefv = calloc(elements,sizeof(char *)))) + return 0; + + for (psrc=ictx->prefixv,pdst=prefv; *psrc; psrc++,pdst++) + *pdst = *psrc; + + if (ictx->prefixv != ictx->prefptr) + free(ictx->prefixv); + + ictx->prefixv = prefv; + ictx->prefixp = pdst; + ictx->prefcap = &prefv[--elements]; + } + + if (!(pitem = strdup(prefix))) + return 0; + + *ictx->prefixp++ = pitem; + + return pitem; +} + +static char * tpax_add_prefix_item_from_path( + const struct tpax_driver_ctx * dctx, + const char * path, + const char * mark) +{ + off_t nbytes; + char pathbuf[PATH_MAX]; + + if ((nbytes = (mark - path)) >= (PATH_MAX - 1)) + return 0; + + memcpy(pathbuf,path,nbytes); + pathbuf[nbytes++] = '/'; + pathbuf[nbytes] = '\0'; + + return tpax_add_prefix_item(dctx,pathbuf); +} + +static struct tpax_dirent_buffer * tpax_dirent_buf_first_alloc( + const struct tpax_driver_ctx * dctx) +{ + void * addr; + struct tpax_driver_ctx_impl * ictx; + + addr = (struct tpax_dirent_buffer *)mmap( + 0,TPAX_DIRENT_BUFLEN, + PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, + -1,0); + + if (addr == MAP_FAILED) + return 0; + + ictx = tpax_get_driver_ictx(dctx); + ictx->dirents = (struct tpax_dirent_buffer *)addr; + ictx->dirents->cdent = ictx->dirents->dbuf; + + ictx->dirents->size = TPAX_DIRENT_BUFLEN; + ictx->dirents->next = 0; + + ictx->dirents->nfree = TPAX_DIRENT_BUFLEN; + ictx->dirents->nfree -= offsetof(struct tpax_dirent_buffer,dbuf); + + return ictx->dirents; +} + +static struct tpax_dirent_buffer * tpax_dirent_buf_next_alloc( + struct tpax_dirent_buffer * current) +{ + void * addr; + + addr = (struct tpax_dirent_buffer *)mmap( + 0,TPAX_DIRENT_BUFLEN, + PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, + -1,0); + + if (addr == MAP_FAILED) + return 0; + + current->next = (struct tpax_dirent_buffer *)addr; + current->next->cdent = current->next->dbuf; + + current->next->size = TPAX_DIRENT_BUFLEN; + current->next->next = 0; + + current->next->nfree = TPAX_DIRENT_BUFLEN; + current->next->nfree -= offsetof(struct tpax_dirent_buffer,dbuf); + + return current->next; +} + +static int tpax_archive_enqueue_ret( + int ret, + struct tpax_unit_ctx * unit) +{ + if (unit) + tpax_lib_free_unit_ctx(unit); + + return ret; +} + +static int tpax_archive_add_queue_item( + const struct tpax_driver_ctx * dctx, + const struct dirent * dirent, + const struct tpax_dirent * parent, + const char * prefix, + int depth, + int flags, + int fdat, + bool * fkeep) +{ + struct tpax_dirent_buffer * dentbuf; + struct tpax_dirent * cdent; + const char * src; + char * dst; + char * cap; + size_t needed; + + if (!(dentbuf = tpax_get_driver_dirents(dctx))) + if (!(dentbuf = tpax_dirent_buf_first_alloc(dctx))) + return tpax_archive_enqueue_ret( + TPAX_SYSTEM_ERROR(dctx), + 0); + + needed = dirent->d_reclen; + needed += offsetof(struct tpax_dirent,dirent); + needed += 0x7; + needed |= 0x7; + needed ^= 0x7; + + for (; dentbuf->next && (dentbuf->nfree < needed); ) + dentbuf = dentbuf->next; + + if (dentbuf->nfree < needed) + if (!(dentbuf = tpax_dirent_buf_next_alloc(dentbuf))) + return tpax_archive_enqueue_ret( + TPAX_SYSTEM_ERROR(dctx), + 0); + + *fkeep = true; + cdent = dentbuf->cdent; + + cdent->fdat = fdat; + cdent->depth = depth; + cdent->flags = flags; + cdent->nsize = needed; + cdent->parent = parent; + cdent->prefix = prefix; + + memset(&cdent->dirent,0,offsetof(struct dirent,d_name)); + + cdent->dirent.d_ino = dirent->d_ino; + cdent->dirent.d_type = dirent->d_type; + cdent->dirent.d_reclen = dirent->d_reclen; + + src = dirent->d_name; + dst = cdent->dirent.d_name; + + cap = dst - offsetof(struct dirent,d_name); + cap -= offsetof(struct tpax_dirent,dirent); + cap += needed; + + for (; *src; ) + *dst++ = *src++; + + for (; dstcdent = (struct tpax_dirent *)cap; + dentbuf->nfree -= needed; + + tpax_set_driver_dirmark(dctx,cdent); + + return 0; +} + +static int tpax_archive_enqueue_dir_entries( + const struct tpax_driver_ctx * dctx, + struct tpax_dirent * dent) +{ + int fd; + int fdat; + int depth; + bool fkeep; + long nbytes; + struct dirent * dirent; + struct dirent * dirents; + struct tpax_unit_ctx * uctx; + struct stat st; + uintptr_t addr; + + /* init */ + fdat = dent->fdat; + depth = dent->depth; + + /* uctx on the fly */ + if (tpax_lib_get_unit_ctx( + dctx,fdat, + dent->dirent.d_name, + &uctx) < 0) + return TPAX_NESTED_ERROR(dctx); + + /* verify that recursion item is still a directory */ + if (!S_ISDIR(uctx->st->st_mode)) + return tpax_archive_enqueue_ret( + TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR), + uctx); + + /* obtain buffer for file-system directory entries */ + dirents = tpax_get_driver_getdents_buffer(dctx); + dirent = dirents; + fkeep = false; + nbytes = 0; + depth++; + + /* open directory and obtain first directory entries */ + if ((fd = openat(fdat,dent->dirent.d_name,O_RDONLY|O_DIRECTORY|O_CLOEXEC,0)) < 0) + return tpax_archive_enqueue_ret( + TPAX_SYSTEM_ERROR(dctx), + uctx); + + nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN); + + while ((nbytes == -EINTR) || ((nbytes < 0) && (errno == EINTR))) + nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN); + + if (nbytes < 0) + return tpax_archive_enqueue_ret( + TPAX_SYSTEM_ERROR(dctx), + uctx); + + /* iterate */ + for (; nbytes>0; ) { + if (!strcmp(dirent->d_name,".")) { + (void)0; + + } else if (!strcmp(dirent->d_name,"..")) { + (void)0; + + } else { + if (dirent->d_type == DT_UNKNOWN) { + if (fstatat(fd,dirent->d_name,&st,AT_SYMLINK_NOFOLLOW)) + return tpax_archive_enqueue_ret( + TPAX_SYSTEM_ERROR(dctx), + uctx); + + if (S_ISDIR(st.st_mode)) { + dirent->d_type = DT_DIR; + } + } + + if (tpax_archive_add_queue_item( + dctx,dirent, + dent,0,depth, + TPAX_ITEM_IMPLICIT, + fd,&fkeep) < 0) + return tpax_archive_enqueue_ret( + TPAX_NESTED_ERROR(dctx), + uctx); + } + + addr = (uintptr_t)dirent; + addr += dirent->d_reclen; + nbytes -= dirent->d_reclen; + dirent = (struct dirent *)addr; + + if (nbytes == 0) { + nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN); + + while ((nbytes == -EINTR) || ((nbytes < 0) && (errno == EINTR))) + nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN); + + if (nbytes < 0) + tpax_archive_enqueue_ret( + TPAX_SYSTEM_ERROR(dctx), + uctx); + + dirent = dirents; + } + } + + /* all done */ + return tpax_archive_enqueue_ret( + fkeep ? 0 : close(fd), + uctx); +} + +static const char * tpax_path_prefix_mark(const char * path) +{ + const char * src; + char * mark; + char pathbuf[PATH_MAX]; + + src = path; + mark = pathbuf; + + for (; *src; ) + *mark++ = *src++; + + for (--mark; (*mark == '/'); mark--) + (void)0; + + *++mark = '\0'; + + for (; (mark > pathbuf) && (mark[-1] != '/'); ) + mark--; + + return (mark <= pathbuf) ? 0 : &path[--mark-pathbuf]; +} + +static int tpax_dirent_init_from_uctx( + const struct stat * st, + const char * basename, + struct dirent * dirent) +{ + /* st_mode to d_type translation */ + if (S_ISREG(st->st_mode)) + dirent->d_type = DT_REG; + else if (S_ISLNK(st->st_mode)) + dirent->d_type = DT_LNK; + else if (S_ISDIR(st->st_mode)) + dirent->d_type = DT_DIR; + else if (S_ISCHR(st->st_mode)) + dirent->d_type = DT_CHR; + else if (S_ISBLK(st->st_mode)) + dirent->d_type = DT_CHR; + else if (S_ISFIFO(st->st_mode)) + dirent->d_type = DT_CHR; + else + return -1; + + /* d_off, d_ino */ + dirent->d_off = 0; + dirent->d_ino = st->st_ino; + + /* d_reclen */ + dirent->d_reclen = offsetof(struct dirent,d_name); + dirent->d_reclen += strlen(basename) + 1; + + dirent->d_reclen += 0x1; + dirent->d_reclen |= 0x1; + dirent->d_reclen ^= 0x1; + + /* d_name */ + strcpy(dirent->d_name,basename); + + return 0; +} + +int tpax_archive_enqueue( + const struct tpax_driver_ctx * dctx, + const struct tpax_unit_ctx * uctx) +{ + int fdat; + uintptr_t addr; + const char * name; + const char * mark; + const char * prefix; + bool fkeep; + struct tpax_dirent_buffer * dentbuf; + struct tpax_dirent * cdent; + struct tpax_dirent * cnext; + struct dirent * dirent; + char entbuf[PATH_MAX + sizeof(struct dirent)]; + + /* init */ + fdat = tpax_driver_fdcwd(dctx); + dirent = (struct dirent *)entbuf; + prefix = 0; + + /* split path to prefix + basename */ + if ((mark = tpax_path_prefix_mark(*uctx->path))) + if (!(prefix = tpax_add_prefix_item_from_path( + dctx,*uctx->path,mark))) + return tpax_archive_enqueue_ret( + TPAX_BUFFER_ERROR(dctx), + 0); + + name = mark ? ++mark : *uctx->path; + + if (prefix) + if ((fdat = openat(fdat,prefix,O_RDONLY|O_DIRECTORY|O_CLOEXEC,0)) < 0) + return tpax_archive_enqueue_ret( + TPAX_SYSTEM_ERROR(dctx), + 0); + + /* explicit item directory entry */ + if (tpax_dirent_init_from_uctx(uctx->st,name,dirent) < 0) + return tpax_archive_enqueue_ret( + TPAX_CUSTOM_ERROR( + dctx, + TPAX_ERR_FLOW_ERROR), + 0); + + /* add to queue */ + if (tpax_archive_add_queue_item( + dctx,dirent,0,prefix,0, + TPAX_ITEM_EXPLICIT, + fdat,&fkeep) < 0) + return tpax_archive_enqueue_ret( + TPAX_NESTED_ERROR(dctx), + 0); + + /* queue directory child items */ + dentbuf = tpax_get_driver_dirents(dctx); + cdent = tpax_get_driver_dirmark(dctx); + + for (; cdent; ) { + if (cdent->dirent.d_type == DT_DIR) + if (dctx->cctx->drvflags & TPAX_DRIVER_DIR_MEMBER_RECURSE) + if (tpax_archive_enqueue_dir_entries(dctx,cdent) < 0) + return TPAX_NESTED_ERROR(dctx); + + addr = (uintptr_t)cdent; + addr += cdent->nsize; + cnext = (struct tpax_dirent *)addr; + + if (cnext == dentbuf->cdent) { + dentbuf = dentbuf->next; + cnext = dentbuf ? dentbuf->dbuf : 0; + } + + cdent = cnext; + } + + return 0; +} -- cgit v1.2.3