/// <summary>
        /// Sets the list of implementation directories in a specific configuration file.
        /// </summary>
        /// <param name="configPath">The path of the configuration file to write.</param>
        /// <param name="paths">The list of implementation directories to set.</param>
        /// <exception cref="IOException">There was a problem writing <paramref name="configPath"/>.</exception>
        /// <exception cref="UnauthorizedAccessException">Access to <paramref name="configPath"/> was not permitted.</exception>
        private static void SetDirectories(string configPath, IEnumerable <string> paths)
        {
            #region Sanity checks
            if (string.IsNullOrEmpty(configPath))
            {
                throw new ArgumentNullException(nameof(configPath));
            }
            if (paths == null)
            {
                throw new ArgumentNullException(nameof(paths));
            }
            #endregion

            using var atomic = new AtomicWrite(configPath);
            using (var configFile = new StreamWriter(atomic.WritePath, append: false, encoding: FeedUtils.Encoding)
            {
                NewLine = "\n"
            })
            {
                foreach (string path in paths)
                {
                    configFile.WriteLine(path);
                }
            }
            atomic.Commit();
        }
Example #2
0
        /// <summary>
        /// Adds a directory prefix to all entries in an external flag file.
        /// </summary>
        /// <param name="path">The full path to the flag file, named <see cref="FlagUtils.XbitFile"/> or <see cref="FlagUtils.SymlinkFile"/>.</param>
        /// <param name="source">The old path of the renamed file or directory relative to <paramref name="path"/>.</param>
        /// <param name="destination">The new path of the renamed file or directory relative to <paramref name="path"/>.</param>
        /// <exception cref="ArgumentException"><paramref name="source"/> or <paramref name="destination"/> is not a relative path.</exception>
        /// <exception cref="IOException">There was an error writing the flag file.</exception>
        /// <exception cref="UnauthorizedAccessException">You have insufficient rights to write the flag file.</exception>
        public static void Rename([NotNull] string path, [NotNull] string source, [NotNull] string destination)
        {
            #region Sanity checks
            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentNullException("path");
            }
            if (string.IsNullOrEmpty(source))
            {
                throw new ArgumentNullException("source");
            }
            if (Path.IsPathRooted(source))
            {
                throw new ArgumentException(Resources.PathNotRelative, "source");
            }
            if (string.IsNullOrEmpty(destination))
            {
                throw new ArgumentNullException("destination");
            }
            if (Path.IsPathRooted(destination))
            {
                throw new ArgumentException(Resources.PathNotRelative, "destination");
            }
            #endregion

            if (!File.Exists(path))
            {
                return;
            }

            // Convert paths to rooted Unix-style
            source      = "/" + source.Replace(Path.DirectorySeparatorChar, '/');
            destination = "/" + destination.Replace(Path.DirectorySeparatorChar, '/');

            using (var atomic = new AtomicWrite(path))
                using (var newFlagFile = new StreamWriter(atomic.WritePath, append: false, encoding: FeedUtils.Encoding)
                {
                    NewLine = "\n"
                })
                    using (var oldFlagFile = File.OpenText(path))
                    {
                        // Each line in the file signals a flagged file
                        while (!oldFlagFile.EndOfStream)
                        {
                            string line = oldFlagFile.ReadLine();
                            if (line != null && line.StartsWith("/"))
                            {
                                if (line == source || line.StartsWith(source + "/"))
                                {
                                    newFlagFile.WriteLine(destination + line.Substring(source.Length));
                                }
                                else
                                {
                                    newFlagFile.WriteLine(line);
                                }
                            }
                        }
                        atomic.Commit();
                    }
        }
Example #3
0
        /// <inheritdoc/>
        public string GetIcon(Uri iconUrl, ITaskHandler handler)
        {
            #region Sanity checks
            if (iconUrl == null)
            {
                throw new ArgumentNullException(nameof(iconUrl));
            }
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }
            #endregion

            string path = Path.Combine(DirectoryPath, new FeedUri(iconUrl).Escape());

            // Prevent file-exists race conditions
            lock (_lock)
            {
                // Download missing icons
                if (!File.Exists(path))
                {
                    using (var atomic = new AtomicWrite(path))
                    {
                        handler.RunTask(new DownloadFile(iconUrl, atomic.WritePath));
                        atomic.Commit();
                    }
                }
            }

            return(path);
        }
