summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/logic/tpax_archive_append.c129
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;
}