00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "pg_backup.h"
00032 #include "pg_backup_archiver.h"
00033 #include "pg_backup_tar.h"
00034 #include "pg_backup_utils.h"
00035 #include "parallel.h"
00036 #include "pgtar.h"
00037
00038 #include <sys/stat.h>
00039 #include <ctype.h>
00040 #include <limits.h>
00041 #include <unistd.h>
00042
00043 static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te);
00044 static void _StartData(ArchiveHandle *AH, TocEntry *te);
00045 static size_t _WriteData(ArchiveHandle *AH, const void *data, size_t dLen);
00046 static void _EndData(ArchiveHandle *AH, TocEntry *te);
00047 static int _WriteByte(ArchiveHandle *AH, const int i);
00048 static int _ReadByte(ArchiveHandle *);
00049 static size_t _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len);
00050 static size_t _ReadBuf(ArchiveHandle *AH, void *buf, size_t len);
00051 static void _CloseArchive(ArchiveHandle *AH);
00052 static void _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
00053 static void _WriteExtraToc(ArchiveHandle *AH, TocEntry *te);
00054 static void _ReadExtraToc(ArchiveHandle *AH, TocEntry *te);
00055 static void _PrintExtraToc(ArchiveHandle *AH, TocEntry *te);
00056
00057 static void _StartBlobs(ArchiveHandle *AH, TocEntry *te);
00058 static void _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
00059 static void _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
00060 static void _EndBlobs(ArchiveHandle *AH, TocEntry *te);
00061
00062 #define K_STD_BUF_SIZE 1024
00063
00064
00065 typedef struct
00066 {
00067 #ifdef HAVE_LIBZ
00068 gzFile zFH;
00069 #else
00070 FILE *zFH;
00071 #endif
00072 FILE *nFH;
00073 FILE *tarFH;
00074 FILE *tmpFH;
00075 char *targetFile;
00076 char mode;
00077 pgoff_t pos;
00078 pgoff_t fileLen;
00079 ArchiveHandle *AH;
00080 } TAR_MEMBER;
00081
00082
00083
00084
00085
00086
00087 #define MAX_TAR_MEMBER_FILELEN (((int64) 1 << Min(33, sizeof(pgoff_t)*8 - 1)) - 1)
00088
00089 typedef struct
00090 {
00091 int hasSeek;
00092 pgoff_t filePos;
00093 TAR_MEMBER *blobToc;
00094 FILE *tarFH;
00095 pgoff_t tarFHpos;
00096 pgoff_t tarNextMember;
00097 TAR_MEMBER *FH;
00098 int isSpecialScript;
00099 TAR_MEMBER *scriptTH;
00100 } lclContext;
00101
00102 typedef struct
00103 {
00104 TAR_MEMBER *TH;
00105 char *filename;
00106 } lclTocEntry;
00107
00108
00109 static const char *modulename = gettext_noop("tar archiver");
00110
00111 static void _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt);
00112
00113 static TAR_MEMBER *tarOpen(ArchiveHandle *AH, const char *filename, char mode);
00114 static void tarClose(ArchiveHandle *AH, TAR_MEMBER *TH);
00115
00116 #ifdef __NOT_USED__
00117 static char *tarGets(char *buf, size_t len, TAR_MEMBER *th);
00118 #endif
00119 static int tarPrintf(ArchiveHandle *AH, TAR_MEMBER *th, const char *fmt,...) __attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4)));
00120
00121 static void _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th);
00122 static TAR_MEMBER *_tarPositionTo(ArchiveHandle *AH, const char *filename);
00123 static size_t tarRead(void *buf, size_t len, TAR_MEMBER *th);
00124 static size_t tarWrite(const void *buf, size_t len, TAR_MEMBER *th);
00125 static void _tarWriteHeader(TAR_MEMBER *th);
00126 static int _tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th);
00127 static size_t _tarReadRaw(ArchiveHandle *AH, void *buf, size_t len, TAR_MEMBER *th, FILE *fh);
00128
00129 static size_t _scriptOut(ArchiveHandle *AH, const void *buf, size_t len);
00130
00131
00132
00133
00134 void
00135 InitArchiveFmt_Tar(ArchiveHandle *AH)
00136 {
00137 lclContext *ctx;
00138
00139
00140 AH->ArchiveEntryPtr = _ArchiveEntry;
00141 AH->StartDataPtr = _StartData;
00142 AH->WriteDataPtr = _WriteData;
00143 AH->EndDataPtr = _EndData;
00144 AH->WriteBytePtr = _WriteByte;
00145 AH->ReadBytePtr = _ReadByte;
00146 AH->WriteBufPtr = _WriteBuf;
00147 AH->ReadBufPtr = _ReadBuf;
00148 AH->ClosePtr = _CloseArchive;
00149 AH->ReopenPtr = NULL;
00150 AH->PrintTocDataPtr = _PrintTocData;
00151 AH->ReadExtraTocPtr = _ReadExtraToc;
00152 AH->WriteExtraTocPtr = _WriteExtraToc;
00153 AH->PrintExtraTocPtr = _PrintExtraToc;
00154
00155 AH->StartBlobsPtr = _StartBlobs;
00156 AH->StartBlobPtr = _StartBlob;
00157 AH->EndBlobPtr = _EndBlob;
00158 AH->EndBlobsPtr = _EndBlobs;
00159 AH->ClonePtr = NULL;
00160 AH->DeClonePtr = NULL;
00161
00162 AH->MasterStartParallelItemPtr = NULL;
00163 AH->MasterEndParallelItemPtr = NULL;
00164
00165 AH->WorkerJobDumpPtr = NULL;
00166 AH->WorkerJobRestorePtr = NULL;
00167
00168
00169
00170
00171 ctx = (lclContext *) pg_malloc0(sizeof(lclContext));
00172 AH->formatData = (void *) ctx;
00173 ctx->filePos = 0;
00174 ctx->isSpecialScript = 0;
00175
00176
00177 AH->lo_buf_size = LOBBUFSIZE;
00178 AH->lo_buf = (void *) pg_malloc(LOBBUFSIZE);
00179
00180
00181
00182
00183 if (AH->mode == archModeWrite)
00184 {
00185 if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
00186 {
00187 ctx->tarFH = fopen(AH->fSpec, PG_BINARY_W);
00188 if (ctx->tarFH == NULL)
00189 exit_horribly(modulename,
00190 "could not open TOC file \"%s\" for output: %s\n",
00191 AH->fSpec, strerror(errno));
00192 }
00193 else
00194 {
00195 ctx->tarFH = stdout;
00196 if (ctx->tarFH == NULL)
00197 exit_horribly(modulename,
00198 "could not open TOC file for output: %s\n",
00199 strerror(errno));
00200 }
00201
00202 ctx->tarFHpos = 0;
00203
00204
00205
00206
00207
00208
00209
00210 ctx->hasSeek = checkSeek(ctx->tarFH);
00211
00212 if (AH->compression < 0 || AH->compression > 9)
00213 AH->compression = Z_DEFAULT_COMPRESSION;
00214
00215
00216 if (AH->compression == Z_DEFAULT_COMPRESSION)
00217 AH->compression = 0;
00218
00219
00220
00221
00222
00223
00224 if (AH->compression != 0)
00225 exit_horribly(modulename,
00226 "compression is not supported by tar archive format\n");
00227 }
00228 else
00229 {
00230 if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
00231 {
00232 ctx->tarFH = fopen(AH->fSpec, PG_BINARY_R);
00233 if (ctx->tarFH == NULL)
00234 exit_horribly(modulename, "could not open TOC file \"%s\" for input: %s\n",
00235 AH->fSpec, strerror(errno));
00236 }
00237 else
00238 {
00239 ctx->tarFH = stdin;
00240 if (ctx->tarFH == NULL)
00241 exit_horribly(modulename, "could not open TOC file for input: %s\n",
00242 strerror(errno));
00243 }
00244
00245
00246
00247
00248
00249
00250
00251 ctx->tarFHpos = 0;
00252
00253 ctx->hasSeek = checkSeek(ctx->tarFH);
00254
00255
00256
00257
00258
00259 AH->readHeader = 0;
00260
00261 ctx->FH = (void *) tarOpen(AH, "toc.dat", 'r');
00262 ReadHead(AH);
00263 ReadToc(AH);
00264 tarClose(AH, ctx->FH);
00265 }
00266 }
00267
00268
00269
00270
00271
00272 static void
00273 _ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
00274 {
00275 lclTocEntry *ctx;
00276 char fn[K_STD_BUF_SIZE];
00277
00278 ctx = (lclTocEntry *) pg_malloc0(sizeof(lclTocEntry));
00279 if (te->dataDumper != NULL)
00280 {
00281 #ifdef HAVE_LIBZ
00282 if (AH->compression == 0)
00283 sprintf(fn, "%d.dat", te->dumpId);
00284 else
00285 sprintf(fn, "%d.dat.gz", te->dumpId);
00286 #else
00287 sprintf(fn, "%d.dat", te->dumpId);
00288 #endif
00289 ctx->filename = pg_strdup(fn);
00290 }
00291 else
00292 {
00293 ctx->filename = NULL;
00294 ctx->TH = NULL;
00295 }
00296 te->formatData = (void *) ctx;
00297 }
00298
00299 static void
00300 _WriteExtraToc(ArchiveHandle *AH, TocEntry *te)
00301 {
00302 lclTocEntry *ctx = (lclTocEntry *) te->formatData;
00303
00304 if (ctx->filename)
00305 WriteStr(AH, ctx->filename);
00306 else
00307 WriteStr(AH, "");
00308 }
00309
00310 static void
00311 _ReadExtraToc(ArchiveHandle *AH, TocEntry *te)
00312 {
00313 lclTocEntry *ctx = (lclTocEntry *) te->formatData;
00314
00315 if (ctx == NULL)
00316 {
00317 ctx = (lclTocEntry *) pg_malloc0(sizeof(lclTocEntry));
00318 te->formatData = (void *) ctx;
00319 }
00320
00321 ctx->filename = ReadStr(AH);
00322 if (strlen(ctx->filename) == 0)
00323 {
00324 free(ctx->filename);
00325 ctx->filename = NULL;
00326 }
00327 ctx->TH = NULL;
00328 }
00329
00330 static void
00331 _PrintExtraToc(ArchiveHandle *AH, TocEntry *te)
00332 {
00333 lclTocEntry *ctx = (lclTocEntry *) te->formatData;
00334
00335 if (AH->public.verbose && ctx->filename != NULL)
00336 ahprintf(AH, "-- File: %s\n", ctx->filename);
00337 }
00338
00339 static void
00340 _StartData(ArchiveHandle *AH, TocEntry *te)
00341 {
00342 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
00343
00344 tctx->TH = tarOpen(AH, tctx->filename, 'w');
00345 }
00346
00347 static TAR_MEMBER *
00348 tarOpen(ArchiveHandle *AH, const char *filename, char mode)
00349 {
00350 lclContext *ctx = (lclContext *) AH->formatData;
00351 TAR_MEMBER *tm;
00352
00353 #ifdef HAVE_LIBZ
00354 char fmode[10];
00355 #endif
00356
00357 if (mode == 'r')
00358 {
00359 tm = _tarPositionTo(AH, filename);
00360 if (!tm)
00361 {
00362 if (filename)
00363 {
00364
00365
00366
00367
00368 exit_horribly(modulename, "could not find file \"%s\" in archive\n", filename);
00369 }
00370 else
00371 {
00372
00373 return NULL;
00374 }
00375 }
00376
00377 #ifdef HAVE_LIBZ
00378
00379 if (AH->compression == 0)
00380 tm->nFH = ctx->tarFH;
00381 else
00382 exit_horribly(modulename, "compression is not supported by tar archive format\n");
00383
00384 #else
00385 tm->nFH = ctx->tarFH;
00386 #endif
00387 }
00388 else
00389 {
00390 tm = pg_malloc0(sizeof(TAR_MEMBER));
00391
00392 #ifndef WIN32
00393 tm->tmpFH = tmpfile();
00394 #else
00395
00396
00397
00398
00399
00400
00401 while (1)
00402 {
00403 char *name;
00404 int fd;
00405
00406 name = _tempnam(NULL, "pg_temp_");
00407 if (name == NULL)
00408 break;
00409 fd = open(name, O_RDWR | O_CREAT | O_EXCL | O_BINARY |
00410 O_TEMPORARY, S_IRUSR | S_IWUSR);
00411 free(name);
00412
00413 if (fd != -1)
00414 {
00415 tm->tmpFH = fdopen(fd, "w+b");
00416 break;
00417 }
00418 else if (errno != EEXIST)
00419 break;
00420 }
00421 #endif
00422
00423 if (tm->tmpFH == NULL)
00424 exit_horribly(modulename, "could not generate temporary file name: %s\n", strerror(errno));
00425
00426 #ifdef HAVE_LIBZ
00427
00428 if (AH->compression != 0)
00429 {
00430 sprintf(fmode, "wb%d", AH->compression);
00431 tm->zFH = gzdopen(dup(fileno(tm->tmpFH)), fmode);
00432 if (tm->zFH == NULL)
00433 exit_horribly(modulename, "could not open temporary file\n");
00434 }
00435 else
00436 tm->nFH = tm->tmpFH;
00437 #else
00438
00439 tm->nFH = tm->tmpFH;
00440 #endif
00441
00442 tm->AH = AH;
00443 tm->targetFile = pg_strdup(filename);
00444 }
00445
00446 tm->mode = mode;
00447 tm->tarFH = ctx->tarFH;
00448
00449 return tm;
00450 }
00451
00452 static void
00453 tarClose(ArchiveHandle *AH, TAR_MEMBER *th)
00454 {
00455
00456
00457
00458 if (AH->compression != 0)
00459 if (GZCLOSE(th->zFH) != 0)
00460 exit_horribly(modulename, "could not close tar member\n");
00461
00462 if (th->mode == 'w')
00463 _tarAddFile(AH, th);
00464
00465
00466
00467
00468
00469
00470 if (th->targetFile)
00471 free(th->targetFile);
00472
00473 th->nFH = NULL;
00474 th->zFH = NULL;
00475 }
00476
00477 #ifdef __NOT_USED__
00478 static char *
00479 tarGets(char *buf, size_t len, TAR_MEMBER *th)
00480 {
00481 char *s;
00482 size_t cnt = 0;
00483 char c = ' ';
00484 int eof = 0;
00485
00486
00487 if (len > (th->fileLen - th->pos))
00488 len = th->fileLen - th->pos;
00489
00490 while (cnt < len && c != '\n')
00491 {
00492 if (_tarReadRaw(th->AH, &c, 1, th, NULL) <= 0)
00493 {
00494 eof = 1;
00495 break;
00496 }
00497 buf[cnt++] = c;
00498 }
00499
00500 if (eof && cnt == 0)
00501 s = NULL;
00502 else
00503 {
00504 buf[cnt++] = '\0';
00505 s = buf;
00506 }
00507
00508 if (s)
00509 {
00510 len = strlen(s);
00511 th->pos += len;
00512 }
00513
00514 return s;
00515 }
00516 #endif
00517
00518
00519
00520
00521
00522 static size_t
00523 _tarReadRaw(ArchiveHandle *AH, void *buf, size_t len, TAR_MEMBER *th, FILE *fh)
00524 {
00525 lclContext *ctx = (lclContext *) AH->formatData;
00526 size_t avail;
00527 size_t used = 0;
00528 size_t res = 0;
00529
00530 avail = AH->lookaheadLen - AH->lookaheadPos;
00531 if (avail > 0)
00532 {
00533
00534 if (avail >= len)
00535 used = len;
00536 else
00537 used = avail;
00538
00539
00540 memcpy(buf, AH->lookahead + AH->lookaheadPos, used);
00541 AH->lookaheadPos += used;
00542
00543
00544 len -= used;
00545 }
00546
00547
00548 if (len > 0)
00549 {
00550 if (fh)
00551 res = fread(&((char *) buf)[used], 1, len, fh);
00552 else if (th)
00553 {
00554 if (th->zFH)
00555 res = GZREAD(&((char *) buf)[used], 1, len, th->zFH);
00556 else
00557 res = fread(&((char *) buf)[used], 1, len, th->nFH);
00558 }
00559 else
00560 exit_horribly(modulename, "internal error -- neither th nor fh specified in tarReadRaw()\n");
00561 }
00562
00563 ctx->tarFHpos += res + used;
00564
00565 return (res + used);
00566 }
00567
00568 static size_t
00569 tarRead(void *buf, size_t len, TAR_MEMBER *th)
00570 {
00571 size_t res;
00572
00573 if (th->pos + len > th->fileLen)
00574 len = th->fileLen - th->pos;
00575
00576 if (len <= 0)
00577 return 0;
00578
00579 res = _tarReadRaw(th->AH, buf, len, th, NULL);
00580
00581 th->pos += res;
00582
00583 return res;
00584 }
00585
00586 static size_t
00587 tarWrite(const void *buf, size_t len, TAR_MEMBER *th)
00588 {
00589 size_t res;
00590
00591 if (th->zFH != NULL)
00592 res = GZWRITE(buf, 1, len, th->zFH);
00593 else
00594 res = fwrite(buf, 1, len, th->nFH);
00595
00596 if (res != len)
00597 exit_horribly(modulename,
00598 "could not write to output file: %s\n", strerror(errno));
00599
00600 th->pos += res;
00601 return res;
00602 }
00603
00604 static size_t
00605 _WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
00606 {
00607 lclTocEntry *tctx = (lclTocEntry *) AH->currToc->formatData;
00608
00609 dLen = tarWrite(data, dLen, tctx->TH);
00610
00611 return dLen;
00612 }
00613
00614 static void
00615 _EndData(ArchiveHandle *AH, TocEntry *te)
00616 {
00617 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
00618
00619
00620 tarClose(AH, tctx->TH);
00621 tctx->TH = NULL;
00622 }
00623
00624
00625
00626
00627 static void
00628 _PrintFileData(ArchiveHandle *AH, char *filename, RestoreOptions *ropt)
00629 {
00630 lclContext *ctx = (lclContext *) AH->formatData;
00631 char buf[4096];
00632 size_t cnt;
00633 TAR_MEMBER *th;
00634
00635 if (!filename)
00636 return;
00637
00638 th = tarOpen(AH, filename, 'r');
00639 ctx->FH = th;
00640
00641 while ((cnt = tarRead(buf, 4095, th)) > 0)
00642 {
00643 buf[cnt] = '\0';
00644 ahwrite(buf, 1, cnt, AH);
00645 }
00646
00647 tarClose(AH, th);
00648 }
00649
00650
00651
00652
00653
00654 static void
00655 _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
00656 {
00657 lclContext *ctx = (lclContext *) AH->formatData;
00658 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
00659 int pos1;
00660
00661 if (!tctx->filename)
00662 return;
00663
00664
00665
00666
00667
00668
00669
00670
00671 if (ctx->isSpecialScript)
00672 {
00673 if (te->copyStmt)
00674 {
00675
00676 ahprintf(AH, "\\.\n");
00677
00678
00679
00680
00681
00682 pos1 = (int) strlen(te->copyStmt) - 13;
00683 if (pos1 < 6 || strncmp(te->copyStmt, "COPY ", 5) != 0 ||
00684 strcmp(te->copyStmt + pos1, " FROM stdin;\n") != 0)
00685 exit_horribly(modulename,
00686 "unexpected COPY statement syntax: \"%s\"\n",
00687 te->copyStmt);
00688
00689
00690 ahwrite(te->copyStmt, 1, pos1, AH);
00691
00692 ahprintf(AH, " FROM '$$PATH$$/%s';\n\n", tctx->filename);
00693 }
00694 else
00695 {
00696
00697 ahprintf(AH, "\\i $$PATH$$/%s\n\n", tctx->filename);
00698 }
00699
00700 return;
00701 }
00702
00703 if (strcmp(te->desc, "BLOBS") == 0)
00704 _LoadBlobs(AH, ropt);
00705 else
00706 _PrintFileData(AH, tctx->filename, ropt);
00707 }
00708
00709 static void
00710 _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt)
00711 {
00712 Oid oid;
00713 lclContext *ctx = (lclContext *) AH->formatData;
00714 TAR_MEMBER *th;
00715 size_t cnt;
00716 bool foundBlob = false;
00717 char buf[4096];
00718
00719 StartRestoreBlobs(AH);
00720
00721 th = tarOpen(AH, NULL, 'r');
00722 while (th != NULL)
00723 {
00724 ctx->FH = th;
00725
00726 if (strncmp(th->targetFile, "blob_", 5) == 0)
00727 {
00728 oid = atooid(&th->targetFile[5]);
00729 if (oid != 0)
00730 {
00731 ahlog(AH, 1, "restoring large object with OID %u\n", oid);
00732
00733 StartRestoreBlob(AH, oid, ropt->dropSchema);
00734
00735 while ((cnt = tarRead(buf, 4095, th)) > 0)
00736 {
00737 buf[cnt] = '\0';
00738 ahwrite(buf, 1, cnt, AH);
00739 }
00740 EndRestoreBlob(AH, oid);
00741 foundBlob = true;
00742 }
00743 tarClose(AH, th);
00744 }
00745 else
00746 {
00747 tarClose(AH, th);
00748
00749
00750
00751
00752
00753
00754
00755 if (foundBlob)
00756 break;
00757 }
00758
00759 th = tarOpen(AH, NULL, 'r');
00760 }
00761 EndRestoreBlobs(AH);
00762 }
00763
00764
00765 static int
00766 _WriteByte(ArchiveHandle *AH, const int i)
00767 {
00768 lclContext *ctx = (lclContext *) AH->formatData;
00769 int res;
00770 char b = i;
00771
00772 res = tarWrite(&b, 1, ctx->FH);
00773 if (res != EOF)
00774 ctx->filePos += res;
00775 return res;
00776 }
00777
00778 static int
00779 _ReadByte(ArchiveHandle *AH)
00780 {
00781 lclContext *ctx = (lclContext *) AH->formatData;
00782 size_t res;
00783 unsigned char c;
00784
00785 res = tarRead(&c, 1, ctx->FH);
00786 if (res != 1)
00787 exit_horribly(modulename, "unexpected end of file\n");
00788 ctx->filePos += 1;
00789 return c;
00790 }
00791
00792 static size_t
00793 _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
00794 {
00795 lclContext *ctx = (lclContext *) AH->formatData;
00796 size_t res;
00797
00798 res = tarWrite(buf, len, ctx->FH);
00799 ctx->filePos += res;
00800 return res;
00801 }
00802
00803 static size_t
00804 _ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
00805 {
00806 lclContext *ctx = (lclContext *) AH->formatData;
00807 size_t res;
00808
00809 res = tarRead(buf, len, ctx->FH);
00810 ctx->filePos += res;
00811 return res;
00812 }
00813
00814 static void
00815 _CloseArchive(ArchiveHandle *AH)
00816 {
00817 lclContext *ctx = (lclContext *) AH->formatData;
00818 TAR_MEMBER *th;
00819 RestoreOptions *ropt;
00820 RestoreOptions *savRopt;
00821 int savVerbose,
00822 i;
00823
00824 if (AH->mode == archModeWrite)
00825 {
00826
00827
00828
00829 th = tarOpen(AH, "toc.dat", 'w');
00830 ctx->FH = th;
00831 WriteHead(AH);
00832 WriteToc(AH);
00833 tarClose(AH, th);
00834
00835
00836
00837
00838 WriteDataChunks(AH, NULL);
00839
00840
00841
00842
00843
00844 th = tarOpen(AH, "restore.sql", 'w');
00845
00846 tarPrintf(AH, th, "--\n"
00847 "-- NOTE:\n"
00848 "--\n"
00849 "-- File paths need to be edited. Search for $$PATH$$ and\n"
00850 "-- replace it with the path to the directory containing\n"
00851 "-- the extracted data files.\n"
00852 "--\n");
00853
00854 AH->CustomOutPtr = _scriptOut;
00855
00856 ctx->isSpecialScript = 1;
00857 ctx->scriptTH = th;
00858
00859 ropt = NewRestoreOptions();
00860 memcpy(ropt, AH->ropt, sizeof(RestoreOptions));
00861 ropt->filename = NULL;
00862 ropt->dropSchema = 1;
00863 ropt->compression = 0;
00864 ropt->superuser = NULL;
00865 ropt->suppressDumpWarnings = true;
00866
00867 savRopt = AH->ropt;
00868 AH->ropt = ropt;
00869
00870 savVerbose = AH->public.verbose;
00871 AH->public.verbose = 0;
00872
00873 RestoreArchive((Archive *) AH);
00874
00875 AH->ropt = savRopt;
00876 AH->public.verbose = savVerbose;
00877
00878 tarClose(AH, th);
00879
00880 ctx->isSpecialScript = 0;
00881
00882
00883
00884
00885 for (i = 0; i < 512 * 2; i++)
00886 {
00887 if (fputc(0, ctx->tarFH) == EOF)
00888 exit_horribly(modulename,
00889 "could not write null block at end of tar archive\n");
00890 }
00891 }
00892
00893 AH->FH = NULL;
00894 }
00895
00896 static size_t
00897 _scriptOut(ArchiveHandle *AH, const void *buf, size_t len)
00898 {
00899 lclContext *ctx = (lclContext *) AH->formatData;
00900
00901 return tarWrite(buf, len, ctx->scriptTH);
00902 }
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918 static void
00919 _StartBlobs(ArchiveHandle *AH, TocEntry *te)
00920 {
00921 lclContext *ctx = (lclContext *) AH->formatData;
00922 char fname[K_STD_BUF_SIZE];
00923
00924 sprintf(fname, "blobs.toc");
00925 ctx->blobToc = tarOpen(AH, fname, 'w');
00926 }
00927
00928
00929
00930
00931
00932
00933
00934
00935 static void
00936 _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
00937 {
00938 lclContext *ctx = (lclContext *) AH->formatData;
00939 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
00940 char fname[255];
00941 char *sfx;
00942
00943 if (oid == 0)
00944 exit_horribly(modulename, "invalid OID for large object (%u)\n", oid);
00945
00946 if (AH->compression != 0)
00947 sfx = ".gz";
00948 else
00949 sfx = "";
00950
00951 sprintf(fname, "blob_%u.dat%s", oid, sfx);
00952
00953 tarPrintf(AH, ctx->blobToc, "%u %s\n", oid, fname);
00954
00955 tctx->TH = tarOpen(AH, fname, 'w');
00956 }
00957
00958
00959
00960
00961
00962
00963
00964 static void
00965 _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
00966 {
00967 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
00968
00969 tarClose(AH, tctx->TH);
00970 }
00971
00972
00973
00974
00975
00976
00977
00978 static void
00979 _EndBlobs(ArchiveHandle *AH, TocEntry *te)
00980 {
00981 lclContext *ctx = (lclContext *) AH->formatData;
00982
00983
00984
00985
00986 tarClose(AH, ctx->blobToc);
00987 }
00988
00989
00990
00991
00992
00993
00994
00995
00996 static int
00997 tarPrintf(ArchiveHandle *AH, TAR_MEMBER *th, const char *fmt,...)
00998 {
00999 char *p = NULL;
01000 va_list ap;
01001 size_t bSize = strlen(fmt) + 256;
01002 int cnt = -1;
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013 while (cnt < 0 || cnt >= (bSize - 1))
01014 {
01015 if (p != NULL)
01016 free(p);
01017 bSize *= 2;
01018 p = (char *) pg_malloc(bSize);
01019 va_start(ap, fmt);
01020 cnt = vsnprintf(p, bSize, fmt, ap);
01021 va_end(ap);
01022 }
01023 cnt = tarWrite(p, cnt, th);
01024 free(p);
01025 return cnt;
01026 }
01027
01028 bool
01029 isValidTarHeader(char *header)
01030 {
01031 int sum;
01032 int chk = tarChecksum(header);
01033
01034 sscanf(&header[148], "%8o", &sum);
01035
01036 if (sum != chk)
01037 return false;
01038
01039
01040 if (memcmp(&header[257], "ustar\0", 6) == 0 &&
01041 memcmp(&header[263], "00", 2) == 0)
01042 return true;
01043
01044 if (memcmp(&header[257], "ustar \0", 8) == 0)
01045 return true;
01046
01047 if (memcmp(&header[257], "ustar00\0", 8) == 0)
01048 return true;
01049
01050 return false;
01051 }
01052
01053
01054 static void
01055 _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th)
01056 {
01057 lclContext *ctx = (lclContext *) AH->formatData;
01058 FILE *tmp = th->tmpFH;
01059 char buf[32768];
01060 size_t cnt;
01061 pgoff_t len = 0;
01062 size_t res;
01063 size_t i,
01064 pad;
01065
01066
01067
01068
01069 fseeko(tmp, 0, SEEK_END);
01070 th->fileLen = ftello(tmp);
01071 fseeko(tmp, 0, SEEK_SET);
01072
01073
01074
01075
01076
01077 if (th->fileLen > MAX_TAR_MEMBER_FILELEN)
01078 exit_horribly(modulename, "archive member too large for tar format\n");
01079
01080 _tarWriteHeader(th);
01081
01082 while ((cnt = fread(buf, 1, sizeof(buf), tmp)) > 0)
01083 {
01084 res = fwrite(buf, 1, cnt, th->tarFH);
01085 if (res != cnt)
01086 exit_horribly(modulename,
01087 "could not write to output file: %s\n",
01088 strerror(errno));
01089 len += res;
01090 }
01091
01092 if (fclose(tmp) != 0)
01093 exit_horribly(modulename, "could not close temporary file: %s\n",
01094 strerror(errno));
01095
01096 if (len != th->fileLen)
01097 {
01098 char buf1[32],
01099 buf2[32];
01100
01101 snprintf(buf1, sizeof(buf1), INT64_FORMAT, (int64) len);
01102 snprintf(buf2, sizeof(buf2), INT64_FORMAT, (int64) th->fileLen);
01103 exit_horribly(modulename, "actual file length (%s) does not match expected (%s)\n",
01104 buf1, buf2);
01105 }
01106
01107 pad = ((len + 511) & ~511) - len;
01108 for (i = 0; i < pad; i++)
01109 {
01110 if (fputc('\0', th->tarFH) == EOF)
01111 exit_horribly(modulename, "could not output padding at end of tar member\n");
01112 }
01113
01114 ctx->tarFHpos += len + pad;
01115 }
01116
01117
01118 static TAR_MEMBER *
01119 _tarPositionTo(ArchiveHandle *AH, const char *filename)
01120 {
01121 lclContext *ctx = (lclContext *) AH->formatData;
01122 TAR_MEMBER *th = pg_malloc0(sizeof(TAR_MEMBER));
01123 char c;
01124 char header[512];
01125 size_t i,
01126 len,
01127 blks;
01128 int id;
01129
01130 th->AH = AH;
01131
01132
01133 if (ctx->tarFHpos != 0)
01134 {
01135 char buf1[100],
01136 buf2[100];
01137
01138 snprintf(buf1, sizeof(buf1), INT64_FORMAT, (int64) ctx->tarFHpos);
01139 snprintf(buf2, sizeof(buf2), INT64_FORMAT, (int64) ctx->tarNextMember);
01140 ahlog(AH, 4, "moving from position %s to next member at file position %s\n",
01141 buf1, buf2);
01142
01143 while (ctx->tarFHpos < ctx->tarNextMember)
01144 _tarReadRaw(AH, &c, 1, NULL, ctx->tarFH);
01145 }
01146
01147 {
01148 char buf[100];
01149
01150 snprintf(buf, sizeof(buf), INT64_FORMAT, (int64) ctx->tarFHpos);
01151 ahlog(AH, 4, "now at file position %s\n", buf);
01152 }
01153
01154
01155
01156
01157 if (!_tarGetHeader(AH, th))
01158 {
01159 if (filename)
01160 exit_horribly(modulename, "could not find header for file \"%s\" in tar archive\n", filename);
01161 else
01162 {
01163
01164
01165
01166
01167 free(th);
01168 return NULL;
01169 }
01170 }
01171
01172 while (filename != NULL && strcmp(th->targetFile, filename) != 0)
01173 {
01174 ahlog(AH, 4, "skipping tar member %s\n", th->targetFile);
01175
01176 id = atoi(th->targetFile);
01177 if ((TocIDRequired(AH, id) & REQ_DATA) != 0)
01178 exit_horribly(modulename, "restoring data out of order is not supported in this archive format: "
01179 "\"%s\" is required, but comes before \"%s\" in the archive file.\n",
01180 th->targetFile, filename);
01181
01182
01183 len = ((th->fileLen + 511) & ~511);
01184 blks = len >> 9;
01185
01186 for (i = 0; i < blks; i++)
01187 _tarReadRaw(AH, &header[0], 512, NULL, ctx->tarFH);
01188
01189 if (!_tarGetHeader(AH, th))
01190 exit_horribly(modulename, "could not find header for file \"%s\" in tar archive\n", filename);
01191 }
01192
01193 ctx->tarNextMember = ctx->tarFHpos + ((th->fileLen + 511) & ~511);
01194 th->pos = 0;
01195
01196 return th;
01197 }
01198
01199
01200 static int
01201 _tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
01202 {
01203 lclContext *ctx = (lclContext *) AH->formatData;
01204 char h[512];
01205 char tag[100];
01206 int sum,
01207 chk;
01208 size_t len;
01209 unsigned long ullen;
01210 pgoff_t hPos;
01211 bool gotBlock = false;
01212
01213 while (!gotBlock)
01214 {
01215 #if 0
01216 if (ftello(ctx->tarFH) != ctx->tarFHpos)
01217 {
01218 char buf1[100],
01219 buf2[100];
01220
01221 snprintf(buf1, sizeof(buf1), INT64_FORMAT, (int64) ftello(ctx->tarFH));
01222 snprintf(buf2, sizeof(buf2), INT64_FORMAT, (int64) ftello(ctx->tarFHpos));
01223 exit_horribly(modulename,
01224 "mismatch in actual vs. predicted file position (%s vs. %s)\n",
01225 buf1, buf2);
01226 }
01227 #endif
01228
01229
01230 hPos = ctx->tarFHpos;
01231
01232
01233 len = _tarReadRaw(AH, h, 512, NULL, ctx->tarFH);
01234 if (len == 0)
01235 return 0;
01236
01237 if (len != 512)
01238 exit_horribly(modulename,
01239 ngettext("incomplete tar header found (%lu byte)\n",
01240 "incomplete tar header found (%lu bytes)\n",
01241 len),
01242 (unsigned long) len);
01243
01244
01245 chk = tarChecksum(h);
01246 sscanf(&h[148], "%8o", &sum);
01247
01248
01249
01250
01251
01252 if (chk == sum)
01253 gotBlock = true;
01254 else
01255 {
01256 int i;
01257
01258 for (i = 0; i < 512; i++)
01259 {
01260 if (h[i] != 0)
01261 {
01262 gotBlock = true;
01263 break;
01264 }
01265 }
01266 }
01267 }
01268
01269 sscanf(&h[0], "%99s", tag);
01270 sscanf(&h[124], "%12lo", &ullen);
01271 len = (size_t) ullen;
01272
01273 {
01274 char buf[100];
01275
01276 snprintf(buf, sizeof(buf), INT64_FORMAT, (int64) hPos);
01277 ahlog(AH, 3, "TOC Entry %s at %s (length %lu, checksum %d)\n",
01278 tag, buf, (unsigned long) len, sum);
01279 }
01280
01281 if (chk != sum)
01282 {
01283 char buf[100];
01284
01285 snprintf(buf, sizeof(buf), INT64_FORMAT, (int64) ftello(ctx->tarFH));
01286 exit_horribly(modulename,
01287 "corrupt tar header found in %s "
01288 "(expected %d, computed %d) file position %s\n",
01289 tag, sum, chk, buf);
01290 }
01291
01292 th->targetFile = pg_strdup(tag);
01293 th->fileLen = len;
01294
01295 return 1;
01296 }
01297
01298
01299 static void
01300 _tarWriteHeader(TAR_MEMBER *th)
01301 {
01302 char h[512];
01303
01304 tarCreateHeader(h, th->targetFile, NULL, th->fileLen, 0600, 04000, 02000, time(NULL));
01305
01306
01307 if (fwrite(h, 1, 512, th->tarFH) != 512)
01308 exit_horribly(modulename, "could not write to output file: %s\n", strerror(errno));
01309 }