errmsg("unexpected WAL file size \"%s\"", walFileName)));
}
- /* wal_segment_size is a multiple of 512, so no need for padding */
+ /*
+ * wal_segment_size is a multiple of TAR_BLOCK_SIZE, so no need
+ * for padding.
+ */
+ Assert(wal_segment_size % TAR_BLOCK_SIZE == 0);
FreeFile(fp);
pq_putmessage('d', content, len);
update_basebackup_progress(len);
- /* Pad to 512 byte boundary, per tar format requirements */
- pad = ((len + 511) & ~511) - len;
+ /* Pad to a multiple of the tar block size. */
+ pad = tarPaddingBytesRequired(len);
if (pad > 0)
{
- char buf[512];
+ char buf[TAR_BLOCK_SIZE];
MemSet(buf, 0, pad);
pq_putmessage('d', buf, pad);
if (sent || sizeonly)
{
- /* Add size, rounded up to 512byte block */
- size += ((statbuf.st_size + 511) & ~511);
- size += 512; /* Size of the header of the file */
+ /* Add size. */
+ size += statbuf.st_size;
+
+ /* Pad to a multiple of the tar block size. */
+ size += tarPaddingBytesRequired(statbuf.st_size);
+
+ /* Size of the header for the file. */
+ size += TAR_BLOCK_SIZE;
}
}
else
}
/*
- * Pad to 512 byte boundary, per tar format requirements. (This small
+ * Pad to a block boundary, per tar format requirements. (This small
* piece of data is probably not worth throttling, and is not checksummed
* because it's not actually part of the file.)
*/
- pad = ((len + 511) & ~511) - len;
+ pad = tarPaddingBytesRequired(len);
if (pad > 0)
{
MemSet(buf, 0, pad);
_tarWriteHeader(const char *filename, const char *linktarget,
struct stat *statbuf, bool sizeonly)
{
- char h[512];
+ char h[TAR_BLOCK_SIZE];
enum tarError rc;
if (!sizeonly)
int tablespacenum;
char filename[MAXPGPATH];
FILE *tarfile;
- char tarhdr[512];
+ char tarhdr[TAR_BLOCK_SIZE];
bool basetablespace;
bool in_tarhdr;
bool skip_file;
static void
ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
{
- char zerobuf[1024];
+ char zerobuf[TAR_BLOCK_SIZE * 2];
WriteTarState state;
memset(&state, 0, sizeof(state));
if (state.basetablespace && writerecoveryconf)
{
- char header[512];
+ char header[TAR_BLOCK_SIZE];
/*
* If postgresql.auto.conf has not been found in the streamed data,
pg_file_create_mode, 04000, 02000,
time(NULL));
- padding = ((recoveryconfcontents->len + 511) & ~511) - recoveryconfcontents->len;
+ padding = tarPaddingBytesRequired(recoveryconfcontents->len);
writeTarData(&state, header, sizeof(header));
writeTarData(&state, recoveryconfcontents->data,
*/
if (strcmp(basedir, "-") == 0 && manifest)
{
- char header[512];
+ char header[TAR_BLOCK_SIZE];
PQExpBufferData buf;
initPQExpBuffer(&buf);
termPQExpBuffer(&buf);
}
- /* 2 * 512 bytes empty data at end of file */
+ /* 2 * TAR_BLOCK_SIZE bytes empty data at end of file */
writeTarData(&state, zerobuf, sizeof(zerobuf));
#ifdef HAVE_LIBZ
*
* To do this, we have to process the individual files inside the TAR
* stream. The stream consists of a header and zero or more chunks,
- * all 512 bytes long. The stream from the server is broken up into
- * smaller pieces, so we have to track the size of the files to find
- * the next header structure.
+ * each with a length equal to TAR_BLOCK_SIZE. The stream from the
+ * server is broken up into smaller pieces, so we have to track the
+ * size of the files to find the next header structure.
*/
int rr = r;
int pos = 0;
* We're currently reading a header structure inside the TAR
* stream, i.e. the file metadata.
*/
- if (state->tarhdrsz < 512)
+ if (state->tarhdrsz < TAR_BLOCK_SIZE)
{
/*
* Copy the header structure into tarhdr in case the
- * header is not aligned to 512 bytes or it's not returned
- * in whole by the last PQgetCopyData call.
+ * header is not aligned properly or it's not returned in
+ * whole by the last PQgetCopyData call.
*/
int hdrleft;
int bytes2copy;
- hdrleft = 512 - state->tarhdrsz;
+ hdrleft = TAR_BLOCK_SIZE - state->tarhdrsz;
bytes2copy = (rr > hdrleft ? hdrleft : rr);
memcpy(&state->tarhdr[state->tarhdrsz], copybuf + pos,
state->filesz = read_tar_number(&state->tarhdr[124], 12);
state->file_padding_len =
- ((state->filesz + 511) & ~511) - state->filesz;
+ tarPaddingBytesRequired(state->filesz);
if (state->is_recovery_guc_supported &&
state->is_postgresql_auto_conf &&
writerecoveryconf)
{
/* replace tar header */
- char header[512];
+ char header[TAR_BLOCK_SIZE];
tarCreateHeader(header, "postgresql.auto.conf", NULL,
state->filesz + recoveryconfcontents->len,
* If we're not skipping the file, write the tar
* header unmodified.
*/
- writeTarData(state, state->tarhdr, 512);
+ writeTarData(state, state->tarhdr, TAR_BLOCK_SIZE);
}
}
int padding;
int tailsize;
- tailsize = (512 - state->file_padding_len) + recoveryconfcontents->len;
- padding = ((tailsize + 511) & ~511) - tailsize;
+ tailsize = (TAR_BLOCK_SIZE - state->file_padding_len) + recoveryconfcontents->len;
+ padding = tarPaddingBytesRequired(tailsize);
writeTarData(state, recoveryconfcontents->data,
recoveryconfcontents->len);
if (padding)
{
- char zerobuf[512];
+ char zerobuf[TAR_BLOCK_SIZE];
MemSet(zerobuf, 0, sizeof(zerobuf));
writeTarData(state, zerobuf, padding);
/*
* No current file, so this must be the header for a new file
*/
- if (r != 512)
+ if (r != TAR_BLOCK_SIZE)
{
pg_log_error("invalid tar block header size: %zu", r);
exit(1);
}
- totaldone += 512;
+ totaldone += TAR_BLOCK_SIZE;
state->current_len_left = read_tar_number(©buf[124], 12);
#endif
/*
- * All files are padded up to 512 bytes
+ * All files are padded up to a multiple of TAR_BLOCK_SIZE
*/
state->current_padding =
- ((state->current_len_left + 511) & ~511) - state->current_len_left;
+ tarPaddingBytesRequired(state->current_len_left);
/*
* First part of header is zero terminated filename
{
off_t ofs_start; /* Where does the *header* for this file start */
off_t currpos;
- char header[512];
+ char header[TAR_BLOCK_SIZE];
char *pathname;
size_t pad_to_size;
} TarMethodFile;
if (!tar_data->compression)
{
errno = 0;
- if (write(tar_data->fd, tar_data->currentfile->header, 512) != 512)
+ if (write(tar_data->fd, tar_data->currentfile->header,
+ TAR_BLOCK_SIZE) != TAR_BLOCK_SIZE)
{
save_errno = errno;
pg_free(tar_data->currentfile);
else
{
/* Write header through the zlib APIs but with no compression */
- if (!tar_write_compressed_data(tar_data->currentfile->header, 512, true))
+ if (!tar_write_compressed_data(tar_data->currentfile->header,
+ TAR_BLOCK_SIZE, true))
return NULL;
/* Re-enable compression for the rest of the file */
/* Uncompressed, so pad now */
tar_write_padding_data(tar_data->currentfile, pad_to_size);
/* Seek back to start */
- if (lseek(tar_data->fd, tar_data->currentfile->ofs_start + 512, SEEK_SET) != tar_data->currentfile->ofs_start + 512)
+ if (lseek(tar_data->fd,
+ tar_data->currentfile->ofs_start + TAR_BLOCK_SIZE,
+ SEEK_SET) != tar_data->currentfile->ofs_start + TAR_BLOCK_SIZE)
return NULL;
tar_data->currentfile->currpos = 0;
}
/*
- * Get the size of the file, and pad the current data up to the nearest
- * 512 byte boundary.
+ * Get the size of the file, and pad out to a multiple of the tar block
+ * size.
*/
filesize = tar_get_current_pos(f);
- padding = ((filesize + 511) & ~511) - filesize;
+ padding = tarPaddingBytesRequired(filesize);
if (padding)
{
- char zerobuf[512];
+ char zerobuf[TAR_BLOCK_SIZE];
MemSet(zerobuf, 0, padding);
if (tar_write(f, zerobuf, padding) != padding)
if (!tar_data->compression)
{
errno = 0;
- if (write(tar_data->fd, tf->header, 512) != 512)
+ if (write(tar_data->fd, tf->header, TAR_BLOCK_SIZE) != TAR_BLOCK_SIZE)
{
/* if write didn't set errno, assume problem is no disk space */
if (errno == 0)
}
/* Overwrite the header, assuming the size will be the same */
- if (!tar_write_compressed_data(tar_data->currentfile->header, 512, true))
+ if (!tar_write_compressed_data(tar_data->currentfile->header,
+ TAR_BLOCK_SIZE, true))
return -1;
/* Turn compression back on */
/*
* EOF marker for tar files is two blocks of NULLs.
*/
- for (i = 0; i < 512 * 2; i++)
+ for (i = 0; i < TAR_BLOCK_SIZE * 2; i++)
{
if (fputc(0, ctx->tarFH) == EOF)
WRITE_ERROR_EXIT;
buf1, buf2);
}
- pad = ((len + 511) & ~511) - len;
+ pad = tarPaddingBytesRequired(len);
for (i = 0; i < pad; i++)
{
if (fputc('\0', th->tarFH) == EOF)
lclContext *ctx = (lclContext *) AH->formatData;
TAR_MEMBER *th = pg_malloc0(sizeof(TAR_MEMBER));
char c;
- char header[512];
+ char header[TAR_BLOCK_SIZE];
size_t i,
len,
blks;
th->targetFile, filename);
/* Header doesn't match, so read to next header */
- len = ((th->fileLen + 511) & ~511); /* Padded length */
- blks = len >> 9; /* # of 512 byte blocks */
+ len = th->fileLen;
+ len += tarPaddingBytesRequired(th->fileLen);
+ blks = len / TAR_BLOCK_SIZE; /* # of tar blocks */
for (i = 0; i < blks; i++)
- _tarReadRaw(AH, &header[0], 512, NULL, ctx->tarFH);
+ _tarReadRaw(AH, &header[0], TAR_BLOCK_SIZE, NULL, ctx->tarFH);
if (!_tarGetHeader(AH, th))
fatal("could not find header for file \"%s\" in tar archive", filename);
}
- ctx->tarNextMember = ctx->tarFHpos + ((th->fileLen + 511) & ~511);
+ ctx->tarNextMember = ctx->tarFHpos + th->fileLen
+ + tarPaddingBytesRequired(th->fileLen);
th->pos = 0;
return th;
_tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
{
lclContext *ctx = (lclContext *) AH->formatData;
- char h[512];
+ char h[TAR_BLOCK_SIZE];
char tag[100 + 1];
int sum,
chk;
/* Save the pos for reporting purposes */
hPos = ctx->tarFHpos;
- /* Read a 512 byte block, return EOF, exit if short */
- len = _tarReadRaw(AH, h, 512, NULL, ctx->tarFH);
+ /* Read the next tar block, return EOF, exit if short */
+ len = _tarReadRaw(AH, h, TAR_BLOCK_SIZE, NULL, ctx->tarFH);
if (len == 0) /* EOF */
return 0;
- if (len != 512)
+ if (len != TAR_BLOCK_SIZE)
fatal(ngettext("incomplete tar header found (%lu byte)",
"incomplete tar header found (%lu bytes)",
len),
{
int i;
- for (i = 0; i < 512; i++)
+ for (i = 0; i < TAR_BLOCK_SIZE; i++)
{
if (h[i] != 0)
{
static void
_tarWriteHeader(TAR_MEMBER *th)
{
- char h[512];
+ char h[TAR_BLOCK_SIZE];
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)
+ if (fwrite(h, 1, TAR_BLOCK_SIZE, th->tarFH) != TAR_BLOCK_SIZE)
WRITE_ERROR_EXIT;
}
*
*-------------------------------------------------------------------------
*/
+#ifndef PG_TAR_H
+#define PG_TAR_H
+
+#define TAR_BLOCK_SIZE 512
enum tarError
{
TAR_SYMLINK_TOO_LONG
};
-extern enum tarError tarCreateHeader(char *h, const char *filename, const char *linktarget,
- pgoff_t size, mode_t mode, uid_t uid, gid_t gid, time_t mtime);
+extern enum tarError tarCreateHeader(char *h, const char *filename,
+ const char *linktarget, pgoff_t size,
+ mode_t mode, uid_t uid, gid_t gid,
+ time_t mtime);
extern uint64 read_tar_number(const char *s, int len);
extern void print_tar_number(char *s, int len, uint64 val);
extern int tarChecksum(char *header);
+
+/*
+ * Compute the number of padding bytes required for an entry in a tar
+ * archive. We must pad out to a multiple of TAR_BLOCK_SIZE. Since that's
+ * a power of 2, we can use TYPEALIGN().
+ */
+static inline size_t
+tarPaddingBytesRequired(size_t len)
+{
+ return TYPEALIGN(TAR_BLOCK_SIZE, len) - len;
+}
+
+#endif