diff --git a/include/haproxy/tools.h b/include/haproxy/tools.h index 22a20a856..e31151211 100644 --- a/include/haproxy/tools.h +++ b/include/haproxy/tools.h @@ -1147,6 +1147,7 @@ void dump_hex(struct buffer *out, const char *pfx, const void *buf, int len, int int may_access(const void *ptr); const void *resolve_sym_name(struct buffer *buf, const char *pfx, const void *addr); const void *resolve_dso_name(struct buffer *buf, const char *pfx, const void *addr); +void make_tar_header(char *output, const char *pfx, const char *fname, const char *link, size_t size, mode_t mode); const char *get_exec_path(void); void *get_sym_curr_addr(const char *name); void *get_sym_next_addr(const char *name); diff --git a/src/tools.c b/src/tools.c index 112b57e82..5ad0c95ae 100644 --- a/src/tools.c +++ b/src/tools.c @@ -5809,6 +5809,71 @@ const void *resolve_dso_name(struct buffer *buf, const char *pfx, const void *ad return NULL; } +/* make a simplistic tar header (512 bytes) into output for file name + * of size and mode . An optional prefix directory name can be + * passed in , and an optional symlink destination may be passed in + * . NULL is accepted for and if unused. Note that here we + * may abuse the link destination that is normally not used with regular files + * to place a magic. + */ +void make_tar_header(char *output, const char *pfx, const char *fname, const char *link, size_t size, mode_t mode) +{ + uint i, csum; + + union { + uchar buffer[512]; /* raw data */ + struct { /* byte offset */ + char name[100]; /* 0 */ + char mode[8]; /* 100 : octal */ + char uid[8]; /* 108 : octal */ + char gid[8]; /* 116 : octal */ + char size[12]; /* 124 : octal */ + char mtime[12]; /* 136 : octal */ + char chksum[8]; /* 148 : sum of the header's bytes */ + char typeflag; /* 156 : '0' = regular file */ + char linkname[100]; /* 157 */ + char magic_ver[8]; /* 257 : "ustar \0" or "ustar\0""00" */ + char uname[32]; /* 265 */ + char gname[32]; /* 297 */ + char devmajor[8]; /* 329 */ + char devminor[8]; /* 337 */ + char prefix[155]; /* 345 */ + char pad12[12]; /* 500 */ + } hdr; + } blk = { + .hdr = { + .name = "", + .mode = "", + .uid = "0000000", + .gid = "0000000", + .size = "00000000000", + .mtime = "00000000000", + .chksum = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }, + .typeflag = '0', // regular file + .magic_ver = { 'u', 's', 't', 'a', 'r', '\0', '0', '0' }, + .uname = "root", + .gname = "root", + .devmajor = "0", + .devminor = "0", + }, + }; + + strlcpy2(blk.hdr.linkname, link ? link : NULL, sizeof(blk.hdr.linkname)); + strlcpy2(blk.hdr.prefix, pfx ? pfx : NULL, sizeof(blk.hdr.prefix)); + strlcpy2(blk.hdr.name, fname, sizeof(blk.hdr.name)); + snprintf(blk.hdr.size, sizeof(blk.hdr.size), "%llo", (ullong)size); + snprintf(blk.hdr.mode, sizeof(blk.hdr.mode), "%07o", (uint)mode & 0x1FFFFF); + + /* cksum: 6 octal bytes followed by NUL then space. Computed with cksum + * preset to 8 spaces. + */ + for (i = csum = 0; i < 512; i++) + csum += blk.buffer[i]; + + snprintf(blk.hdr.chksum, sizeof(blk.hdr.chksum), "%06o", csum); + memcpy(output, &blk, sizeof(blk)); +} + /* On systems where this is supported, let's provide a possibility to enumerate * the list of object files. The output is appended to a buffer initialized by * the caller, with one name per line. A trailing zero is always emitted if data