Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions libvirtnbdbackup/backup/disk.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
from libvirtnbdbackup.backup import server
from libvirtnbdbackup.backup import target
from libvirtnbdbackup.backup.metadata import backupChecksum
from libvirtnbdbackup.backup.metadata import adler32_full_file
from libvirtnbdbackup.backup.metadata import write_checksum_sidecar
from libvirtnbdbackup.backup.metadata import _fsync_file
from libvirtnbdbackup import extenthandler
from libvirtnbdbackup.qemu import util as qemu
from libvirtnbdbackup.qemu.exceptions import ProcessError
Expand Down Expand Up @@ -208,24 +211,33 @@ def backup( # pylint: disable=too-many-arguments,too-many-branches, too-many-lo
if args.compress:
dStream.writeCompressionTrailer(writer, compressedSizes)

progressBar.close()
progressBar.close()
writer.close()
connection.disconnect()

if args.offline is True and virtClient.remoteHost == "":
logging.info("Stopping NBD Service.")
lib.killProc(nbdProc.pid)

if args.offline is True:
lib.remove(args, nbdProc.pidFile)

if not args.stdout:
if args.noprogress is True:
logging.info(
"Backup of disk [%s] finished, file: [%s]", disk.target, targetFile
)
logging.info("Backup of disk [%s] finished, file: [%s]", disk.target, targetFile)

# finalize filename before checksumming
partialfile.rename(targetFilePartial, targetFile)
if streamType != "raw":
backupChecksum(fileStream, targetFile)
_fsync_file(targetFile)

if streamType == "raw":
logging.info("RAW path: computing full-file Adler32 for %s", targetFile)
checksum = adler32_full_file(targetFile)
logging.info("RAW path: Adler32=%d", checksum)
write_checksum_sidecar(targetFile, checksum)
else:
logging.info("STREAM path: writing stream metadata checksum for %s", targetFile)
backupChecksum(fileStream, targetFile)

# Always return (even when args.stdout is True)
return backupSize, True

31 changes: 29 additions & 2 deletions libvirtnbdbackup/backup/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import os
import os, zlib
import logging
from argparse import Namespace
from typing import List, Union
Expand All @@ -31,6 +31,33 @@

log = logging.getLogger()

def adler32_full_file(path: str, bufsize: int = 8 * 1024 * 1024) -> int:
"""
Compute Adler-32 over the entire file, matching virtnbdrestore's verify path.
"""
csum = 1 # zlib.adler32 seed
with open(path, "rb") as f:
for chunk in iter(lambda: f.read(bufsize), b""):
csum = zlib.adler32(chunk, csum)
return csum & 0xFFFFFFFF

def _fsync_file(path: str) -> None:
try:
with open(path, "rb", buffering=0) as f:
os.fsync(f.fileno())
except Exception:
pass

def write_checksum_sidecar(target_file: str, crc: int) -> None:
sidecar = f"{target_file}.chksum"
with open(sidecar, "w") as fh:
fh.write(f"{crc}\n")
try:
with open(sidecar, "rb", buffering=0) as f:
os.fsync(f.fileno())
except Exception:
pass


def backupChecksum(fileStream, targetFile):
"""Save the calculated adler32 checksum, it can be verified
Expand Down Expand Up @@ -144,4 +171,4 @@ def addFiles(args: Namespace, configFile: Union[str, None], zipStream, logFile:
zipStream.zipStream.write(diskInfo, os.path.basename(diskInfo))

log.info("Adding backup log [%s] to zipfile", logFile)
zipStream.zipStream.write(logFile, logFile)
zipStream.zipStream.write(logFile, logFile)
Loading
Loading