/// <summary> /// Creates a stream for writing an extracted file to the filesystem. /// </summary> /// <param name="relativePath">A path relative to the archive's root.</param> /// <param name="executable"><see langword="true"/> if the file's executable bit is set; <see langword="false"/> otherwise.</param> /// <returns>A stream for writing the extracted file.</returns> protected FileStream OpenFileWriteStream([NotNull] string relativePath, bool executable = false) { CancellationToken.ThrowIfCancellationRequested(); string fullPath = CombinePath(relativePath); string directoryPath = Path.GetDirectoryName(fullPath); if (directoryPath != null && !Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } bool alreadyExists = File.Exists(fullPath); var stream = File.Create(fullPath); // If a symlink is overwritten by a normal file, remove the symlink flag if (alreadyExists) { string flagRelativePath = string.IsNullOrEmpty(Destination) ? relativePath : Path.Combine(Destination, relativePath); FlagUtils.Remove(Path.Combine(TargetDir, FlagUtils.SymlinkFile), flagRelativePath); } if (executable) { SetExecutableBit(relativePath); } else if (alreadyExists) { RemoveExecutableBit(relativePath); // If an executable file is overwritten by a non-executable file, remove the xbit flag } return(stream); }
/// <summary> /// Marks a file as no longer executable using the filesystem if possible, an <see cref="FlagUtils.XbitFile"/> file otherwise. /// </summary> /// <param name="relativePath">A path relative to the archive's root.</param> private void RemoveExecutableBit(string relativePath) { #region Sanity checks if (string.IsNullOrEmpty(relativePath)) { throw new ArgumentNullException("relativePath"); } #endregion if (_isUnixFS) { FileUtils.SetExecutable(Path.Combine(EffectiveTargetDir, relativePath), false); } else { // Non-Unixoid OSes (e.g. Windows) can't store the executable flag directly in the filesystem; remember in a text-file instead string flagRelativePath = string.IsNullOrEmpty(Destination) ? relativePath : Path.Combine(Destination, relativePath); FlagUtils.Remove(Path.Combine(TargetDir, FlagUtils.XbitFile), flagRelativePath); } }