diff -durpN postgresql.2/src/backend/replication/basebackup.c postgresql.3/src/backend/replication/basebackup.c --- postgresql.2/src/backend/replication/basebackup.c 2012-10-06 19:25:21.002166521 +0200 +++ postgresql.3/src/backend/replication/basebackup.c 2012-11-20 20:00:14.025523523 +0100 @@ -721,48 +721,12 @@ sendDir(char *path, int basepathlen, boo /* - * Utility routine to print possibly larger than 32 bit integers in a - * portable fashion. Filled with zeros. - */ -static void -print_val(char *s, uint64 val, unsigned int base, size_t len) -{ - int i; - - for (i = len; i > 0; i--) - { - int digit = val % base; - - s[i - 1] = '0' + digit; - val = val / base; - } -} - -/* * Maximum file size for a tar member: The limit inherent in the * format is 2^33-1 bytes (nearly 8 GB). But we don't want to exceed * what we can represent in pgoff_t. */ #define MAX_TAR_MEMBER_FILELEN (((int64) 1 << Min(33, sizeof(pgoff_t)*8 - 1)) - 1) -static int -_tarChecksum(char *header) -{ - int i, - sum; - - /* - * Per POSIX, the checksum is the simple sum of all bytes in the header, - * treating the bytes as unsigned, and treating the checksum field (at - * offset 148) as though it contained 8 spaces. - */ - sum = 8 * ' '; /* presumed value for checksum field */ - for (i = 0; i < 512; i++) - if (i < 148 || i >= 156) - sum += 0xFF & header[i]; - return sum; -} - /* Given the member, write the TAR header & send the file */ static void sendFile(char *readfilename, char *tarfilename, struct stat * statbuf) @@ -840,94 +804,12 @@ _tarWriteHeader(const char *filename, co { char h[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 - * required bytes; that null goes into the first byte of the next field. - * This is okay as long as we fill the fields in order. - */ - memset(h, 0, sizeof(h)); - - /* Name 100 */ - sprintf(&h[0], "%.99s", filename); - if (linktarget != NULL || S_ISDIR(statbuf->st_mode)) - { - /* - * We only support symbolic links to directories, and this is - * indicated in the tar format by adding a slash at the end of the - * name, the same as for regular directories. - */ - int flen = strlen(filename); - - flen = Min(flen, 99); - h[flen] = '/'; - h[flen + 1] = '\0'; - } - - /* Mode 8 */ - sprintf(&h[100], "%07o ", (int) statbuf->st_mode); - - /* User ID 8 */ - sprintf(&h[108], "%07o ", statbuf->st_uid); - - /* Group 8 */ - sprintf(&h[116], "%07o ", statbuf->st_gid); - - /* File size 12 - 11 digits, 1 space; use print_val for 64 bit support */ - if (linktarget != NULL || S_ISDIR(statbuf->st_mode)) - /* Symbolic link or directory has size zero */ - print_val(&h[124], 0, 8, 11); - else - print_val(&h[124], statbuf->st_size, 8, 11); - sprintf(&h[135], " "); - - /* Mod Time 12 */ - sprintf(&h[136], "%011o ", (int) statbuf->st_mtime); - - /* Checksum 8 cannot be calculated until we've filled all other fields */ - - if (linktarget != NULL) - { - /* Type - Symbolic link */ - sprintf(&h[156], "2"); - /* Link Name 100 */ - sprintf(&h[157], "%.99s", linktarget); - } - else if (S_ISDIR(statbuf->st_mode)) - /* Type - directory */ - sprintf(&h[156], "5"); - else - /* Type - regular file */ - sprintf(&h[156], "0"); - - /* Magic 6 */ - sprintf(&h[257], "ustar"); - - /* Version 2 */ - sprintf(&h[263], "00"); - - /* User 32 */ - /* XXX: Do we need to care about setting correct username? */ - sprintf(&h[265], "%.31s", "postgres"); - - /* Group 32 */ - /* XXX: Do we need to care about setting correct group name? */ - sprintf(&h[297], "%.31s", "postgres"); - - /* Major Dev 8 */ - sprintf(&h[329], "%07o ", 0); - - /* Minor Dev 8 */ - sprintf(&h[337], "%07o ", 0); - - /* Prefix 155 - not used, leave as nulls */ - - /* - * We mustn't overwrite the next field while inserting the checksum. - * Fortunately, the checksum can't exceed 6 octal digits, so we just write - * 6 digits, a space, and a null, which is legal per POSIX. - */ - sprintf(&h[148], "%06o ", _tarChecksum(h)); + _tarCreateHeader(h, filename, linktarget, + statbuf->st_size, + statbuf->st_mode, + statbuf->st_uid, + statbuf->st_gid, + statbuf->st_mtime); /* Now send the completed header. */ pq_putmessage('d', h, 512); diff -durpN postgresql.2/src/bin/pg_basebackup/pg_basebackup.c postgresql.3/src/bin/pg_basebackup/pg_basebackup.c --- postgresql.2/src/bin/pg_basebackup/pg_basebackup.c 2012-11-20 16:40:52.329063335 +0100 +++ postgresql.3/src/bin/pg_basebackup/pg_basebackup.c 2012-11-20 20:18:38.312376749 +0100 @@ -26,7 +26,6 @@ #include #include #include -#include #ifdef HAVE_LIBZ #include @@ -73,8 +72,6 @@ static int has_xlogendptr = 0; static volatile LONG has_xlogendptr = 0; #endif -/* Don't ever change this value, the TAR file format requires it. */ -#define TARCHUNKSZ 512 PQExpBuffer rcExpBuf = NULL; /* Function headers */ @@ -87,10 +84,6 @@ static void ReceiveAndUnpackTarFile(PGco static char *escape_quotes(const char *src); static void CreateRecoveryConf(PGconn *conn); static void WriteRecoveryConf(void); -static int _tarChecksum(char *header); -static void print_val(char *s, uint64 val, unsigned int base, size_t len); -static void scan_val(char *s, uint64 *val, unsigned int base, size_t len); -static void _tarCreateHeader(char *header, char *filename, size_t filesize); static void BaseBackup(void); static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline, @@ -683,7 +676,10 @@ ReceiveTarFile(PGconn *conn, PGresult *r char header[TARCHUNKSZ]; int padding; - _tarCreateHeader(header, "recovery.conf", rcExpBuf->len); + _tarCreateHeader(header, "recovery.conf", NULL, + rcExpBuf->len, + 0600, 04000, 02000, + time(NULL)); padding = ((rcExpBuf->len + (TARCHUNKSZ-1)) & ~(TARCHUNKSZ-1)) - rcExpBuf->len; @@ -804,7 +800,7 @@ ReceiveTarFile(PGconn *conn, PGresult *r skip_file = (strcmp(&tarhdr[0], "recovery.conf") == 0); - scan_val(&tarhdr[124], &filesz, 8, 11); + _tarScanVal(&tarhdr[124], &filesz, 8, 11); padding = ((filesz + (TARCHUNKSZ-1)) & ~(TARCHUNKSZ-1)) - filesz; filesz += padding; @@ -1110,131 +1106,6 @@ ReceiveAndUnpackTarFile(PGconn *conn, PG WriteRecoveryConf(); } -static int -_tarChecksum(char *header) -{ - int i, - sum; - - /* - * Per POSIX, the checksum is the simple sum of all bytes in the header, - * treating the bytes as unsigned, and treating the checksum field (at - * offset 148) as though it contained 8 spaces. - */ - sum = 8 * ' '; /* presumed value for checksum field */ - for (i = 0; i < TARCHUNKSZ; i++) - if (i < 148 || i >= 156) - sum += 0xFF & header[i]; - return sum; -} - - -/* - * Utility routine to print possibly larger than 32 bit integers in a - * portable fashion. Filled with zeros. - */ -static void -print_val(char *s, uint64 val, unsigned int base, size_t len) -{ - int i; - - for (i = len; i > 0; i--) - { - int digit = val % base; - - s[i - 1] = '0' + digit; - val = val / base; - } -} - - -/* - * Inverse for print_val() - */ -static void -scan_val(char *s, uint64 *val, unsigned int base, size_t len) -{ - uint64 tmp = 0; - int i; - - for (i = 0; i < len; i++) - { - int digit = s[i] - '0'; - - tmp = tmp * base + digit; - } - - *val = tmp; -} - - -static void -_tarCreateHeader(char *header, char *filename, size_t filesize) -{ - /* - * 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 - * required bytes; that null goes into the first byte of the next field. - * This is okay as long as we fill the fields in order. - */ - memset(header, 0, TARCHUNKSZ /* sizeof the tar header */); - - /* Name 100 */ - sprintf(&header[0], "%.99s", filename); - - /* Mode 8 */ - sprintf(&header[100], "0000600 "); - - /* User ID 8 */ - sprintf(&header[108], "0004000 "); - - /* Group 8 */ - sprintf(&header[116], "0002000 "); - - /* File size 12 - 11 digits, 1 space; use print_val for 64 bit support */ - print_val(&header[124], filesize, 8, 11); - sprintf(&header[135], " "); - - /* Mod Time 12 */ - sprintf(&header[136], "%011o ", (int) time(NULL)); - - /* Checksum 8 cannot be calculated until we've filled all other fields */ - - /* Type - regular file */ - sprintf(&header[156], "0"); - - /* Link Name 100 (leave as nulls) */ - - /* Magic 6 */ - sprintf(&header[257], "ustar"); - - /* Version 2 */ - sprintf(&header[263], "00"); - - /* User 32 */ - /* XXX: Do we need to care about setting correct username? */ - sprintf(&header[265], "%.31s", "postgres"); - - /* Group 32 */ - /* XXX: Do we need to care about setting correct group name? */ - sprintf(&header[297], "%.31s", "postgres"); - - /* Major Dev 8 */ - sprintf(&header[329], "%07o ", 0); - - /* Minor Dev 8 */ - sprintf(&header[337], "%07o ", 0); - - /* Prefix 155 - not used, leave as nulls */ - - /* - * We mustn't overwrite the next field while inserting the checksum. - * Fortunately, the checksum can't exceed 6 octal digits, so we just write - * 6 digits, a space, and a null, which is legal per POSIX. - */ - sprintf(&header[148], "%06o ", _tarChecksum(header)); -} - /* * Escape single quotes in a string */ diff -durpN postgresql.2/src/bin/pg_dump/pg_backup_tar.c postgresql.3/src/bin/pg_dump/pg_backup_tar.c --- postgresql.2/src/bin/pg_dump/pg_backup_tar.c 2012-10-03 10:40:48.304207436 +0200 +++ postgresql.3/src/bin/pg_dump/pg_backup_tar.c 2012-11-20 20:16:05.951430114 +0100 @@ -115,7 +115,6 @@ static char *tarGets(char *buf, size_t l static int tarPrintf(ArchiveHandle *AH, TAR_MEMBER *th, const char *fmt,...) __attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4))); static void _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th); -static int _tarChecksum(char *th); static TAR_MEMBER *_tarPositionTo(ArchiveHandle *AH, const char *filename); static size_t tarRead(void *buf, size_t len, TAR_MEMBER *th); static size_t tarWrite(const void *buf, size_t len, TAR_MEMBER *th); @@ -1016,24 +1015,6 @@ tarPrintf(ArchiveHandle *AH, TAR_MEMBER return cnt; } -static int -_tarChecksum(char *header) -{ - int i, - sum; - - /* - * Per POSIX, the checksum is the simple sum of all bytes in the header, - * treating the bytes as unsigned, and treating the checksum field (at - * offset 148) as though it contained 8 spaces. - */ - sum = 8 * ' '; /* presumed value for checksum field */ - for (i = 0; i < 512; i++) - if (i < 148 || i >= 156) - sum += 0xFF & header[i]; - return sum; -} - bool isValidTarHeader(char *header) { @@ -1305,94 +1286,16 @@ _tarGetHeader(ArchiveHandle *AH, TAR_MEM } -/* - * Utility routine to print possibly larger than 32 bit integers in a - * portable fashion. Filled with zeros. - */ -static void -print_val(char *s, uint64 val, unsigned int base, size_t len) -{ - int i; - - for (i = len; i > 0; i--) - { - int digit = val % base; - - s[i - 1] = '0' + digit; - val = val / base; - } -} - - static void _tarWriteHeader(TAR_MEMBER *th) { char h[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 - * required bytes; that null goes into the first byte of the next field. - * This is okay as long as we fill the fields in order. - */ - memset(h, 0, sizeof(h)); - - /* Name 100 */ - sprintf(&h[0], "%.99s", th->targetFile); - - /* Mode 8 */ - sprintf(&h[100], "0000600 "); - - /* User ID 8 */ - sprintf(&h[108], "0004000 "); - - /* Group 8 */ - sprintf(&h[116], "0002000 "); - - /* File size 12 - 11 digits, 1 space; use print_val for 64 bit support */ - print_val(&h[124], th->fileLen, 8, 11); - sprintf(&h[135], " "); - - /* Mod Time 12 */ - sprintf(&h[136], "%011o ", (int) time(NULL)); - - /* Checksum 8 cannot be calculated until we've filled all other fields */ - - /* Type - regular file */ - sprintf(&h[156], "0"); - - /* Link Name 100 (leave as nulls) */ - - /* Magic 6 */ - sprintf(&h[257], "ustar"); - - /* Version 2 */ - sprintf(&h[263], "00"); - - /* User 32 */ - /* XXX: Do we need to care about setting correct username? */ - sprintf(&h[265], "%.31s", "postgres"); - - /* Group 32 */ - /* XXX: Do we need to care about setting correct group name? */ - sprintf(&h[297], "%.31s", "postgres"); - - /* Major Dev 8 */ - sprintf(&h[329], "%07o ", 0); - - /* Minor Dev 8 */ - sprintf(&h[337], "%07o ", 0); - - /* Prefix 155 - not used, leave as nulls */ - - /* - * We mustn't overwrite the next field while inserting the checksum. - * Fortunately, the checksum can't exceed 6 octal digits, so we just write - * 6 digits, a space, and a null, which is legal per POSIX. - */ - sprintf(&h[148], "%06o ", _tarChecksum(h)); + _tarCreateHeader(h, th->targetFile, NULL, + th->fileLen, + 0600, 04000, 02000, + time(NULL)); - /* Now write the completed header. */ if (fwrite(h, 1, 512, th->tarFH) != 512) exit_horribly(modulename, "could not write to output file: %s\n", strerror(errno)); } diff -durpN postgresql.2/src/include/port.h postgresql.3/src/include/port.h --- postgresql.2/src/include/port.h 2012-07-22 16:48:48.548857900 +0200 +++ postgresql.3/src/include/port.h 2012-11-20 19:59:44.745328643 +0100 @@ -16,6 +16,7 @@ #include #include #include +#include /* socket has a different definition on WIN32 */ #ifndef WIN32 @@ -465,4 +466,19 @@ extern int pg_check_dir(const char *dir) /* port/pgmkdirp.c */ extern int pg_mkdir_p(char *path, int omode); +/* port/tarutil.c */ + +/* Don't ever change this value, the TAR file format requires it. */ +#define TARCHUNKSZ 512 + +extern int _tarChecksum(char *header); +extern void _tarPrintVal(char *s, uint64 val, unsigned int base, size_t len); +extern void _tarScanVal(char *s, uint64 *val, unsigned int base, size_t len); +extern void _tarCreateHeader(char *header, + const char *filename, + const char *linktarget, + int64 filesize, int st_mode, + int st_uid, int st_gid, + time_t mtime); + #endif /* PG_PORT_H */ diff -durpN postgresql.2/src/port/Makefile postgresql.3/src/port/Makefile --- postgresql.2/src/port/Makefile 2012-05-09 12:28:11.755496856 +0200 +++ postgresql.3/src/port/Makefile 2012-11-20 17:30:06.199236922 +0100 @@ -32,7 +32,7 @@ LIBS += $(PTHREAD_LIBS) OBJS = $(LIBOBJS) chklocale.o dirmod.o erand48.o exec.o fls.o inet_net_ntop.o \ noblock.o path.o pgcheckdir.o pg_crc.o pgmkdirp.o pgsleep.o \ - pgstrcasecmp.o qsort.o qsort_arg.o sprompt.o thread.o + pgstrcasecmp.o qsort.o qsort_arg.o sprompt.o thread.o tarutil.o # foo_srv.o and foo.o are both built from foo.c, but only foo.o has -DFRONTEND OBJS_SRV = $(OBJS:%.o=%_srv.o) diff -durpN postgresql.2/src/port/tarutil.c postgresql.3/src/port/tarutil.c --- postgresql.2/src/port/tarutil.c 1970-01-01 01:00:00.000000000 +0100 +++ postgresql.3/src/port/tarutil.c 2012-11-20 19:59:46.832342223 +0100 @@ -0,0 +1,174 @@ +/*------------------------------------------------------------------------- + * + * tarutil.c + * common functions for handling the TAR format + * + * IDENTIFICATION + * src/port/tarutil.c + * + *------------------------------------------------------------------------- + */ +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include + +int +_tarChecksum(char *header) +{ + int i, + sum; + + /* + * Per POSIX, the checksum is the simple sum of all bytes in the header, + * treating the bytes as unsigned, and treating the checksum field (at + * offset 148) as though it contained 8 spaces. + */ + sum = 8 * ' '; /* presumed value for checksum field */ + for (i = 0; i < TARCHUNKSZ; i++) + if (i < 148 || i >= 156) + sum += 0xFF & header[i]; + return sum; +} + + +/* + * Utility routine to print possibly larger than 32 bit integers in a + * portable fashion. Filled with zeros. + */ +void +_tarPrintVal(char *s, uint64 val, unsigned int base, size_t len) +{ + int i; + + for (i = len; i > 0; i--) + { + int digit = val % base; + + s[i - 1] = '0' + digit; + val = val / base; + } +} + + +/* + * Inverse of _tarPrintVal() + */ +void +_tarScanVal(char *s, uint64 *val, unsigned int base, size_t len) +{ + uint64 tmp = 0; + int i; + + for (i = 0; i < len; i++) + { + int digit = s[i] - '0'; + + tmp = tmp * base + digit; + } + + *val = tmp; +} + + +void +_tarCreateHeader(char *header, const char *filename, + const char *linktarget, + int64 filesize, int st_mode, + int st_uid, int st_gid, + time_t mtime) +{ + /* + * 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 + * required bytes; that null goes into the first byte of the next field. + * This is okay as long as we fill the fields in order. + */ + memset(header, 0, TARCHUNKSZ /* sizeof the tar header */); + + /* Name 100 */ + sprintf(&header[0], "%.99s", filename); + if (linktarget != NULL || S_ISDIR(st_mode)) + { + /* + * We only support symbolic links to directories, and this is + * indicated in the tar format by adding a slash at the end of the + * name, the same as for regular directories. + */ + int flen = strlen(filename); + + flen = Min(flen, 99); + header[flen] = '/'; + header[flen + 1] = '\0'; + } + + /* Mode 8 */ + sprintf(&header[100], "%07o ", st_mode); + + /* User ID 8 */ + sprintf(&header[108], "%07o ", st_uid); + + /* Group 8 */ + sprintf(&header[116], "%07o ", st_gid); + + /* File size 12 - 11 digits, 1 space; use _tarPrintVal for 64 bit support */ + if (linktarget != NULL || S_ISDIR(st_mode)) + /* Symbolic link or directory has size zero */ + _tarPrintVal(&header[124], 0, 8, 11); + else + _tarPrintVal(&header[124], filesize, 8, 11); + sprintf(&header[135], " "); + + /* Mod Time 12 - 11 digits, 1 space; use _tarPrintVal for 64 bit support */ + _tarPrintVal(&header[136], mtime, 8, 11); + sprintf(&header[147], " "); + + /* Checksum 8 cannot be calculated until we've filled all other fields */ + + if (linktarget != NULL) + { + /* Type - Symbolic link */ + sprintf(&header[156], "2"); + /* Link Name 100 */ + sprintf(&header[157], "%.99s", linktarget); + } + else if (S_ISDIR(st_mode)) + /* Type - directory */ + sprintf(&header[156], "5"); + else + /* Type - regular file */ + sprintf(&header[156], "0"); + + /* Magic 6 */ + sprintf(&header[257], "ustar"); + + /* Version 2 */ + sprintf(&header[263], "00"); + + /* User 32 */ + /* XXX: Do we need to care about setting correct username? */ + sprintf(&header[265], "%.31s", "postgres"); + + /* Group 32 */ + /* XXX: Do we need to care about setting correct group name? */ + sprintf(&header[297], "%.31s", "postgres"); + + /* Major Dev 8 */ + sprintf(&header[329], "%07o ", 0); + + /* Minor Dev 8 */ + sprintf(&header[337], "%07o ", 0); + + /* Prefix 155 - not used, leave as nulls */ + + /* + * We mustn't overwrite the next field while inserting the checksum. + * Fortunately, the checksum can't exceed 6 octal digits, so we just write + * 6 digits, a space, and a null, which is legal per POSIX. + */ + sprintf(&header[148], "%06o ", _tarChecksum(header)); +} +