1717#include "pg_rewind.h"
1818#include "port/pg_bswap.h"
1919#include "rewind_source.h"
20+ #include "tde_ops.h"
21+
22+ #include "pg_tde.h"
2023
2124/*
2225 * Files are fetched MAX_CHUNK_SIZE bytes at a time, and with a
@@ -31,6 +34,7 @@ typedef struct
3134 const char * path ; /* path relative to data directory root */
3235 off_t offset ;
3336 size_t length ;
37+ bool encrypt ;
3438} fetch_range_request ;
3539
3640typedef struct
@@ -71,6 +75,10 @@ static char *libpq_fetch_file(rewind_source *source, const char *path,
7175static XLogRecPtr libpq_get_current_wal_insert_lsn (rewind_source * source );
7276static void libpq_destroy (rewind_source * source );
7377
78+ static void libpq_queue_process_fetch_range (rewind_source * source , const char * path ,
79+ bool needs_encrypt , off_t off , size_t len );
80+ static void libpq_fetch_tde_keys (rewind_source * source );
81+
7482/*
7583 * Create a new libpq source.
7684 *
@@ -100,6 +108,8 @@ init_libpq_source(PGconn *conn)
100108 initStringInfo (& src -> offsets );
101109 initStringInfo (& src -> lengths );
102110
111+ libpq_fetch_tde_keys (& src -> common );
112+
103113 return & src -> common ;
104114}
105115
@@ -345,7 +355,7 @@ libpq_queue_fetch_file(rewind_source *source, const char *path, size_t len)
345355 * fetch-requests are for a whole file.
346356 */
347357 open_target_file (path , true);
348- libpq_queue_fetch_range (source , path , 0 , Max (len , MAX_CHUNK_SIZE ));
358+ libpq_queue_process_fetch_range (source , path , false , 0 , Max (len , MAX_CHUNK_SIZE ));
349359}
350360
351361/*
@@ -354,6 +364,17 @@ libpq_queue_fetch_file(rewind_source *source, const char *path, size_t len)
354364static void
355365libpq_queue_fetch_range (rewind_source * source , const char * path , off_t off ,
356366 size_t len )
367+ {
368+ libpq_queue_process_fetch_range (source , path , true, off , len );
369+ }
370+
371+ /*
372+ * A workhorse for libpq_queue_fetch_range.
373+ * `needs_encrypt` indicates if file's blocks may need re-encryption.
374+ */
375+ static void
376+ libpq_queue_process_fetch_range (rewind_source * source , const char * path ,
377+ bool needs_encrypt , off_t off , size_t len )
357378{
358379 libpq_source * src = (libpq_source * ) source ;
359380
@@ -406,6 +427,7 @@ libpq_queue_fetch_range(rewind_source *source, const char *path, off_t off,
406427 src -> request_queue [src -> num_requests ].path = path ;
407428 src -> request_queue [src -> num_requests ].offset = off ;
408429 src -> request_queue [src -> num_requests ].length = thislen ;
430+ src -> request_queue [src -> num_requests ].encrypt = needs_encrypt ;
409431 src -> num_requests ++ ;
410432
411433 off += thislen ;
@@ -420,6 +442,7 @@ static void
420442libpq_finish_fetch (rewind_source * source )
421443{
422444 process_queued_fetch_requests ((libpq_source * ) source );
445+ flush_current_key ();
423446}
424447
425448static void
@@ -592,6 +615,19 @@ process_queued_fetch_requests(libpq_source *src)
592615
593616 open_target_file (filename , false);
594617
618+ if (rq -> encrypt )
619+ {
620+ Assert (chunksize % BLCKSZ == 0 );
621+
622+ ensure_tde_keys (filename );
623+
624+ for (int i = 0 ; i < chunksize / BLCKSZ ; i ++ )
625+ {
626+ unsigned char * data = (unsigned char * ) chunk + BLCKSZ * i ;
627+
628+ encrypt_block (data , chunkoff + BLCKSZ * i );
629+ }
630+ }
595631 write_target_range (chunk , chunkoff , chunksize );
596632 }
597633
@@ -682,3 +718,52 @@ libpq_destroy(rewind_source *source)
682718
683719 /* NOTE: we don't close the connection here, as it was not opened by us. */
684720}
721+
722+ static void
723+ libpq_fetch_tde_keys (rewind_source * source )
724+ {
725+ PGconn * conn = ((libpq_source * ) source )-> conn ;
726+ PGresult * res ;
727+
728+ res = PQexec (conn , "SELECT pg_ls_dir('" PG_TDE_DATA_DIR "', true, false)" );
729+
730+ if (PQresultStatus (res ) != PGRES_TUPLES_OK )
731+ pg_fatal ("could not fetch file list: %s" ,
732+ PQresultErrorMessage (res ));
733+
734+ /* no tde dir, nothing to do */
735+ if (PQnfields (res ) == 0 )
736+ {
737+ PQclear (res );
738+ return ;
739+ }
740+
741+ init_tde ();
742+
743+ for (int i = 0 ; i < PQntuples (res ); i ++ )
744+ {
745+ char * path ;
746+ char * tde_file_buf ;
747+ size_t size ;
748+ char target_path [MAXPGPATH ];
749+
750+ if (PQgetisnull (res , i , 0 ))
751+ {
752+ /*
753+ * The file was removed from the server while the query was
754+ * running. Ignore it.
755+ */
756+ continue ;
757+ }
758+
759+ path = PQgetvalue (res , i , 0 );
760+
761+ snprintf (target_path , MAXPGPATH , "%s/%s" , PG_TDE_DATA_DIR , path );
762+ tde_file_buf = libpq_fetch_file (source , target_path , & size );
763+
764+ write_tmp_source_file (path , tde_file_buf , size );
765+ pg_free (tde_file_buf );
766+ }
767+
768+ PQclear (res );
769+ }
0 commit comments