diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/logic/tpax_archive_append.c | 129 |
1 files changed, 126 insertions, 3 deletions
diff --git a/src/logic/tpax_archive_append.c b/src/logic/tpax_archive_append.c index 219c596..3dcac5c 100644 --- a/src/logic/tpax_archive_append.c +++ b/src/logic/tpax_archive_append.c @@ -92,6 +92,24 @@ static char * tpax_append_prefix_item( 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 int tpax_archive_append_pad( const struct tpax_driver_ctx * dctx, int fdout, @@ -367,15 +385,120 @@ static int tpax_archive_append_dir_entries( 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); + + 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_item( const struct tpax_driver_ctx * dctx, const struct tpax_unit_ctx * uctx) { - (void)dctx; - (void)uctx; + int fdat; + const char * name; + const char * mark; + const char * prefix; + bool fkeep; + 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); + (void)tpax_archive_append_pad; (void)tpax_archive_append_dir_entries; - (void)tpax_append_prefix_item; return 0; } |