tar: fix problem with paths longer than 100 characters - sbase - suckless unix tools
 (HTM) git clone git://git.suckless.org/sbase
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 20c27b1ad0f2fae65ede721c43f8cb66186d3049
 (DIR) parent cf1e0643396391213056ebae2f5c25611fc20ea4
 (HTM) Author: TahaGTRC <tahamedhous@gmail.com>
       Date:   Fri,  6 Dec 2024 10:37:20 +0100
       
       tar: fix problem with paths longer than 100 characters
       
       Diffstat:
         M tar.c                               |      25 +++++++++++++++++++++++--
       
       1 file changed, 23 insertions(+), 2 deletions(-)
       ---
 (DIR) diff --git a/tar.c b/tar.c
       @@ -201,7 +201,28 @@ archive(const char *path)
        
                h = (struct header *)b;
                memset(b, 0, sizeof(b));
       -        estrlcpy(h->name,    path,                        sizeof(h->name));
       +
       +        if (strlen(path) > 255) {
       +                const char *reason = "path exceeds 255 character limit";
       +                eprintf("malformed tar archive: %s\n", reason);
       +        } else if (strlen(path) >= 100) {
       +                size_t prefix_len = 155;
       +                const char *last_slash = strrchr(path, '/');
       +
       +                if (last_slash && last_slash < path + prefix_len) {
       +                    prefix_len = last_slash - path + 1;
       +                }
       +
       +                /* strlcpy is fine here - for path ONLY -,
       +                 * since we're splitting the path.
       +                 * It's not an issue if the prefix can't hold
       +                 * the full path — name will take the rest. */
       +                strlcpy(h->prefix, path, prefix_len);
       +                estrlcpy(h->name, path + prefix_len, sizeof(h->name));
       +        } else {
       +                estrlcpy(h->name, path,                sizeof(h->name));
       +        }
       +
                putoctal(h->mode,    (unsigned)st.st_mode & 0777, sizeof(h->mode));
                putoctal(h->uid,     (unsigned)st.st_uid,         sizeof(h->uid));
                putoctal(h->gid,     (unsigned)st.st_gid,         sizeof(h->gid));
       @@ -456,7 +477,7 @@ xt(int argc, char *argv[], int mode)
                int i, n;
                int (*fn)(char *, ssize_t, char[BLKSIZ]) = (mode == 'x') ? unarchive : print;
        
       -        while (eread(tarfd, b, BLKSIZ) > 0 && h->name[0]) {
       +        while (eread(tarfd, b, BLKSIZ) > 0 && (h->name[0] || h->prefix[0])) {
                        chktar(h);
                        sanitize(h), n = 0;