public (string, BackupRecord) GetBackupHashAndRecord(string bsname, string prefix, int offset = 0) { var bset = LoadBackupSet(bsname); var match = HashByPrefix(bsname, prefix); if (match == null || match.Value.multiplematches == true) { // TODO: throw this exception out of HashByPrefix? throw new KeyNotFoundException(); } int pidx = 0; for (int i = 0; i < bset.Backups.Count; i++) { if (bset.Backups[i].hash.SequenceEqual(match.Value.singlematchhash)) { pidx = i; break; } } int bidx = pidx + offset; if (bidx >= 0 && bidx < bset.Backups.Count) { return(HashTools.ByteArrayToHexViaLookup32(bset.Backups[bidx].hash).ToLower(), GetBackupRecord(bsname, bset.Backups[bidx].hash)); } else { throw new IndexOutOfRangeException(); } }
public IEnumerable <string> GetBackupsAndMetadataReferencesAsStrings(BackupSetReference bsname) { var bset = LoadBackupSet(bsname); foreach ((byte[] backupref, bool _) in bset.Backups) { yield return(HashTools.ByteArrayToHexViaLookup32(backupref)); foreach (byte[] reference in Dependencies.Blobs.GetAllBlobReferences(backupref, BlobLocation.BlobType.BackupRecord, false, false)) { yield return(HashTools.ByteArrayToHexViaLookup32(reference)); } } }
public Task DeleteBlobAsync(byte[] hash, string fileId) { return(DeleteFileAsync(Path.Combine(BlobSaveDirectory, HashTools.ByteArrayToHexViaLookup32(hash)), fileId)); }
public Task <(byte[] encryptedHash, string fileId)> StoreBlobAsync(byte[] hash, byte[] data) { return(StoreFileAsync(Path.Combine(BlobSaveDirectory, HashTools.ByteArrayToHexViaLookup32(hash)), hash, data)); }
public Task <byte[]> LoadBlobAsync(byte[] hash) { return(LoadFileAsync(Path.Combine(BlobSaveDirectory, HashTools.ByteArrayToHexViaLookup32(hash)))); }
/// <summary> /// /// </summary> /// <param name="file"></param> /// <param name="hash"></param> /// <param name="data"></param> /// <returns>fileId</returns> private async Task <(byte[] encryptedHash, string fileId)> StoreFileAsync(string file, byte[] hash, byte[] data, bool preventEncryption = false) { async Task <GetUploadUrlResponse> GetUploadUrl(int attempts = 0) { if (AuthResp == null) { AuthResp = await AuthorizeAccount(); } Delay(); try { var urlresp = await AuthResp.apiUrl .AppendPathSegment("/b2api/v1/b2_get_upload_url") .WithHeaders(new { Authorization = AuthResp.authorizationToken }) .PostJsonAsync(new { bucketId = BucketId }) .ReceiveJson <GetUploadUrlResponse>().ConfigureAwait(false); SuccessfulTransmission(); return(urlresp); } catch (FlurlHttpException ex) { if (ex.Call.HttpStatus != null && ex.Call.HttpStatus == System.Net.HttpStatusCode.Unauthorized) { AuthResp = null; } else { // Other classes of errors may be congestion related so we increase the delay FailedTransmission(); } if (attempts < Retries) { return(await GetUploadUrl(attempts + 1).ConfigureAwait(false)); } throw; } } var hashFileId = await UploadData(); async Task <(byte[] encryptedHash, string fileId)> UploadData(int attempts = 0) { if (UploadUrlResp == null) { UploadUrlResp = await GetUploadUrl(); } Delay(); try { if (Encryptor != null && !preventEncryption) { data = Encryptor.EncryptBytes(data); hash = HashTools.GetSHA1Hasher().ComputeHash(data); } var filecontent = new ByteArrayContent(data); filecontent.Headers.Add("Content-Type", "application/octet-stream"); var uploadresp = await UploadUrlResp.uploadUrl .WithHeaders(new { Authorization = UploadUrlResp.authorizationToken, X_Bz_File_Name = file, Content_Length = data.Length, X_Bz_Content_Sha1 = HashTools.ByteArrayToHexViaLookup32(hash) }) .PostAsync(filecontent) .ReceiveJson <UploadResponse>().ConfigureAwait(false); SuccessfulTransmission(); return(hash, uploadresp.fileId); } catch (FlurlHttpException ex) { if (ex.Call.HttpStatus != null && ex.Call.HttpStatus == System.Net.HttpStatusCode.Unauthorized) { UploadUrlResp = null; } else { // Other classes of errors may be congestion related so we increase the delay FailedTransmission(); } if (attempts < Retries) { return(await UploadData(attempts + 1).ConfigureAwait(false)); } throw; } } return(hashFileId); }
/// <summary> /// /// </summary> /// <param name="prefix"></param> /// <returns>Null if no matches, (true, null) for multiple matches, (false, hashstring) for exact match.</returns> public (bool multiplematches, byte[] singlematchhash)? HashByPrefix(string bsname, string prefix) { var bset = LoadBackupSet(bsname); // TODO: This implementation is pretty slow, could be improved with a better data structure like a trie or DAFSA // also if this becomes an issue, keep a s prefix = prefix.ToLower(); List <string> hashes = new List <string>(from backup in bset.Backups select HashTools.ByteArrayToHexViaLookup32(backup.hash)); List <string> matches = new List <string>(from h in hashes where h.ToLower().StartsWith(prefix.ToLower()) select h); if (matches.Count == 0) { return(null); } else if (matches.Count > 1) { return(true, null); } else { return(false, HashTools.HexStringToByteArray(matches[0])); } }
public (string, BackupRecord) GetBackupHashAndRecord(string bsname, int offset = 0) { var bset = LoadBackupSet(bsname); return(GetBackupHashAndRecord(bsname, HashTools.ByteArrayToHexViaLookup32(bset.Backups[bset.Backups.Count - 1].hash).ToLower(), offset)); }