< Summary

Information
Class: Renci.SshNet.RemotePathShellQuoteTransformation
Assembly: Renci.SshNet
File(s): \home\appveyor\projects\ssh-net\src\Renci.SshNet\RemotePathShellQuoteTransformation.cs
Line coverage
92%
Covered lines: 52
Uncovered lines: 4
Coverable lines: 56
Total lines: 209
Line coverage: 92.8%
Branch coverage
100%
Covered branches: 26
Total branches: 26
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
Transform(...)100%2692.85%

File(s)

\home\appveyor\projects\ssh-net\src\Renci.SshNet\RemotePathShellQuoteTransformation.cs

#LineLine coverage
 1using System;
 2using System.Text;
 3
 4namespace Renci.SshNet
 5{
 6    /// <summary>
 7    /// Quotes a path in a way to be suitable to be used with a shell-based server.
 8    /// </summary>
 9    internal sealed class RemotePathShellQuoteTransformation : IRemotePathTransformation
 10    {
 11        /// <summary>
 12        /// Quotes a path in a way to be suitable to be used with a shell-based server.
 13        /// </summary>
 14        /// <param name="path">The path to transform.</param>
 15        /// <returns>
 16        /// A quoted path.
 17        /// </returns>
 18        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 19        /// <remarks>
 20        /// <para>
 21        /// If <paramref name="path"/> contains a single-quote, that character is embedded
 22        /// in quotation marks (eg. "'"). Sequences of single-quotes are grouped in a single
 23        /// pair of quotation marks.
 24        /// </para>
 25        /// <para>
 26        /// An exclamation mark in <paramref name="path"/> is escaped with a backslash. This is
 27        /// necessary because C Shell interprets it as a meta-character for history substitution
 28        /// even when enclosed in single quotes or quotation marks.
 29        /// </para>
 30        /// <para>
 31        /// All other characters are enclosed in single quotes. Sequences of such characters are grouped
 32        /// in a single pair of single quotes.
 33        /// </para>
 34        /// <para>
 35        /// References:
 36        /// <list type="bullet">
 37        ///   <item>
 38        ///     <description><a href="http://pubs.opengroup.org/onlinepubs/7908799/xcu/chap2.html">Shell Command Languag
 39        ///   </item>
 40        ///   <item>
 41        ///     <description><a href="https://earthsci.stanford.edu/computing/unix/shell/specialchars.php">Unix C-Shell 
 42        ///   </item>
 43        ///   <item>
 44        ///     <description><a href="https://docstore.mik.ua/orelly/unix3/upt/ch27_13.htm">Differences Between Bourne a
 45        ///   </item>
 46        /// </list>
 47        /// </para>
 48        /// </remarks>
 49        /// <example>
 50        /// <list type="table">
 51        ///   <listheader>
 52        ///     <term>Original</term>
 53        ///     <term>Transformed</term>
 54        ///   </listheader>
 55        ///   <item>
 56        ///     <term>/var/log/auth.log</term>
 57        ///     <term>'/var/log/auth.log'</term>
 58        ///   </item>
 59        ///   <item>
 60        ///     <term>/var/mp3/Guns N' Roses</term>
 61        ///     <term>'/var/mp3/Guns N'"'"' Roses'</term>
 62        ///   </item>
 63        ///   <item>
 64        ///     <term>/var/garbage!/temp</term>
 65        ///     <term>'/var/garbage'\!'/temp'</term>
 66        ///   </item>
 67        ///   <item>
 68        ///     <term>/var/would be 'kewl'!, not?</term>
 69        ///     <term>'/var/would be '"'"'kewl'"'"\!', not?'</term>
 70        ///   </item>
 71        ///   <item>
 72        ///     <term></term>
 73        ///     <term>''</term>
 74        ///   </item>
 75        ///   <item>
 76        ///     <term>Hello &quot;World&quot;</term>
 77        ///     <term>'Hello "World"'</term>
 78        ///   </item>
 79        /// </list>
 80        /// </example>
 81        public string Transform(string path)
 39482        {
 39483            if (path is null)
 384            {
 385                throw new ArgumentNullException(nameof(path));
 86            }
 87
 88            // result is at least value and (likely) leading/trailing single-quotes
 39189            var sb = new StringBuilder(path.Length + 2);
 39190            var state = ShellQuoteState.Unquoted;
 91
 885792            foreach (var c in path)
 384293            {
 384294                switch (c)
 95                {
 96                    case '\'':
 97                        // embed a single-quote in quotes
 5898                        switch (state)
 99                        {
 100                            case ShellQuoteState.Unquoted:
 101                                // Start quoted string
 12102                                _ = sb.Append('"');
 12103                                break;
 104                            case ShellQuoteState.Quoted:
 105                                // Continue quoted string
 3106                                break;
 107                            case ShellQuoteState.SingleQuoted:
 108                                // Close single-quoted string
 43109                                _ = sb.Append('\'');
 110
 111                                // Start quoted string
 43112                                _ = sb.Append('"');
 43113                                break;
 114                            default:
 0115                                break;
 116                        }
 117
 58118                        state = ShellQuoteState.Quoted;
 58119                        break;
 120                    case '!':
 121                        /*
 122                         * In C-Shell, an exclamatation point can only be protected from shell interpretation
 123                         * when escaped by a backslash.
 124                         *
 125                         * Source:
 126                         * https://earthsci.stanford.edu/computing/unix/shell/specialchars.php
 127                         */
 128
 42129                        switch (state)
 130                        {
 131                            case ShellQuoteState.Unquoted:
 9132                                _ = sb.Append('\\');
 9133                                break;
 134                            case ShellQuoteState.Quoted:
 135                                // Close quoted string
 18136                                _ = sb.Append('"');
 18137                                _ = sb.Append('\\');
 18138                                break;
 139                            case ShellQuoteState.SingleQuoted:
 140                                // Close single quoted string
 15141                                _ = sb.Append('\'');
 15142                                _ = sb.Append('\\');
 15143                                break;
 144                            default:
 0145                                break;
 146                        }
 147
 42148                        state = ShellQuoteState.Unquoted;
 42149                        break;
 150                    default:
 3742151                        switch (state)
 152                        {
 153                            case ShellQuoteState.Unquoted:
 154                                // Start single-quoted string
 397155                                _ = sb.Append('\'');
 397156                                break;
 157                            case ShellQuoteState.Quoted:
 158                                // Close quoted string
 31159                                _ = sb.Append('"');
 160
 161                                // Start single-quoted string
 31162                                _ = sb.Append('\'');
 31163                                break;
 164                            case ShellQuoteState.SingleQuoted:
 165                                // Continue single-quoted string
 3314166                                break;
 167                            default:
 0168                                break;
 169                        }
 170
 3742171                        state = ShellQuoteState.SingleQuoted;
 3742172                        break;
 173                }
 174
 3842175                _ = sb.Append(c);
 3842176            }
 177
 391178            switch (state)
 179            {
 180                case ShellQuoteState.Unquoted:
 15181                    break;
 182                case ShellQuoteState.Quoted:
 183                    // Close quoted string
 6184                    _ = sb.Append('"');
 6185                    break;
 186                case ShellQuoteState.SingleQuoted:
 187                    // Close single-quoted string
 370188                    _ = sb.Append('\'');
 370189                    break;
 190                default:
 0191                    break;
 192            }
 193
 391194            if (sb.Length == 0)
 3195            {
 3196                _ = sb.Append("''");
 3197            }
 198
 391199            return sb.ToString();
 391200        }
 201
 202        private enum ShellQuoteState
 203        {
 204            Unquoted = 1,
 205            SingleQuoted = 2,
 206            Quoted = 3
 207        }
 208    }
 209}

Methods/Properties

Transform(System.String)