diff --git a/Duplicati/Library/Utility/Utility.cs b/Duplicati/Library/Utility/Utility.cs
index 01a34ccf1..0ae450d8d 100644
--- a/Duplicati/Library/Utility/Utility.cs
+++ b/Duplicati/Library/Utility/Utility.cs
@@ -1496,5 +1496,74 @@ namespace Duplicati.Library.Utility
}
}
}
+
+ ///
+ /// The regular expression matching all know non-quoted commandline characters
+ ///
+ private static readonly Regex COMMANDLINE_SAFE = new Regex(@"[A-Za-z0-9\-_/:\.]*");
+ ///
+ /// Special characters that needs to be escaped on Linux
+ ///
+ private static readonly Regex COMMANDLINE_ESCAPED_LINUX = new Regex(@"[""|$|`|\\|!]");
+
+ ///
+ /// Wraps a single argument in quotes suitable for the passing on the commandline
+ ///
+ /// The wrapped commandline element.
+ /// The argument to wrap.
+ /// A flag indicating if environment variables are allowed to be expanded
+ public static string WrapCommandLineElement(string arg, bool allowEnvExpansion)
+ {
+ if (string.IsNullOrWhiteSpace(arg))
+ return arg;
+
+ if (!Library.Utility.Utility.IsClientWindows)
+ {
+ // We could consider using single quotes that prevents all expansions
+ //if (!allowEnvExpansion)
+ // return "'" + arg.Replace("'", "\\'") + "'";
+
+ // Linux is using backslash to escape, except for !
+ arg = COMMANDLINE_ESCAPED_LINUX.Replace(arg, (match) =>
+ {
+ if (match.Value == "!")
+ return "\"'!'\"";
+
+ if (match.Value == "$" && allowEnvExpansion)
+ return match.Value;
+
+ return "\\" + match.Value;
+ });
+ }
+ else
+ {
+ // Windows needs only needs " replaced with "",
+ // but is prone to %var% expansion when used in
+ // immediate mode (i.e. from command prompt)
+
+ // TODO: I have not found a way to avoid escaping %varname%,
+ // and sadly it expands only if the variable exists
+ // making it even rarer and harder to diagnose when
+ // it happens
+ arg = arg.Replace("\"", "\"\"");
+ }
+
+ // Check that all characters are in the safe set
+ if (COMMANDLINE_SAFE.Match(arg).Length != arg.Length)
+ return "\"" + arg + "\"";
+ else
+ return arg;
+ }
+
+ ///
+ /// Wrap a set of commandline arguments suitable for the commandline
+ ///
+ /// A commandline string.
+ /// The arguments to create into a commandline.
+ /// A flag indicating if environment variables are allowed to be expanded
+ public static string WrapAsCommandLine(IEnumerable args, bool allowEnvExpansion = false)
+ {
+ return string.Join(" ", args.Select(x => WrapCommandLineElement(x, allowEnvExpansion)));
+ }
}
}