On 12/22/14 5:40 PM, Oskari Saarenmaa wrote: > I think we should just use the UStar tar format > (http://en.wikipedia.org/wiki/Tar_%28computing%29#UStar_format) and > allow long file names; all actively used tar implementations should be > able to handle them. I'll try to write a patch for that soonish.
UStar doesn't handle long link targets, only long file names (and then only up to 255 characters, which doesn't seem satisfactory). AFAICT, to allow long link targets, the available solutions are either pax extended headers or GNU-specific long-link extra headers. When I create a symlink with a long target and call tar on it, GNU tar by default creates the GNU long-link header and BSD tar by default creates a pax header. But they are both able to extract either one. As a demo for how this might look, attached is a wildly incomplete patch to produce GNU long-link headers.
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c index fbcecbb..f0cffcf 100644 --- a/src/backend/replication/basebackup.c +++ b/src/backend/replication/basebackup.c @@ -1233,13 +1233,15 @@ static void _tarWriteHeader(const char *filename, const char *linktarget, struct stat * statbuf) { - char h[512]; + char *h; - tarCreateHeader(h, filename, linktarget, statbuf->st_size, + h = tarCreateHeader(filename, linktarget, statbuf->st_size, statbuf->st_mode, statbuf->st_uid, statbuf->st_gid, statbuf->st_mtime); pq_putmessage('d', h, 512); + + free(h); } /* diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c index e7c2939..490dd98 100644 --- a/src/bin/pg_basebackup/pg_basebackup.c +++ b/src/bin/pg_basebackup/pg_basebackup.c @@ -911,10 +911,10 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum) if (basetablespace && writerecoveryconf) { - char header[512]; + char *header; int padding; - tarCreateHeader(header, "recovery.conf", NULL, + header = tarCreateHeader("recovery.conf", NULL, recoveryconfcontents->len, 0600, 04000, 02000, time(NULL)); @@ -925,6 +925,8 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum) WRITE_TAR_DATA(recoveryconfcontents->data, recoveryconfcontents->len); if (padding) WRITE_TAR_DATA(zerobuf, padding); + + free(header); } /* 2 * 512 bytes empty data at end of file */ diff --git a/src/bin/pg_dump/pg_backup_tar.c b/src/bin/pg_dump/pg_backup_tar.c index f48d369..60ae013 100644 --- a/src/bin/pg_dump/pg_backup_tar.c +++ b/src/bin/pg_dump/pg_backup_tar.c @@ -1300,11 +1300,13 @@ _tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th) static void _tarWriteHeader(TAR_MEMBER *th) { - char h[512]; + char *h; - tarCreateHeader(h, th->targetFile, NULL, th->fileLen, 0600, 04000, 02000, time(NULL)); + h = tarCreateHeader(th->targetFile, NULL, th->fileLen, 0600, 04000, 02000, time(NULL)); /* Now write the completed header. */ if (fwrite(h, 1, 512, th->tarFH) != 512) WRITE_ERROR_EXIT; + + free(h); } diff --git a/src/include/pgtar.h b/src/include/pgtar.h index 2dd6f6b..c3e0eb5 100644 --- a/src/include/pgtar.h +++ b/src/include/pgtar.h @@ -11,5 +11,5 @@ * *------------------------------------------------------------------------- */ -extern void tarCreateHeader(char *h, const char *filename, const char *linktarget, size_t size, mode_t mode, uid_t uid, gid_t gid, time_t mtime); +extern char * tarCreateHeader(const char *filename, const char *linktarget, size_t size, mode_t mode, uid_t uid, gid_t gid, time_t mtime); extern int tarChecksum(char *header); diff --git a/src/port/tar.c b/src/port/tar.c index 8ef4f9c..d8183d7 100644 --- a/src/port/tar.c +++ b/src/port/tar.c @@ -49,10 +49,26 @@ tarChecksum(char *header) * must always have space for 512 characters, which is a requirement by * the tar format. */ -void -tarCreateHeader(char *h, const char *filename, const char *linktarget, +char * +tarCreateHeader(const char *filename, const char *linktarget, size_t size, mode_t mode, uid_t uid, gid_t gid, time_t mtime) { + char *h; + char *ext_header = NULL; + char *ext_content = NULL; + + if (0 && linktarget && strlen(linktarget) > 99) + { + ext_header = calloc(512, 1); + print_val(&ext_header[124], 512, 8, 11); + sprintf(&ext_header[156], "K"); + sprintf(&ext_header[148], "%06o ", tarChecksum(ext_header)); + + ext_content = calloc(512, 1); + strcpy(ext_content, linktarget); + } + h = malloc(512); + /* * Note: most of the fields in a tar header are not supposed to be * null-terminated. We use sprintf, which will write a null after the @@ -141,4 +157,18 @@ tarCreateHeader(char *h, const char *filename, const char *linktarget, * 6 digits, a space, and a null, which is legal per POSIX. */ sprintf(&h[148], "%06o ", tarChecksum(h)); + + if (ext_header || ext_content) + { + char *ret = malloc(3 * 512); + memcpy(ret, ext_header, 512); + memcpy(ret + 512, ext_content, 512); + memcpy(ret + 1024, h, 512); + free(ext_header); + free(ext_content); + free(h); + return ret; + } + else + return h; }
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers