/// <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; }
/// <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([NotNull, ItemNotNull, InstantHandle] IEnumerable<FeedUri> uris) { #region Sanity checks if (uris == null) throw new ArgumentNullException("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(); } }
/// <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 occurs while writing the file.</exception> /// <exception cref="UnauthorizedAccessException">Write access to the file is not permitted.</exception> public void Save([NotNull] 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(); } }
/// <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(); } }
/// <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(); } }
/// <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(); } }
/// <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 SetImplementationDirs([NotNull] string configPath, [NotNull, ItemNotNull, InstantHandle] 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 (var path in paths) configFile.WriteLine(path); } atomic.Commit(); } }
/// <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(); } }