Clean up error handling in pg_basebackup's walmethods.c.
The error handling here was a mess, as a result of a fundamentally bad design (relying on errno to keep its value much longer than is safe to assume) as well as a lot of just plain sloppiness, both as to noticing errors at all and as to reporting the correct errno. Moreover, the recent addition of LZ4 compression broke things completely, because liblz4 doesn't use errno to report errors. To improve matters, keep the error state in the DirectoryMethodData or TarMethodData struct, and add a string field so we can handle cases that don't set errno. (The tar methods already had a version of this, but it can be done more efficiently since all these cases use a constant error string.) Make the dir and tar methods handle errors in basically identical ways, which they didn't before. This requires copying errno into the state struct in a lot of places, which is a bit tedious, but it has the virtue that we can get rid of ad-hoc code to save and restore errno in a number of places ... not to mention that it fixes other places that should've saved/restored errno but neglected to. In passing, fix some pointlessly static buffers to be ordinary local variables. There remains an issue about exactly how to handle errors from fsync(), but that seems like material for its own patch. While the LZ4 problems are new, all the rest of this is fixes for old bugs, so backpatch to v10 where walmethods.c was introduced. Patch by me; thanks to Michael Paquier for review. Discussion: https://postgr.es/m/1343113.1636489231@sss.pgh.pa.us
This commit is contained in:
parent
bbda88c338
commit
c8b5221b57
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include "common/file_perm.h"
|
#include "common/file_perm.h"
|
||||||
#include "common/file_utils.h"
|
#include "common/file_utils.h"
|
||||||
|
#include "common/logging.h"
|
||||||
#include "pgtar.h"
|
#include "pgtar.h"
|
||||||
#include "receivelog.h"
|
#include "receivelog.h"
|
||||||
#include "streamutil.h"
|
#include "streamutil.h"
|
||||||
@ -43,6 +44,8 @@ typedef struct DirectoryMethodData
|
|||||||
char *basedir;
|
char *basedir;
|
||||||
int compression;
|
int compression;
|
||||||
bool sync;
|
bool sync;
|
||||||
|
const char *lasterrstring; /* if set, takes precedence over lasterrno */
|
||||||
|
int lasterrno;
|
||||||
} DirectoryMethodData;
|
} DirectoryMethodData;
|
||||||
static DirectoryMethodData *dir_data = NULL;
|
static DirectoryMethodData *dir_data = NULL;
|
||||||
|
|
||||||
@ -61,11 +64,17 @@ typedef struct DirectoryMethodFile
|
|||||||
#endif
|
#endif
|
||||||
} DirectoryMethodFile;
|
} DirectoryMethodFile;
|
||||||
|
|
||||||
|
#define dir_clear_error() \
|
||||||
|
(dir_data->lasterrstring = NULL, dir_data->lasterrno = 0)
|
||||||
|
#define dir_set_error(msg) \
|
||||||
|
(dir_data->lasterrstring = _(msg))
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
dir_getlasterror(void)
|
dir_getlasterror(void)
|
||||||
{
|
{
|
||||||
/* Directory method always sets errno, so just use strerror */
|
if (dir_data->lasterrstring)
|
||||||
return strerror(errno);
|
return dir_data->lasterrstring;
|
||||||
|
return strerror(dir_data->lasterrno);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
@ -83,7 +92,7 @@ dir_get_file_name(const char *pathname, const char *temp_suffix)
|
|||||||
static Walfile
|
static Walfile
|
||||||
dir_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_size)
|
dir_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_size)
|
||||||
{
|
{
|
||||||
static char tmppath[MAXPGPATH];
|
char tmppath[MAXPGPATH];
|
||||||
char *filename;
|
char *filename;
|
||||||
int fd;
|
int fd;
|
||||||
DirectoryMethodFile *f;
|
DirectoryMethodFile *f;
|
||||||
@ -91,6 +100,8 @@ dir_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_
|
|||||||
gzFile gzfp = NULL;
|
gzFile gzfp = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
dir_clear_error();
|
||||||
|
|
||||||
filename = dir_get_file_name(pathname, temp_suffix);
|
filename = dir_get_file_name(pathname, temp_suffix);
|
||||||
snprintf(tmppath, sizeof(tmppath), "%s/%s",
|
snprintf(tmppath, sizeof(tmppath), "%s/%s",
|
||||||
dir_data->basedir, filename);
|
dir_data->basedir, filename);
|
||||||
@ -104,7 +115,10 @@ dir_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_
|
|||||||
*/
|
*/
|
||||||
fd = open(tmppath, O_WRONLY | O_CREAT | PG_BINARY, pg_file_create_mode);
|
fd = open(tmppath, O_WRONLY | O_CREAT | PG_BINARY, pg_file_create_mode);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
dir_data->lasterrno = errno;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LIBZ
|
#ifdef HAVE_LIBZ
|
||||||
if (dir_data->compression > 0)
|
if (dir_data->compression > 0)
|
||||||
@ -112,6 +126,7 @@ dir_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_
|
|||||||
gzfp = gzdopen(fd, "wb");
|
gzfp = gzdopen(fd, "wb");
|
||||||
if (gzfp == NULL)
|
if (gzfp == NULL)
|
||||||
{
|
{
|
||||||
|
dir_data->lasterrno = errno;
|
||||||
close(fd);
|
close(fd);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -119,6 +134,7 @@ dir_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_
|
|||||||
if (gzsetparams(gzfp, dir_data->compression,
|
if (gzsetparams(gzfp, dir_data->compression,
|
||||||
Z_DEFAULT_STRATEGY) != Z_OK)
|
Z_DEFAULT_STRATEGY) != Z_OK)
|
||||||
{
|
{
|
||||||
|
dir_data->lasterrno = errno;
|
||||||
gzclose(gzfp);
|
gzclose(gzfp);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -137,24 +153,17 @@ dir_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_
|
|||||||
errno = 0;
|
errno = 0;
|
||||||
if (write(fd, zerobuf.data, XLOG_BLCKSZ) != XLOG_BLCKSZ)
|
if (write(fd, zerobuf.data, XLOG_BLCKSZ) != XLOG_BLCKSZ)
|
||||||
{
|
{
|
||||||
int save_errno = errno;
|
/* If write didn't set errno, assume problem is no disk space */
|
||||||
|
dir_data->lasterrno = errno ? errno : ENOSPC;
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
/*
|
|
||||||
* If write didn't set errno, assume problem is no disk space.
|
|
||||||
*/
|
|
||||||
errno = save_errno ? save_errno : ENOSPC;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lseek(fd, 0, SEEK_SET) != 0)
|
if (lseek(fd, 0, SEEK_SET) != 0)
|
||||||
{
|
{
|
||||||
int save_errno = errno;
|
dir_data->lasterrno = errno;
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
errno = save_errno;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -170,6 +179,7 @@ dir_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_
|
|||||||
if (fsync_fname(tmppath, false) != 0 ||
|
if (fsync_fname(tmppath, false) != 0 ||
|
||||||
fsync_parent_path(tmppath) != 0)
|
fsync_parent_path(tmppath) != 0)
|
||||||
{
|
{
|
||||||
|
dir_data->lasterrno = errno;
|
||||||
#ifdef HAVE_LIBZ
|
#ifdef HAVE_LIBZ
|
||||||
if (dir_data->compression > 0)
|
if (dir_data->compression > 0)
|
||||||
gzclose(gzfp);
|
gzclose(gzfp);
|
||||||
@ -202,13 +212,30 @@ dir_write(Walfile f, const void *buf, size_t count)
|
|||||||
DirectoryMethodFile *df = (DirectoryMethodFile *) f;
|
DirectoryMethodFile *df = (DirectoryMethodFile *) f;
|
||||||
|
|
||||||
Assert(f != NULL);
|
Assert(f != NULL);
|
||||||
|
dir_clear_error();
|
||||||
|
|
||||||
#ifdef HAVE_LIBZ
|
#ifdef HAVE_LIBZ
|
||||||
if (dir_data->compression > 0)
|
if (dir_data->compression > 0)
|
||||||
|
{
|
||||||
|
errno = 0;
|
||||||
r = (ssize_t) gzwrite(df->gzfp, buf, count);
|
r = (ssize_t) gzwrite(df->gzfp, buf, count);
|
||||||
|
if (r != count)
|
||||||
|
{
|
||||||
|
/* If write didn't set errno, assume problem is no disk space */
|
||||||
|
dir_data->lasterrno = errno ? errno : ENOSPC;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
|
errno = 0;
|
||||||
r = write(df->fd, buf, count);
|
r = write(df->fd, buf, count);
|
||||||
|
if (r != count)
|
||||||
|
{
|
||||||
|
/* If write didn't set errno, assume problem is no disk space */
|
||||||
|
dir_data->lasterrno = errno ? errno : ENOSPC;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (r > 0)
|
if (r > 0)
|
||||||
df->currpos += r;
|
df->currpos += r;
|
||||||
return r;
|
return r;
|
||||||
@ -218,6 +245,7 @@ static off_t
|
|||||||
dir_get_current_pos(Walfile f)
|
dir_get_current_pos(Walfile f)
|
||||||
{
|
{
|
||||||
Assert(f != NULL);
|
Assert(f != NULL);
|
||||||
|
dir_clear_error();
|
||||||
|
|
||||||
/* Use a cached value to prevent lots of reseeks */
|
/* Use a cached value to prevent lots of reseeks */
|
||||||
return ((DirectoryMethodFile *) f)->currpos;
|
return ((DirectoryMethodFile *) f)->currpos;
|
||||||
@ -228,10 +256,11 @@ dir_close(Walfile f, WalCloseMethod method)
|
|||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
DirectoryMethodFile *df = (DirectoryMethodFile *) f;
|
DirectoryMethodFile *df = (DirectoryMethodFile *) f;
|
||||||
static char tmppath[MAXPGPATH];
|
char tmppath[MAXPGPATH];
|
||||||
static char tmppath2[MAXPGPATH];
|
char tmppath2[MAXPGPATH];
|
||||||
|
|
||||||
Assert(f != NULL);
|
Assert(f != NULL);
|
||||||
|
dir_clear_error();
|
||||||
|
|
||||||
#ifdef HAVE_LIBZ
|
#ifdef HAVE_LIBZ
|
||||||
if (dir_data->compression > 0)
|
if (dir_data->compression > 0)
|
||||||
@ -294,6 +323,9 @@ dir_close(Walfile f, WalCloseMethod method)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (r != 0)
|
||||||
|
dir_data->lasterrno = errno;
|
||||||
|
|
||||||
pg_free(df->pathname);
|
pg_free(df->pathname);
|
||||||
pg_free(df->fullpath);
|
pg_free(df->fullpath);
|
||||||
if (df->temp_suffix)
|
if (df->temp_suffix)
|
||||||
@ -306,7 +338,10 @@ dir_close(Walfile f, WalCloseMethod method)
|
|||||||
static int
|
static int
|
||||||
dir_sync(Walfile f)
|
dir_sync(Walfile f)
|
||||||
{
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
Assert(f != NULL);
|
Assert(f != NULL);
|
||||||
|
dir_clear_error();
|
||||||
|
|
||||||
if (!dir_data->sync)
|
if (!dir_data->sync)
|
||||||
return 0;
|
return 0;
|
||||||
@ -315,24 +350,33 @@ dir_sync(Walfile f)
|
|||||||
if (dir_data->compression > 0)
|
if (dir_data->compression > 0)
|
||||||
{
|
{
|
||||||
if (gzflush(((DirectoryMethodFile *) f)->gzfp, Z_SYNC_FLUSH) != Z_OK)
|
if (gzflush(((DirectoryMethodFile *) f)->gzfp, Z_SYNC_FLUSH) != Z_OK)
|
||||||
|
{
|
||||||
|
dir_data->lasterrno = errno;
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return fsync(((DirectoryMethodFile *) f)->fd);
|
r = fsync(((DirectoryMethodFile *) f)->fd);
|
||||||
|
if (r < 0)
|
||||||
|
dir_data->lasterrno = errno;
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
dir_get_file_size(const char *pathname)
|
dir_get_file_size(const char *pathname)
|
||||||
{
|
{
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
static char tmppath[MAXPGPATH];
|
char tmppath[MAXPGPATH];
|
||||||
|
|
||||||
snprintf(tmppath, sizeof(tmppath), "%s/%s",
|
snprintf(tmppath, sizeof(tmppath), "%s/%s",
|
||||||
dir_data->basedir, pathname);
|
dir_data->basedir, pathname);
|
||||||
|
|
||||||
if (stat(tmppath, &statbuf) != 0)
|
if (stat(tmppath, &statbuf) != 0)
|
||||||
|
{
|
||||||
|
dir_data->lasterrno = errno;
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return statbuf.st_size;
|
return statbuf.st_size;
|
||||||
}
|
}
|
||||||
@ -346,9 +390,11 @@ dir_compression(void)
|
|||||||
static bool
|
static bool
|
||||||
dir_existsfile(const char *pathname)
|
dir_existsfile(const char *pathname)
|
||||||
{
|
{
|
||||||
static char tmppath[MAXPGPATH];
|
char tmppath[MAXPGPATH];
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
|
dir_clear_error();
|
||||||
|
|
||||||
snprintf(tmppath, sizeof(tmppath), "%s/%s",
|
snprintf(tmppath, sizeof(tmppath), "%s/%s",
|
||||||
dir_data->basedir, pathname);
|
dir_data->basedir, pathname);
|
||||||
|
|
||||||
@ -362,6 +408,8 @@ dir_existsfile(const char *pathname)
|
|||||||
static bool
|
static bool
|
||||||
dir_finish(void)
|
dir_finish(void)
|
||||||
{
|
{
|
||||||
|
dir_clear_error();
|
||||||
|
|
||||||
if (dir_data->sync)
|
if (dir_data->sync)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -369,7 +417,10 @@ dir_finish(void)
|
|||||||
* directory entry here as well.
|
* directory entry here as well.
|
||||||
*/
|
*/
|
||||||
if (fsync_fname(dir_data->basedir, true) != 0)
|
if (fsync_fname(dir_data->basedir, true) != 0)
|
||||||
|
{
|
||||||
|
dir_data->lasterrno = errno;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -406,6 +457,7 @@ FreeWalDirectoryMethod(void)
|
|||||||
{
|
{
|
||||||
pg_free(dir_data->basedir);
|
pg_free(dir_data->basedir);
|
||||||
pg_free(dir_data);
|
pg_free(dir_data);
|
||||||
|
dir_data = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -430,7 +482,8 @@ typedef struct TarMethodData
|
|||||||
int compression;
|
int compression;
|
||||||
bool sync;
|
bool sync;
|
||||||
TarMethodFile *currentfile;
|
TarMethodFile *currentfile;
|
||||||
char lasterror[1024];
|
const char *lasterrstring; /* if set, takes precedence over lasterrno */
|
||||||
|
int lasterrno;
|
||||||
#ifdef HAVE_LIBZ
|
#ifdef HAVE_LIBZ
|
||||||
z_streamp zp;
|
z_streamp zp;
|
||||||
void *zlibOut;
|
void *zlibOut;
|
||||||
@ -438,19 +491,17 @@ typedef struct TarMethodData
|
|||||||
} TarMethodData;
|
} TarMethodData;
|
||||||
static TarMethodData *tar_data = NULL;
|
static TarMethodData *tar_data = NULL;
|
||||||
|
|
||||||
#define tar_clear_error() tar_data->lasterror[0] = '\0'
|
#define tar_clear_error() \
|
||||||
#define tar_set_error(msg) strlcpy(tar_data->lasterror, _(msg), sizeof(tar_data->lasterror))
|
(tar_data->lasterrstring = NULL, tar_data->lasterrno = 0)
|
||||||
|
#define tar_set_error(msg) \
|
||||||
|
(tar_data->lasterrstring = _(msg))
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
tar_getlasterror(void)
|
tar_getlasterror(void)
|
||||||
{
|
{
|
||||||
/*
|
if (tar_data->lasterrstring)
|
||||||
* If a custom error is set, return that one. Otherwise, assume errno is
|
return tar_data->lasterrstring;
|
||||||
* set and return that one.
|
return strerror(tar_data->lasterrno);
|
||||||
*/
|
|
||||||
if (tar_data->lasterror[0])
|
|
||||||
return tar_data->lasterror;
|
|
||||||
return strerror(errno);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LIBZ
|
#ifdef HAVE_LIBZ
|
||||||
@ -478,11 +529,8 @@ tar_write_compressed_data(void *buf, size_t count, bool flush)
|
|||||||
errno = 0;
|
errno = 0;
|
||||||
if (write(tar_data->fd, tar_data->zlibOut, len) != len)
|
if (write(tar_data->fd, tar_data->zlibOut, len) != len)
|
||||||
{
|
{
|
||||||
/*
|
/* If write didn't set errno, assume problem is no disk space */
|
||||||
* If write didn't set errno, assume problem is no disk space.
|
tar_data->lasterrno = errno ? errno : ENOSPC;
|
||||||
*/
|
|
||||||
if (errno == 0)
|
|
||||||
errno = ENOSPC;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -519,9 +567,15 @@ tar_write(Walfile f, const void *buf, size_t count)
|
|||||||
/* Tarfile will always be positioned at the end */
|
/* Tarfile will always be positioned at the end */
|
||||||
if (!tar_data->compression)
|
if (!tar_data->compression)
|
||||||
{
|
{
|
||||||
|
errno = 0;
|
||||||
r = write(tar_data->fd, buf, count);
|
r = write(tar_data->fd, buf, count);
|
||||||
if (r > 0)
|
if (r != count)
|
||||||
((TarMethodFile *) f)->currpos += r;
|
{
|
||||||
|
/* If write didn't set errno, assume problem is no disk space */
|
||||||
|
tar_data->lasterrno = errno ? errno : ENOSPC;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
((TarMethodFile *) f)->currpos += r;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
#ifdef HAVE_LIBZ
|
#ifdef HAVE_LIBZ
|
||||||
@ -534,8 +588,11 @@ tar_write(Walfile f, const void *buf, size_t count)
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
else
|
else
|
||||||
|
{
|
||||||
/* Can't happen - compression enabled with no libz */
|
/* Can't happen - compression enabled with no libz */
|
||||||
|
tar_data->lasterrno = ENOSYS;
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -573,7 +630,6 @@ tar_get_file_name(const char *pathname, const char *temp_suffix)
|
|||||||
static Walfile
|
static Walfile
|
||||||
tar_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_size)
|
tar_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_size)
|
||||||
{
|
{
|
||||||
int save_errno;
|
|
||||||
char *tmppath;
|
char *tmppath;
|
||||||
|
|
||||||
tar_clear_error();
|
tar_clear_error();
|
||||||
@ -587,7 +643,10 @@ tar_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_
|
|||||||
O_WRONLY | O_CREAT | PG_BINARY,
|
O_WRONLY | O_CREAT | PG_BINARY,
|
||||||
pg_file_create_mode);
|
pg_file_create_mode);
|
||||||
if (tar_data->fd < 0)
|
if (tar_data->fd < 0)
|
||||||
|
{
|
||||||
|
tar_data->lasterrno = errno;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LIBZ
|
#ifdef HAVE_LIBZ
|
||||||
if (tar_data->compression)
|
if (tar_data->compression)
|
||||||
@ -617,7 +676,6 @@ tar_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_
|
|||||||
/* There's no tar header itself, the file starts with regular files */
|
/* There's no tar header itself, the file starts with regular files */
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert(tar_data->currentfile == NULL);
|
|
||||||
if (tar_data->currentfile != NULL)
|
if (tar_data->currentfile != NULL)
|
||||||
{
|
{
|
||||||
tar_set_error("implementation error: tar files can't have more than one open file");
|
tar_set_error("implementation error: tar files can't have more than one open file");
|
||||||
@ -659,10 +717,9 @@ tar_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_
|
|||||||
tar_data->currentfile->ofs_start = lseek(tar_data->fd, 0, SEEK_CUR);
|
tar_data->currentfile->ofs_start = lseek(tar_data->fd, 0, SEEK_CUR);
|
||||||
if (tar_data->currentfile->ofs_start == -1)
|
if (tar_data->currentfile->ofs_start == -1)
|
||||||
{
|
{
|
||||||
save_errno = errno;
|
tar_data->lasterrno = errno;
|
||||||
pg_free(tar_data->currentfile);
|
pg_free(tar_data->currentfile);
|
||||||
tar_data->currentfile = NULL;
|
tar_data->currentfile = NULL;
|
||||||
errno = save_errno;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
tar_data->currentfile->currpos = 0;
|
tar_data->currentfile->currpos = 0;
|
||||||
@ -672,11 +729,10 @@ tar_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_
|
|||||||
errno = 0;
|
errno = 0;
|
||||||
if (write(tar_data->fd, tar_data->currentfile->header, 512) != 512)
|
if (write(tar_data->fd, tar_data->currentfile->header, 512) != 512)
|
||||||
{
|
{
|
||||||
save_errno = errno;
|
/* If write didn't set errno, assume problem is no disk space */
|
||||||
|
tar_data->lasterrno = errno ? errno : ENOSPC;
|
||||||
pg_free(tar_data->currentfile);
|
pg_free(tar_data->currentfile);
|
||||||
tar_data->currentfile = NULL;
|
tar_data->currentfile = NULL;
|
||||||
/* if write didn't set errno, assume problem is no disk space */
|
|
||||||
errno = save_errno ? save_errno : ENOSPC;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -708,10 +764,16 @@ tar_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_
|
|||||||
if (!tar_data->compression)
|
if (!tar_data->compression)
|
||||||
{
|
{
|
||||||
/* Uncompressed, so pad now */
|
/* Uncompressed, so pad now */
|
||||||
tar_write_padding_data(tar_data->currentfile, pad_to_size);
|
if (!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)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
/* Seek back to start */
|
||||||
|
if (lseek(tar_data->fd,
|
||||||
|
tar_data->currentfile->ofs_start + 512,
|
||||||
|
SEEK_SET) != tar_data->currentfile->ofs_start + 512)
|
||||||
|
{
|
||||||
|
tar_data->lasterrno = errno;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
tar_data->currentfile->currpos = 0;
|
tar_data->currentfile->currpos = 0;
|
||||||
}
|
}
|
||||||
@ -726,7 +788,7 @@ tar_get_file_size(const char *pathname)
|
|||||||
tar_clear_error();
|
tar_clear_error();
|
||||||
|
|
||||||
/* Currently not used, so not supported */
|
/* Currently not used, so not supported */
|
||||||
errno = ENOSYS;
|
tar_data->lasterrno = ENOSYS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -748,6 +810,8 @@ tar_get_current_pos(Walfile f)
|
|||||||
static int
|
static int
|
||||||
tar_sync(Walfile f)
|
tar_sync(Walfile f)
|
||||||
{
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
Assert(f != NULL);
|
Assert(f != NULL);
|
||||||
tar_clear_error();
|
tar_clear_error();
|
||||||
|
|
||||||
@ -761,7 +825,10 @@ tar_sync(Walfile f)
|
|||||||
if (tar_data->compression)
|
if (tar_data->compression)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return fsync(tar_data->fd);
|
r = fsync(tar_data->fd);
|
||||||
|
if (r < 0)
|
||||||
|
tar_data->lasterrno = errno;
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -788,7 +855,10 @@ tar_close(Walfile f, WalCloseMethod method)
|
|||||||
* allow writing of the very last file.
|
* allow writing of the very last file.
|
||||||
*/
|
*/
|
||||||
if (ftruncate(tar_data->fd, tf->ofs_start) != 0)
|
if (ftruncate(tar_data->fd, tf->ofs_start) != 0)
|
||||||
|
{
|
||||||
|
tar_data->lasterrno = errno;
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
pg_free(tf->pathname);
|
pg_free(tf->pathname);
|
||||||
pg_free(tf);
|
pg_free(tf);
|
||||||
@ -849,10 +919,7 @@ tar_close(Walfile f, WalCloseMethod method)
|
|||||||
{
|
{
|
||||||
/* Flush the current buffer */
|
/* Flush the current buffer */
|
||||||
if (!tar_write_compressed_data(NULL, 0, true))
|
if (!tar_write_compressed_data(NULL, 0, true))
|
||||||
{
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -873,15 +940,17 @@ tar_close(Walfile f, WalCloseMethod method)
|
|||||||
|
|
||||||
print_tar_number(&(tf->header[148]), 8, tarChecksum(((TarMethodFile *) f)->header));
|
print_tar_number(&(tf->header[148]), 8, tarChecksum(((TarMethodFile *) f)->header));
|
||||||
if (lseek(tar_data->fd, tf->ofs_start, SEEK_SET) != ((TarMethodFile *) f)->ofs_start)
|
if (lseek(tar_data->fd, tf->ofs_start, SEEK_SET) != ((TarMethodFile *) f)->ofs_start)
|
||||||
|
{
|
||||||
|
tar_data->lasterrno = errno;
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
if (!tar_data->compression)
|
if (!tar_data->compression)
|
||||||
{
|
{
|
||||||
errno = 0;
|
errno = 0;
|
||||||
if (write(tar_data->fd, tf->header, 512) != 512)
|
if (write(tar_data->fd, tf->header, 512) != 512)
|
||||||
{
|
{
|
||||||
/* if write didn't set errno, assume problem is no disk space */
|
/* If write didn't set errno, assume problem is no disk space */
|
||||||
if (errno == 0)
|
tar_data->lasterrno = errno ? errno : ENOSPC;
|
||||||
errno = ENOSPC;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -910,11 +979,19 @@ tar_close(Walfile f, WalCloseMethod method)
|
|||||||
|
|
||||||
/* Move file pointer back down to end, so we can write the next file */
|
/* Move file pointer back down to end, so we can write the next file */
|
||||||
if (lseek(tar_data->fd, 0, SEEK_END) < 0)
|
if (lseek(tar_data->fd, 0, SEEK_END) < 0)
|
||||||
|
{
|
||||||
|
tar_data->lasterrno = errno;
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Always fsync on close, so the padding gets fsynced */
|
/* Always fsync on close, so the padding gets fsynced */
|
||||||
if (tar_sync(f) < 0)
|
if (tar_sync(f) < 0)
|
||||||
|
{
|
||||||
|
/* XXX this seems pretty bogus; why is only this case fatal? */
|
||||||
|
pg_log_fatal("could not fsync file \"%s\": %s",
|
||||||
|
tf->pathname, tar_getlasterror());
|
||||||
exit(1);
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Clean up and done */
|
/* Clean up and done */
|
||||||
pg_free(tf->pathname);
|
pg_free(tf->pathname);
|
||||||
@ -952,9 +1029,8 @@ tar_finish(void)
|
|||||||
errno = 0;
|
errno = 0;
|
||||||
if (write(tar_data->fd, zerobuf, sizeof(zerobuf)) != sizeof(zerobuf))
|
if (write(tar_data->fd, zerobuf, sizeof(zerobuf)) != sizeof(zerobuf))
|
||||||
{
|
{
|
||||||
/* if write didn't set errno, assume problem is no disk space */
|
/* If write didn't set errno, assume problem is no disk space */
|
||||||
if (errno == 0)
|
tar_data->lasterrno = errno ? errno : ENOSPC;
|
||||||
errno = ENOSPC;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -989,8 +1065,7 @@ tar_finish(void)
|
|||||||
* If write didn't set errno, assume problem is no disk
|
* If write didn't set errno, assume problem is no disk
|
||||||
* space.
|
* space.
|
||||||
*/
|
*/
|
||||||
if (errno == 0)
|
tar_data->lasterrno = errno ? errno : ENOSPC;
|
||||||
errno = ENOSPC;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1010,20 +1085,28 @@ tar_finish(void)
|
|||||||
if (tar_data->sync)
|
if (tar_data->sync)
|
||||||
{
|
{
|
||||||
if (fsync(tar_data->fd) != 0)
|
if (fsync(tar_data->fd) != 0)
|
||||||
|
{
|
||||||
|
tar_data->lasterrno = errno;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (close(tar_data->fd) != 0)
|
if (close(tar_data->fd) != 0)
|
||||||
|
{
|
||||||
|
tar_data->lasterrno = errno;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
tar_data->fd = -1;
|
tar_data->fd = -1;
|
||||||
|
|
||||||
if (tar_data->sync)
|
if (tar_data->sync)
|
||||||
{
|
{
|
||||||
if (fsync_fname(tar_data->tarfilename, false) != 0)
|
if (fsync_fname(tar_data->tarfilename, false) != 0 ||
|
||||||
return false;
|
fsync_parent_path(tar_data->tarfilename) != 0)
|
||||||
if (fsync_parent_path(tar_data->tarfilename) != 0)
|
{
|
||||||
|
tar_data->lasterrno = errno;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -1071,4 +1154,5 @@ FreeWalTarMethod(void)
|
|||||||
pg_free(tar_data->zlibOut);
|
pg_free(tar_data->zlibOut);
|
||||||
#endif
|
#endif
|
||||||
pg_free(tar_data);
|
pg_free(tar_data);
|
||||||
|
tar_data = NULL;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user