diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index 046611c..c78566c 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -1503,6 +1503,49 @@ dump_lo_buf(ArchiveHandle *AH) AH->lo_buf_used = 0; } +/* + * ahwrite() blob writing helper + * handles blob output to the AH memory + * */ +static void write_blob(const void *ptr, size_t remaining, ArchiveHandle *AH) +{ + while (AH->lo_buf_used + remaining > AH->lo_buf_size) + { + size_t avail = AH->lo_buf_size - AH->lo_buf_used; + + memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, avail); + ptr = (const void *) ((const char *) ptr + avail); + remaining -= avail; + AH->lo_buf_used += avail; + dump_lo_buf(AH); + } + + memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, remaining); + AH->lo_buf_used += remaining; +} + +/* + * ahwrite() output helper + * handles write of the `nmbemb` units `size` bytes each + * returns actual written byte count + * */ +static size_t write_units(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH) +{ + if (AH->gzOut) + return GZWRITE(ptr, size, nmemb, AH->OF); + + if (AH->CustomOutPtr) + return AH->CustomOutPtr (AH, ptr, size * nmemb); + + /* + * If we're doing a restore, and it's direct to DB, and we're + * connected then send it to the DB. + */ + if (RestoringToDB(AH)) + return ExecuteSqlCommandBuf(AH, (const char *) ptr, size * nmemb); + + return fwrite(ptr, size, nmemb, AH->OF) * size; +} /* * Write buffer to the output file (usually stdout). This is used for @@ -1513,49 +1556,28 @@ dump_lo_buf(ArchiveHandle *AH) void ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH) { - int bytes_written = 0; - - if (AH->writingBlob) - { - size_t remaining = size * nmemb; + size_t bytes_written = 0; + size_t units_written = 0; + size_t write_attempts = 2; + size_t bytes_total = nmemb * size; - while (AH->lo_buf_used + remaining > AH->lo_buf_size) - { - size_t avail = AH->lo_buf_size - AH->lo_buf_used; - - memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, avail); - ptr = (const void *) ((const char *) ptr + avail); - remaining -= avail; - AH->lo_buf_used += avail; - dump_lo_buf(AH); - } + if(AH->writingBlob) + return write_blob(ptr, bytes_total, AH); - memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, remaining); - AH->lo_buf_used += remaining; + do{ + bytes_written += write_units((uint8_t*)ptr + bytes_written, size, nmemb - units_written, AH); - bytes_written = size * nmemb; - } - else if (AH->gzOut) - bytes_written = GZWRITE(ptr, size, nmemb, AH->OF); - else if (AH->CustomOutPtr) - bytes_written = AH->CustomOutPtr (AH, ptr, size * nmemb); - - else - { - /* - * If we're doing a restore, and it's direct to DB, and we're - * connected then send it to the DB. - */ - if (RestoringToDB(AH)) - bytes_written = ExecuteSqlCommandBuf(AH, (const char *) ptr, size * nmemb); - else - bytes_written = fwrite(ptr, size, nmemb, AH->OF) * size; - } + if(bytes_written % size){ + //unit was partially written. Switching to the one byte unit length in attempt to save unit remains anyway + size = 1; + nmemb = bytes_total; + } - if (bytes_written != size * nmemb) - WRITE_ERROR_EXIT; + units_written = bytes_written/size; + }while(bytes_written != bytes_total && (errno == EAGAIN || !errno) && write_attempts--); - return; + if (bytes_written != bytes_total) + WRITE_ERROR_EXIT; } /* on some error, we may decide to go on... */