Example #4
0
        private void InitializeEventJournal(TIdentity aggregateId, params IAggregateEvent <TAggregate, TIdentity>[] events)
        {
            var writerGuid = Guid.NewGuid().ToString();
            var writes     = new AtomicWrite[events.Length];

            for (var i = 0; i < events.Length; i++)
            {
                var committedEvent = new CommittedEvent <TAggregate, TIdentity, IAggregateEvent <TAggregate, TIdentity> >(aggregateId, events[i], new Metadata(), DateTimeOffset.UtcNow, i + 1);
                writes[i] = new AtomicWrite(new Persistent(committedEvent, i + 1, aggregateId.Value, string.Empty, false, ActorRefs.NoSender, writerGuid));
            }
            var journal = Persistence.Instance.Apply(_testKit.Sys).JournalFor(null);

            journal.Tell(new WriteMessages(writes, AggregateTestProbe.Ref, 1));

            AggregateTestProbe.ExpectMsg <WriteMessagesSuccessful>();

            for (var i = 0; i < events.Length; i++)
            {
                var seq = i;
                AggregateTestProbe.ExpectMsg <WriteMessageSuccess>(x =>
                                                                   x.Persistent.PersistenceId == aggregateId.ToString() &&
                                                                   x.Persistent.Payload is CommittedEvent <TAggregate, TIdentity, IAggregateEvent <TAggregate, TIdentity> > &&
                                                                   x.Persistent.SequenceNr == (long)seq + 1);
            }
        }
Example #5
0
 /// <summary>
 /// Writes the entire content of a byte array to file atomically.
 /// </summary>
 /// <param name="data">The data to write.</param>
 /// <param name="path">The file to write to.</param>
 private void WriteToFile(byte[] data, string path)
 {
     lock (_replaceLock)
         using (var atomic = new AtomicWrite(path))
         {
             File.WriteAllBytes(atomic.WritePath, data);
             atomic.Commit();
         }
 }
Example #6
0
 private void Download(Uri href, string path)
 {
     using var atomic = new AtomicWrite(path);
     _handler.RunTask(new DownloadFile(href, atomic.WritePath)
     {
         BytesMaximum = MaximumIconSize
     });
     atomic.Commit();
 }
        private Proto.Msg.AtomicWrite GetAtomicWrite(AtomicWrite write)
        {
            var message = new Proto.Msg.AtomicWrite();

            foreach (var pr in (IImmutableList <IPersistentRepresentation>)write.Payload)
            {
                message.Payload.Add(GetPersistentMessage(pr));
            }
            return(message);
        }
        /// <summary>
        /// Saves the settings to an INI file.
        /// </summary>
        /// <remarks>This method performs an atomic write operation when possible.</remarks>
        /// <exception cref="IOException">A problem occurred while writing the file.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to the file is not permitted.</exception>
        public void Save(string path)
        {
            TransferToIni();

            Log.Debug("Saving Config to: " + path);

            using var atomic = new AtomicWrite(path);
            using (var writer = new StreamWriter(atomic.WritePath, append: false, encoding: FeedUtils.Encoding))
                new StreamIniDataParser().WriteData(writer, _iniData);
            atomic.Commit();
        }
        private CheckAndMutateRowRequest ToBigtableWriteRequest(AtomicWrite atomicWrite, ActorSystem actorSystem)
        {
            if (atomicWrite.HighestSequenceNr != atomicWrite.LowestSequenceNr)
            {
                throw new NotSupportedException("Journal does not support multiple events in a single atomic write");
            }

            var persistent = ((IImmutableList <IPersistentRepresentation>)atomicWrite.Payload).Single();

            return(ToMutateRowIfNotExistsRequest(persistent, actorSystem));
        }
Example #10
0
        private global::AtomicWrite.Builder AtomicWriteToProto(AtomicWrite aw)
        {
            var builder = global::AtomicWrite.CreateBuilder();

            foreach (var p in (IEnumerable <IPersistentRepresentation>)aw.Payload)
            {
                builder.AddPayload(PersistentToProto(p));
            }


            return(builder);
        }
