public bool PushFile(string src, string dest, bool force) { if (dest == null || dest.Length == 0) { dest = Path.GetFileName(src); } DirEntry de; FileInfo fi = new FileInfo(src); bool exists = TryGetEntry(dest, out de); if (exists) { bool changeDetected = force; if (!changeDetected) { VersionEntry ve = de.Versions[de.Latest]; // Compare the file time if (fi.LastWriteTimeUtc.Ticks > ve.LastWriteTime) { // Compare the size if ((ulong)fi.Length != ve.Length) { changeDetected = true; } else if (_context.UseChecksums) { // Checksum check byte[] sha256 = new byte[32]; ComputeHashParams bb = new ComputeHashParams { }; bb.Hash = "sha256"; bb.Path = src; using (MemoryStream ms = new MemoryStream()) { bb.WriteTo(ms); CodecDll.ComputeHash(ms.GetBuffer(), (uint)ms.Length, sha256, (uint)sha256.Length); } // Compare the hash changeDetected = !sha256.SequenceEqual(ve.Checksum); } if (!changeDetected) { // Update the timestamp only de.Versions[de.Latest].LastWriteTime = fi.LastWriteTimeUtc.Ticks; return(true); } } } if (!changeDetected) { return(false); } } else { de = new DirEntry { Type = DirEntryType.File, Latest = 0 }; AddEntry(dest, de); } VersionEntry versionToRemove = null; // Encode the file to a temp location using (var lp = new LocalPath(LocalUtils.GetTempFileName())) { var hash = new byte[32]; CodecHelper.EncodeFile(ref _context, src, lp.Path, ref hash); var newVersionEntry = new VersionEntry { Uuid = Guid.NewGuid().ToString("N"), LastWriteTime = fi.LastWriteTimeUtc.Ticks, LastAccessTime = fi.LastAccessTimeUtc.Ticks, CreationTime = fi.CreationTimeUtc.Ticks, Attributes = (int)fi.Attributes, Length = (ulong)fi.Length }; newVersionEntry.Checksum = ByteString.CopyFrom(hash); if (de.Versions.Count == 0) { // The very first version addition de.Versions.Add(newVersionEntry); Debug.Assert(de.Latest == 0); } else if (de.Versions.Count > 0 && de.Versions.Count >= _context.RepoCfg.MaxVersions) { de.Latest = (de.Latest + 1) % _context.RepoCfg.MaxVersions; versionToRemove = de.Versions[de.Latest]; de.Versions[de.Latest] = newVersionEntry; } else { de.Versions.Add(newVersionEntry); ++de.Latest; } // The in-memory directory is updated, perform the file operations FileId fid = new FileId(newVersionEntry.Uuid); _context.Storage.CreateDirectory(fid.DirectoryPath); _context.Storage.Upload(lp.Path, fid.FullPath); } // Remove the previous version if necessary if (versionToRemove != null) { _context.Storage.RemoveFile((new FileId(versionToRemove.Uuid)).FullPath); } Write(); return(true); }