diff options
-rw-r--r-- | lib/dpkg/path.c | 61 | ||||
-rw-r--r-- | lib/dpkg/path.h | 1 | ||||
-rw-r--r-- | src/archives.c | 65 |
3 files changed, 67 insertions, 60 deletions
diff --git a/lib/dpkg/path.c b/lib/dpkg/path.c index 8ea891eb4..240bdce4d 100644 --- a/lib/dpkg/path.c +++ b/lib/dpkg/path.c @@ -23,6 +23,7 @@ #include <config.h> #include <compat.h> +#include <stdio.h> #include <string.h> #include <dpkg/path.h> @@ -54,3 +55,63 @@ path_skip_slash_dotslash(const char *path) return path; } +/* + * snprintf(3) doesn't work if format contains %.<nnn>s and an argument has + * invalid char for locale, then it returns -1. + * ohshite() is ok, but fd_fd_copy(), which is used in tarobject() in this + * file, is not ok, because + * - fd_fd_copy() == buffer_copy_setup() [include/dpkg.h] + * - buffer_copy_setup() uses varbufvprintf(&v, desc, al); [lib/mlib.c] + * - varbufvprintf() fails and memory exausted, because it call + * fmt = "backend dpkg-deb during `%.255s' + * arg may contain some invalid char, for example, + * /usr/share/doc/console-tools/examples/unicode/\342\231\252\342\231\254 + * in console-tools. + * In this case, if user uses some locale which doesn't support \342\231..., + * vsnprintf() always returns -1 and varbufextend() get called again + * and again until memory is exausted and it aborts. + * + * So, we need to escape invalid char, probably as in + * tar-1.13.19/lib/quotearg.c: quotearg_buffer_restyled() + * but here I escape all 8bit chars, in order to be simple. + * - ukai@debian.or.jp + */ +char * +path_quote_filename(char *buf, int size, char *s) +{ + char *r = buf; + + while (size > 0) { + switch (*s) { + case '\0': + *buf = '\0'; + return r; + case '\\': + *buf++ = '\\'; + *buf++ = '\\'; + size -= 2; + break; + default: + if (((*s) & 0x80) == '\0') { + *buf++ = *s++; + --size; + } else { + if (size > 4) { + sprintf(buf, "\\%03o", + *(unsigned char *)s); + size -= 4; + buf += 4; + s++; + } else { + /* Buffer full. */ + *buf = '\0'; /* XXX */ + return r; + } + } + } + } + *buf = '\0'; /* XXX */ + + return r; +} + diff --git a/lib/dpkg/path.h b/lib/dpkg/path.h index 701eb8e87..ae65f063e 100644 --- a/lib/dpkg/path.h +++ b/lib/dpkg/path.h @@ -32,6 +32,7 @@ DPKG_BEGIN_DECLS size_t path_rtrim_slash_slashdot(char *path); const char *path_skip_slash_dotslash(const char *path); +char *path_quote_filename(char *buf, int size, char *s); DPKG_END_DECLS diff --git a/src/archives.c b/src/archives.c index 17ae9a288..41d3f0744 100644 --- a/src/archives.c +++ b/src/archives.c @@ -43,6 +43,7 @@ #include <dpkg/dpkg.h> #include <dpkg/dpkg-db.h> +#include <dpkg/path.h> #include <dpkg/buffer.h> #include <dpkg/subproc.h> #include <dpkg/tarfn.h> @@ -63,64 +64,6 @@ static security_context_t scontext = NULL; struct pkginfo *conflictor[MAXCONFLICTORS]; int cflict_index = 0; -/* snprintf(3) doesn't work if format contains %.<nnn>s and an argument has - * invalid char for locale, then it returns -1. - * ohshite() is ok, but fd_fd_copy(), which is used in tarobject() in this - * file, is not ok, because - * - fd_fd_copy() == buffer_copy_setup() [include/dpkg.h] - * - buffer_copy_setup() uses varbufvprintf(&v, desc, al); [lib/mlib.c] - * - varbufvprintf() fails and memory exausted, because it call - * fmt = "backend dpkg-deb during `%.255s' - * arg may contain some invalid char, for example, - * /usr/share/doc/console-tools/examples/unicode/\342\231\252\342\231\254 - * in console-tools. - * In this case, if user uses some locale which doesn't support \342\231..., - * vsnprintf() always returns -1 and varbufextend() get called again - * and again until memory is exausted and it aborts. - * - * So, we need to escape invalid char, probably as in - * tar-1.13.19/lib/quotearg.c: quotearg_buffer_restyled() - * but here I escape all 8bit chars, in order to be simple. - * - ukai@debian.or.jp - */ -static char * -quote_filename(char *buf, int size, char *s) -{ - char *r = buf; - - while (size > 0) { - switch (*s) { - case '\0': - *buf = '\0'; - return r; - case '\\': - *buf++ = '\\'; - *buf++ = '\\'; - size -= 2; - break; - default: - if (((*s) & 0x80) == '\0') { - *buf++ = *s++; - --size; - } else { - if (size > 4) { - sprintf(buf, "\\%03o", *(unsigned char *)s); - size -= 4; - buf += 4; - s++; - } else { - /* buffer full */ - *buf = '\0'; /* XXX */ - return r; - } - } - } - } - *buf = '\0'; /* XXX */ - - return r; -} - /* special routine to handle partial reads from the tarfile */ static int safe_read(int fd, void *buf, int len) { @@ -258,7 +201,7 @@ tarfile_skip_one_forward(struct TarInfo *ti, fd_null_copy(tc->backendpipe, ti->Size, _("skipped unpacking file '%.255s' (replaced or excluded?)"), - quote_filename(fnamebuf, 256, ti->Name)); + path_quote_filename(fnamebuf, 256, ti->Name)); r = ti->Size % TARBLKSZ; if (r > 0) r = safe_read(tc->backendpipe, databuf, TARBLKSZ - r); @@ -694,7 +637,9 @@ int tarobject(struct TarInfo *ti) { debug(dbg_eachfiledetail,"tarobject NormalFile[01] open size=%lu", (unsigned long)ti->Size); { char fnamebuf[256]; - fd_fd_copy(tc->backendpipe, fd, ti->Size, _("backend dpkg-deb during `%.255s'"),quote_filename(fnamebuf,256,ti->Name)); + fd_fd_copy(tc->backendpipe, fd, ti->Size, + _("backend dpkg-deb during `%.255s'"), + path_quote_filename(fnamebuf, 256, ti->Name)); } r= ti->Size % TARBLKSZ; if (r > 0) r= safe_read(tc->backendpipe,databuf,TARBLKSZ - r); |