Example #11
0
        /// <summary>
        /// Removes one or more flags for a file or directory in an external flag file.
        /// </summary>
        /// <param name="path">The full path to the flag file, named <see cref="FlagUtils.XbitFile"/> or <see cref="FlagUtils.SymlinkFile"/>.</param>
        /// <param name="relativePath">The path of the file or directory to remove relative to <paramref name="path"/>.</param>
        /// <exception cref="ArgumentException"><paramref name="relativePath"/> is not a relative path.</exception>
        /// <exception cref="IOException">There was an error writing the flag file.</exception>
        /// <exception cref="UnauthorizedAccessException">You have insufficient rights to write the flag file.</exception>
        public static void Remove([NotNull] string path, [NotNull] string relativePath)
        {
            #region Sanity checks
            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentNullException("path");
            }
            if (string.IsNullOrEmpty(relativePath))
            {
                throw new ArgumentNullException("relativePath");
            }
            if (Path.IsPathRooted(relativePath))
            {
                throw new ArgumentException(Resources.PathNotRelative, "relativePath");
            }
            #endregion

            if (!File.Exists(path))
            {
                return;
            }

            // Convert path to rooted Unix-style
            string unixPath = "/" + relativePath.Replace(Path.DirectorySeparatorChar, '/');

            using (var atomic = new AtomicWrite(path))
                using (var newFlagFile = new StreamWriter(atomic.WritePath, append: false, encoding: FeedUtils.Encoding)
                {
                    NewLine = "\n"
                })
                    using (var oldFlagFile = File.OpenText(path))
                    {
                        // Each line in the file signals a flagged file
                        while (!oldFlagFile.EndOfStream)
                        {
                            string line = oldFlagFile.ReadLine();
                            if (line != null && line.StartsWith("/"))
                            {
                                if (line == unixPath || line.StartsWith(unixPath + "/"))
                                {
                                    continue;                                              // Filter out removed files
                                }
                                newFlagFile.WriteLine(line);
                            }
                        }
                        atomic.Commit();
                    }
        }
Example #12
0
        /// <summary>
        /// Saves an object in an XML file ending with a line break.
        /// </summary>
        /// <remarks>This method performs an atomic write operation when possible.</remarks>
        /// <typeparam name="T">The type of object to be saved in an XML stream.</typeparam>
        /// <param name="data">The object to be stored.</param>
        /// <param name="path">The path of the file to write.</param>
        /// <param name="stylesheet">The path of an XSL stylesheet for <typeparamref name="T"/>; can be <c>null</c>.</param>
        /// <exception cref="IOException">A problem occurred while writing the file.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to the file is not permitted.</exception>
        /// <remarks>Uses <seealso cref="AtomicWrite"/> internally.</remarks>
        public static void SaveXml <T>([NotNull] this T data, [NotNull, Localizable(false)] string path, [CanBeNull, Localizable(false)] string stylesheet = null)
        {
            #region Sanity checks
            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentNullException(nameof(path));
            }
            #endregion

            using (var atomic = new AtomicWrite(path))
            {
                using (var fileStream = File.Create(atomic.WritePath))
                    SaveXml(data, fileStream, stylesheet);
                atomic.Commit();
            }
        }
Example #13
0
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
        private async Task WriteBatchAsync(AtomicWrite aw)
        {
            var transaction = Database.CreateTransaction();

            var payloads = aw.Payload.AsInstanceOf <IImmutableList <IPersistentRepresentation> >();

            foreach (var payload in payloads)
            {
                var(bytes, tags) = Extract(payload);

                // save the payload
                transaction.SortedSetAddAsync(_journalHelper.GetJournalKey(payload.PersistenceId), bytes, payload.SequenceNr);

                // notify about a new event being appended for this persistence id
                transaction.PublishAsync(_journalHelper.GetJournalChannel(payload.PersistenceId), payload.SequenceNr);

                // save tags
                foreach (var tag in tags)
                {
                    transaction.ListRightPushAsync(_journalHelper.GetTagKey(tag), $"{payload.SequenceNr}:{payload.PersistenceId}");
                    transaction.PublishAsync(_journalHelper.GetTagsChannel(), tag);
                }
            }

            // set highest sequence number key
            transaction.StringSetAsync(_journalHelper.GetHighestSequenceNrKey(aw.PersistenceId), aw.HighestSequenceNr);

            // add persistenceId
            transaction.SetAddAsync(_journalHelper.GetIdentifiersKey(), aw.PersistenceId).ContinueWith(task =>
            {
                if (task.Result)
                {
                    // notify about a new persistenceId
                    Database.Publish(_journalHelper.GetIdentifiersChannel(), aw.PersistenceId);
                }
            });

            if (!await transaction.ExecuteAsync())
            {
                throw new Exception($"{nameof(WriteMessagesAsync)}: failed to write {typeof(IPersistentRepresentation).Name} to redis");
            }
        }
