From 6eeefd208743b0b2edbd7330dea36eea5b1099b7 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Tue, 16 Nov 2021 14:16:46 +0100 Subject: [PATCH] percent encode characters in path names Paths could contain characters like # (fragment), '?', control-characters, etc. --- stagit-index.c | 24 +++++++++++++++++++++++- stagit.c | 32 +++++++++++++++++++++++++++----- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/stagit-index.c b/stagit-index.c index 84785a9..8a53463 100644 --- a/stagit-index.c +++ b/stagit-index.c @@ -28,6 +28,28 @@ joinpath(char *buf, size_t bufsiz, const char *path, const char *path2) path, path[0] && path[strlen(path) - 1] != '/' ? "/" : "", path2); } +/* Percent-encode, see RFC3986 section 2.1. */ +void +percentencode(FILE *fp, const char *s, size_t len) +{ + static char tab[] = "0123456789ABCDEF"; + unsigned char uc; + size_t i; + + for (i = 0; *s && i < len; s++, i++) { + uc = *s; + /* NOTE: do not encode '/' for paths */ + if (uc < '/' || uc >= 127 || (uc >= ':' && uc <= '@') || + uc == '[' || uc == ']') { + putc('%', fp); + putc(tab[(uc >> 4) & 0x0f], fp); + putc(tab[uc & 0x0f], fp); + } else { + putc(uc, fp); + } + } +} + /* Escape characters below as HTML 2.0 / XML 1.0. */ void xmlencode(FILE *fp, const char *s, size_t len) @@ -118,7 +140,7 @@ writelog(FILE *fp) *p = '\0'; fputs("", fp); xmlencode(fp, stripped_name, strlen(stripped_name)); fputs("", fp); diff --git a/stagit.c b/stagit.c index d637691..07d7929 100644 --- a/stagit.c +++ b/stagit.c @@ -359,6 +359,28 @@ efopen(const char *filename, const char *flags) return fp; } +/* Percent-encode, see RFC3986 section 2.1. */ +void +percentencode(FILE *fp, const char *s, size_t len) +{ + static char tab[] = "0123456789ABCDEF"; + unsigned char uc; + size_t i; + + for (i = 0; *s && i < len; s++, i++) { + uc = *s; + /* NOTE: do not encode '/' for paths */ + if (uc < '/' || uc >= 127 || (uc >= ':' && uc <= '@') || + uc == '[' || uc == ']') { + putc('%', fp); + putc(tab[(uc >> 4) & 0x0f], fp); + putc(tab[uc & 0x0f], fp); + } else { + putc(uc, fp); + } + } +} + /* Escape characters below as HTML 2.0 / XML 1.0. */ void xmlencode(FILE *fp, const char *s, size_t len) @@ -497,7 +519,7 @@ writeheader(FILE *fp, const char *title) fputs("", fp); if (cloneurl[0]) { fputs("git clone ", fp); xmlencode(fp, cloneurl, strlen(cloneurl)); fputs("", fp); @@ -570,7 +592,7 @@ printcommit(FILE *fp, struct commitinfo *ci) fputs("Author: ", fp); xmlencode(fp, ci->author->name, strlen(ci->author->name)); fputs(" <author->email, strlen(ci->author->email)); + xmlencode(fp, ci->author->email, strlen(ci->author->email)); /* not percent-encoded */ fputs("\">", fp); xmlencode(fp, ci->author->email, strlen(ci->author->email)); fputs(">\nDate: ", fp); @@ -665,11 +687,11 @@ printshowfile(FILE *fp, struct commitinfo *ci) patch = ci->deltas[i]->patch; delta = git_patch_get_delta(patch); fprintf(fp, "diff --git a/old_file.path, strlen(delta->old_file.path)); + percentencode(fp, delta->old_file.path, strlen(delta->old_file.path)); fputs(".html\">", fp); xmlencode(fp, delta->old_file.path, strlen(delta->old_file.path)); fprintf(fp, " b/new_file.path, strlen(delta->new_file.path)); + percentencode(fp, delta->new_file.path, strlen(delta->new_file.path)); fprintf(fp, ".html\">"); xmlencode(fp, delta->new_file.path, strlen(delta->new_file.path)); fprintf(fp, "\n"); @@ -1037,7 +1059,7 @@ writefilestree(FILE *fp, git_tree *tree, const char *path) fputs("", fp); fputs(filemode(git_tree_entry_filemode(entry)), fp); fprintf(fp, "", fp); xmlencode(fp, entrypath, strlen(entrypath)); fputs("", fp); -- 2.30.2