diff --git a/pageserver/src/branches.rs b/pageserver/src/branches.rs index c03dd3e3a3..ac73f0db1d 100644 --- a/pageserver/src/branches.rs +++ b/pageserver/src/branches.rs @@ -5,7 +5,6 @@ // use anyhow::{anyhow, bail, Context, Result}; -use bytes::Bytes; use fs::File; use postgres_ffi::{controlfile_utils, pg_constants, xlog_utils}; use rand::Rng; @@ -80,7 +79,7 @@ pub fn init_repo(conf: &'static PageServerConf, repo_dir: &Path) -> Result<()> { // Read control file to extract the LSN and system id let controlfile_path = tmppath.join("global").join("pg_control"); - let controlfile = controlfile_utils::decode_pg_control(Bytes::from(fs::read(controlfile_path)?))?; + let controlfile = controlfile_utils::decode_pg_control(&fs::read(controlfile_path)?)?; // let systemid = controlfile.system_identifier; let lsn = controlfile.checkPoint; let lsnstr = format!("{:016X}", lsn); @@ -212,7 +211,7 @@ pub(crate) fn get_system_id(conf: &PageServerConf) -> Result { let (_, main_snap_dir) = find_latest_snapshot(conf, *main_tli)?; let controlfile_path = main_snap_dir.join("global").join("pg_control"); - let controlfile = controlfile_utils::decode_pg_control(Bytes::from(fs::read(controlfile_path)?))?; + let controlfile = controlfile_utils::decode_pg_control(&fs::read(controlfile_path)?)?; Ok(controlfile.system_identifier) } @@ -356,13 +355,13 @@ fn force_crash_recovery(datadir: &Path) -> Result<()> { // Read in the control file let controlfilepath = datadir.to_path_buf().join("global").join("pg_control"); let mut controlfile = - controlfile_utils::decode_pg_control(Bytes::from(fs::read(controlfilepath.as_path())?))?; + controlfile_utils::decode_pg_control(&fs::read(controlfilepath.as_path())?)?; controlfile.state = postgres_ffi::DBState_DB_IN_PRODUCTION; fs::write( controlfilepath.as_path(), - controlfile_utils::encode_pg_control(controlfile), + controlfile_utils::encode_pg_control(&controlfile), )?; Ok(()) diff --git a/postgres_ffi/src/controlfile_utils.rs b/postgres_ffi/src/controlfile_utils.rs index 31e950759b..dab9410992 100644 --- a/postgres_ffi/src/controlfile_utils.rs +++ b/postgres_ffi/src/controlfile_utils.rs @@ -25,28 +25,36 @@ //! use crate::{ControlFileData, PG_CONTROLFILEDATA_OFFSETOF_CRC, PG_CONTROL_FILE_SIZE}; -use bytes::{Buf, Bytes, BytesMut}; +use anyhow::{bail, Result}; +use bytes::{Bytes, BytesMut}; // sizeof(ControlFileData) const SIZEOF_CONTROLDATA: usize = std::mem::size_of::(); // offsetof(ControlFileData, crc) const OFFSETOF_CRC: usize = PG_CONTROLFILEDATA_OFFSETOF_CRC as usize; -pub fn decode_pg_control(mut buf: Bytes) -> Result { - let mut b: [u8; SIZEOF_CONTROLDATA] = [0u8; SIZEOF_CONTROLDATA]; - buf.copy_to_slice(&mut b); +/// +/// Interpret a slice of bytes as a Postgres control file. +/// +pub fn decode_pg_control(buf: &[u8]) -> Result { + // Check that the slice has the expected size. The control file is + // padded with zeros up to a 512 byte sector size, so accept a + // larger size too, so that the caller can just the whole file + // contents without knowing the exact size of the struct. + if buf.len() < SIZEOF_CONTROLDATA { + bail!("control file is too short"); + } let controlfile: ControlFileData; - // TODO: verify CRC - let mut data_without_crc: [u8; OFFSETOF_CRC] = [0u8; OFFSETOF_CRC]; - data_without_crc.copy_from_slice(&b[0..OFFSETOF_CRC]); - let expectedcrc = crc32c::crc32c(&data_without_crc); + let mut b: [u8; SIZEOF_CONTROLDATA] = [0u8; SIZEOF_CONTROLDATA]; + b.copy_from_slice(&buf[0..SIZEOF_CONTROLDATA]); + let expectedcrc = crc32c::crc32c(&b[0..OFFSETOF_CRC]); controlfile = unsafe { std::mem::transmute::<[u8; SIZEOF_CONTROLDATA], ControlFileData>(b) }; if expectedcrc != controlfile.crc { - anyhow::bail!( + bail!( "invalid CRC in control file: expected {:08X}, was {:08X}", expectedcrc, controlfile.crc @@ -56,10 +64,14 @@ pub fn decode_pg_control(mut buf: Bytes) -> Result Bytes { +/// +/// Convert a struct representing a Postgres control file into raw bytes. +/// +/// The CRC is recomputed to match the contents of the fields. +pub fn encode_pg_control(controlfile: &ControlFileData) -> Bytes { let b: [u8; SIZEOF_CONTROLDATA]; - b = unsafe { std::mem::transmute::(controlfile) }; + b = unsafe { std::mem::transmute::(*controlfile) }; // Recompute the CRC let mut data_without_crc: [u8; OFFSETOF_CRC] = [0u8; OFFSETOF_CRC];