Example #14
0
        /// <summary>
        /// Saves an object in an XML file embedded in a ZIP archive.
        /// </summary>
        /// <typeparam name="T">The type of object to be saved in an XML stream.</typeparam>
        /// <param name="data">The object to be stored.</param>
        /// <param name="path">The ZIP archive to be written.</param>
        /// <param name="password">The password to use for encryption; <c>null</c> for no encryption.</param>
        /// <param name="additionalFiles">Additional files to be stored alongside the XML file in the ZIP archive; can be <c>null</c>.</param>
        /// <exception cref="IOException">A problem occurred while writing the file.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to the file is not permitted.</exception>
        /// <remarks>Uses <seealso cref="AtomicWrite"/> internally.</remarks>
        public static void SaveXmlZip <T>([NotNull] this T data, [NotNull, Localizable(false)] string path, [CanBeNull, Localizable(false)] string password = null, [NotNull] params EmbeddedFile[] additionalFiles)
        {
            #region Sanity checks
            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentNullException(nameof(path));
            }
            if (additionalFiles == null)
            {
                throw new ArgumentNullException(nameof(additionalFiles));
            }
            #endregion

            using (var atomic = new AtomicWrite(path))
            {
                using (var fileStream = File.Create(atomic.WritePath))
                    SaveXmlZip(data, fileStream, password, additionalFiles);
                atomic.Commit();
            }
        }
Example #15
0
        public void Journal_should_serialize_events()
        {
            if (!SupportsSerialization)
            {
                return;
            }

            var probe  = CreateTestProbe();
            var @event = new TestPayload(probe.Ref);

            var aw = new AtomicWrite(
                new Persistent(@event, 6L, Pid, sender: ActorRefs.NoSender, writerGuid: WriterGuid));

            Journal.Tell(new WriteMessages(new [] { aw }, probe.Ref, ActorInstanceId));

            probe.ExpectMsg <WriteMessagesSuccessful>();
            var pid        = Pid;
            var writerGuid = WriterGuid;

            probe.ExpectMsg <WriteMessageSuccess>(o =>
            {
                Assertions.AssertEqual(writerGuid, o.Persistent.WriterGuid);
                Assertions.AssertEqual(pid, o.Persistent.PersistenceId);
                Assertions.AssertEqual(6L, o.Persistent.SequenceNr);
                Assertions.AssertTrue(o.Persistent.Sender == ActorRefs.NoSender || o.Persistent.Sender.Equals(Sys.DeadLetters), $"Expected WriteMessagesSuccess.Persistent.Sender to be null or {Sys.DeadLetters}, but found {o.Persistent.Sender}");
                Assertions.AssertEqual(@event, o.Persistent.Payload);
            });

            Journal.Tell(new ReplayMessages(6L, long.MaxValue, long.MaxValue, Pid, _receiverProbe.Ref));

            _receiverProbe.ExpectMsg <ReplayedMessage>(o =>
            {
                Assertions.AssertEqual(writerGuid, o.Persistent.WriterGuid);
                Assertions.AssertEqual(pid, o.Persistent.PersistenceId);
                Assertions.AssertEqual(6L, o.Persistent.SequenceNr);
                Assertions.AssertTrue(o.Persistent.Sender == ActorRefs.NoSender || o.Persistent.Sender.Equals(Sys.DeadLetters), $"Expected WriteMessagesSuccess.Persistent.Sender to be null or {Sys.DeadLetters}, but found {o.Persistent.Sender}");
                Assertions.AssertEqual(@event, o.Persistent.Payload);
            });

            Assertions.AssertEqual(_receiverProbe.ExpectMsg <RecoverySuccess>().HighestSequenceNr, 6L);
        }
        /// <summary>
        /// Sets the list of catalog sources in a configuration file.
        /// </summary>
        /// <param name="uris">The list of catalog sources to use from now on.</param>
        /// <exception cref="IOException">There was a problem writing a configuration file.</exception>
        /// <exception cref="UnauthorizedAccessException">Access to a configuration file was not permitted.</exception>
        public static void SetSources(IEnumerable <FeedUri> uris)
        {
            #region Sanity checks
            if (uris == null)
            {
                throw new ArgumentNullException(nameof(uris));
            }
            #endregion

            using var atomic = new AtomicWrite(Locations.GetSaveConfigPath("0install.net", true, "catalog-sources"));
            using (var configFile = new StreamWriter(atomic.WritePath, append: false, encoding: FeedUtils.Encoding)
            {
                NewLine = "\n"
            })
            {
                foreach (var uri in uris)
                {
                    configFile.WriteLine(uri.ToStringRfc());
                }
            }
            atomic.Commit();
        }
