As stated by Keith C, there characters that are invalid for Windows/DOS file names namely \/:*?<>|
and also two periods ..
in immediate sequence.
End-users seem to have a bad habit of naming reports with those characters. If added to the <sf:retrieve/> (assuming the namespace) element unzip="false" it will not unzip the retrieve_<insert job id>.zip.
To get the job id, I just regex with new Regex object or using [Regex]::Match if using C# or Powershell respectively "(?mi).*Request ID for the current retrieve task:\s*(?[A-Za-z0-9]{18})". Just get the "jobid" group and put the string in the appropriate place. Since my solution uses .Net, I use the ZipArchive class to individually process and rename the files using ExtractToFile(string, bool).
Other languages such as Python has other means to handle zip files such as ZipFile, but not necessarily a direct extract to file; although, one could open a new file for writing and then write the stream from zipfile.read(member), in theory. I typically replace the invalid characters with underscores, but there are numerous ways to carry it out according to one's needs.
Some untested sample code (with bad practices, no try/catch etc):
using System;
using System.IO;
using System.IO.Compression;
using System.IO.Compression.FileSystems;
using System.Diagnostics;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
/* snip */
// Hungarian notation is evil
Regex rxJobId = new Regex(@"(?mi).*Request ID for the current retrieve task:\s*(?[A-Za-z0-9]{18})", RegexOptions.Compiled);
Regex rxBadChars = new Regex(@"(?:[<>:""/\|?*]|\.\.|\.$", RegexOptions.Compiled);
using (Process p = new Process()) {
string[] para = new string[] {
"/C",
@""""+Path.Combine(Environment.GetEnvironmentVariable("ANT_HOME"), "bin", "ant.bat")+@"""",
"retriveData" // Or whatever you named it in build.xml
};
p.StartInfo = new ProcessStartInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "cmd.exe"), string.Join(" ", parameters)) {
UseShellExecute=false,
RedirectStandardError=true,
RedirectStardardOutput=true
};
bool failed = false;
string jobId = null;
p.Start();
p.OutputDataReceived += new DataReceivedEventHander(
(sender, e)=>{
if ((""+e.Data).Length == 0) {
return;
}
if (e.Data.IndexOf("BUILD FAILED")>=0) {
failed = true;
}
Match m = rxJobId.Match(e.Data);
if (m.Success) {
jobId = m.Groups["jobid"]?.ToString();
}
}
);
p.ErrorDataReceived += new DataReceivedEventHander(
(sender, e)=>{
if ((""+e.Data).Length == 0) {
return;
}
if (e.Data.IndexOf("BUILD FAILED")>=0) {
failed = true;
}
Match m = rxJobId.Match(e.Data);
if (m.Success) {
jobId = m.Groups["jobid"]?.ToString();
}
}
);
p.BeginOutputReadLine();
p.BeginErrorReadLine();
while(p.WaitForExit(250)) {
Thread.Sleep(250);
}
if (!failed && (""+jobId).Length > 0) {
string filename = "retrieve_"+jobId+".zip";
if (File.Exists(filename)) {
using (ZipArchive archive = ZipFile.OpenRead(filename)) {
foreach(ZipArchiveEntry entry in archive.Entries) {
string upzipHere = Path.GetFullPath(Path.Combine("c:\destfolder", Path.GetDirectoryName(entry.FullName), rxBadChars.Replace(entry.Name, "_")));
entry.ExtractToFile(unzipHere, true); // I wanted overwrite
}
}
}
}
}
/* snip */