// Copyright (C) 2024, The Duplicati Team // https://duplicati.com, hello@duplicati.com // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. using System; using System.Collections.Generic; using Newtonsoft.Json; namespace Duplicati.Library.Main.Volumes { public abstract class VolumeBase { public class FilesetData { [JsonProperty("IsFullBackup")] public bool IsFullBackup { get; set; } = true; public static string GetFilesetInstance(bool isFullBackup = true) { return JsonConvert.SerializeObject(new FilesetData { IsFullBackup = isFullBackup }); } } protected class ManifestData { public const string ENCODING = "utf8"; public const long VERSION = 2; public long Version; public string Created; public string Encoding; public long Blocksize; public string BlockHash; public string FileHash; public string AppVersion; public static string GetManifestInstance(long blocksize, string blockhash, string filehash) { return JsonConvert.SerializeObject(new ManifestData() { Version = VERSION, Encoding = ENCODING, Blocksize = blocksize, Created = Library.Utility.Utility.SerializeDateTime(DateTime.UtcNow), BlockHash = blockhash, FileHash = filehash, AppVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString() }); } public static void VerifyManifest(string manifest, long blocksize, string blockhash, string filehash) { var d = JsonConvert.DeserializeObject(manifest); if (d.Version > VERSION) throw new InvalidManifestException("Version", d.Version.ToString(), VERSION.ToString()); if (d.Encoding != ENCODING) throw new InvalidManifestException("Encoding", d.Encoding, ENCODING); if (d.Blocksize != blocksize) throw new InvalidManifestException("Blocksize", d.Blocksize.ToString(), blocksize.ToString()); if (d.BlockHash != blockhash) throw new InvalidManifestException("BlockHash", d.BlockHash, blockhash); if (d.FileHash != filehash) throw new InvalidManifestException("FileHash", d.FileHash, filehash); } } private class ParsedVolume : IParsedVolume { public RemoteVolumeType FileType { get; private set; } public string Prefix { get; private set; } public string Guid { get; private set; } public DateTime Time { get; private set; } public string CompressionModule { get; private set; } public string EncryptionModule { get; private set; } public Library.Interface.IFileEntry File { get; private set; } internal static readonly IDictionary REMOTE_TYPENAME_MAP; internal static readonly IDictionary REVERSE_REMOTE_TYPENAME_MAP; private static readonly System.Text.RegularExpressions.Regex FILENAME_REGEXP; static ParsedVolume() { var dict = new Dictionary(); dict[RemoteVolumeType.Blocks] = "dblock"; dict[RemoteVolumeType.Files] = "dlist"; dict[RemoteVolumeType.Index] = "dindex"; var reversedict = new Dictionary(System.StringComparer.OrdinalIgnoreCase); foreach(var x in dict) reversedict[x.Value] = x.Key; REMOTE_TYPENAME_MAP = dict; REVERSE_REMOTE_TYPENAME_MAP = reversedict; FILENAME_REGEXP = new System.Text.RegularExpressions.Regex(@"(?[^\-]+)\-(([i|b|I|B](?[0-9A-Fa-f]+))|((?