Example #17
0
    /// <summary>
    /// Builds a stub EXE that executes the "0install run" command at a specific path.
    /// </summary>
    /// <param name="path">The path to store the generated EXE file.</param>
    /// <param name="target">The application to be launched.</param>
    /// <param name="command">The command argument to be passed to the the "0install run" command; can be <c>null</c>.</param>
    /// <param name="gui"><c>true</c> to build a GUI stub, <c>false</c> to build a CLI stub.</param>
    /// <exception cref="OperationCanceledException">The user canceled the task.</exception>
    /// <exception cref="InvalidOperationException">There was a compilation error while generating the stub EXE.</exception>
    /// <exception cref="IOException">A problem occurred while writing to the filesystem.</exception>
    /// <exception cref="WebException">A problem occurred while downloading additional data (such as icons).</exception>
    /// <exception cref="UnauthorizedAccessException">Write access to the filesystem is not permitted.</exception>
    public void BuildRunStub(string path, FeedTarget target, string?command = null, bool gui = false)
    {
        #region Sanity checks
        if (string.IsNullOrEmpty(path))
        {
            throw new ArgumentNullException(nameof(path));
        }
        #endregion

        var compilation = CSharpCompilation.Create(
            assemblyName: "ZeroInstall.Stub",
            syntaxTrees: new[]
        {
            GetCode(
                exe: GetExe(gui),
                arguments: GetArguments(target.Uri, command, gui),
                title: target.Feed.GetBestName(CultureInfo.CurrentUICulture, command))
        },
            _references,
            options: new(
                gui ? OutputKind.WindowsApplication : OutputKind.ConsoleApplication,
                optimizationLevel: OptimizationLevel.Release,
                deterministic: true));
        var resources = GetResources(compilation, GetIconPath(target, command));

        using var atomic = new AtomicWrite(path);
        using (var stream = File.Create(atomic.WritePath))
        {
            var result = compilation.Emit(stream, win32Resources: resources);
            if (!result.Success)
            {
                throw new IOException(result.Diagnostics.FirstOrDefault()?.ToString());
            }
        }
        atomic.Commit();
    }
Example #18
0
        /// <summary>
        /// Sets the list of implementation directory paths in the current user configuration.
        /// </summary>
        /// <param name="paths">The list of implementation directory paths to set.</param>
        /// <exception cref="IOException">There was a problem writing a configuration file.</exception>
        /// <exception cref="UnauthorizedAccessException">Access to a configuration file was not permitted.</exception>
        public static void SetUserCustomImplementationDirs([NotNull, ItemNotNull, InstantHandle] IEnumerable <string> paths)
        {
            #region Sanity checks
            if (paths == null)
            {
                throw new ArgumentNullException("paths");
            }
            #endregion

            using (var atomic = new AtomicWrite(Locations.GetSaveConfigPath("0install.net", true, "injector", "implementation-dirs")))
            {
                using (var configFile = new StreamWriter(atomic.WritePath, append: false, encoding: FeedUtils.Encoding)
                {
                    NewLine = "\n"
                })
                {
                    foreach (var path in paths)
                    {
                        configFile.WriteLine(path);
                    }
                }
                atomic.Commit();
            }
        }
Example #19
0
 /// <summary>
 /// Writes the entire content of a byte array to file atomically.
 /// </summary>
 /// <param name="data">The data to write.</param>
 /// <param name="path">The file to write to.</param>
 private static void WriteToFile(byte[] data, string path)
 {
     using var atomic = new AtomicWrite(path);
     File.WriteAllBytes(atomic.WritePath, data);
     atomic.Commit();
 }
Example #20
0
        private global::AtomicWrite.Builder AtomicWriteToProto(AtomicWrite aw)
        {
            var builder = global::AtomicWrite.CreateBuilder();

            foreach (var p in (IEnumerable<IPersistentRepresentation>)aw.Payload)
            {
                builder.AddPayload(PersistentToProto(p));
            }
            

            return builder;
        }