--- apache-ivy-2.2.0/src/java/org/apache/ivy//util/FileUtil.java 2010-06-28 08:17:10.000000000 +1200 +++ apache-ivy-2.2.0-symlink/src/java/org/apache/ivy//util/FileUtil.java 2011-10-03 15:23:14.617761330 +1300 @@ -27,6 +27,7 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringWriter; +import java.io.BufferedOutputStream; import java.net.URL; import java.util.ArrayList; import java.util.Collection; @@ -50,6 +51,22 @@ private static final byte[] EMPTY_BUFFER = new byte[0]; + // currently active symlink helper process + private static Process symlinkHelper; + private static PrintWriter symlinkHelperStdin; + private static BufferedReader symlinkHelperStdout; + + // symlink helper process script, run via sh -c '...' + private static final String symlinkScript = + "IFS=; " + + "while read -r SRC; do "+ + " read -r DEST; " + + " read -r FORCE; " + + " error=`ln -s \"$FORCE\" -- \"$SRC\" \"$DEST\" 2>&1`; " + + " if [ $? -ne 0 ]; then echo \"error: $error\" | head -1; else echo \"ok\"; fi; " + + "done; " + + "echo \"script terminated\"; exit 0"; + public static void symlink(File src, File dest, CopyProgressListener l, boolean overwrite) throws IOException { try { @@ -66,30 +83,61 @@ dest.getParentFile().mkdirs(); } - Runtime runtime = Runtime.getRuntime(); - Message.verbose("executing 'ln -s -f " + src.getAbsolutePath() + " " + dest.getPath() - + "'"); - Process process = runtime.exec(new String[] {"ln", "-s", "-f", src.getAbsolutePath(), - dest.getPath()}); - - if (process.waitFor() != 0) { - InputStream errorStream = process.getErrorStream(); - InputStreamReader isr = new InputStreamReader(errorStream); - BufferedReader br = new BufferedReader(isr); - - StringBuffer error = new StringBuffer(); - String line; - while ((line = br.readLine()) != null) { - error.append(line); - error.append('\n'); + final PrintWriter stdin; + final BufferedReader stdout; + synchronized (FileUtil.class) { + if (symlinkHelper == null) { + Message.verbose("Starting symlink helper - executing: sh -c '" + symlinkScript + "'"); + + ProcessBuilder builder = new ProcessBuilder(new String[]{"sh", "-c", symlinkScript}); + builder.redirectErrorStream(true); + symlinkHelper = builder.start(); + + symlinkHelperStdin = new PrintWriter(new BufferedOutputStream(symlinkHelper.getOutputStream())); + symlinkHelperStdout = new BufferedReader(new InputStreamReader(symlinkHelper.getInputStream())); + } + + stdin = symlinkHelperStdin; + stdout = symlinkHelperStdout; + } + + String result; + try { + Message.verbose("Requesting symlink of " + src.getAbsolutePath() + " to " + dest.getPath()); + symlinkHelperStdin.println(src.getAbsolutePath()); + symlinkHelperStdin.println(dest.getPath()); + symlinkHelperStdin.println(overwrite ? "-f" : ""); + symlinkHelperStdin.flush(); + result = symlinkHelperStdout.readLine(); + } catch (IOException ioe) { + Message.verbose("error writing to symlink helper script: " + ioe); + synchronized (FileUtil.class) { + if (symlinkHelper != null) + symlinkHelper.destroy(); + symlinkHelper = null; } - throw new IOException("error symlinking " + src + " to " + dest + ":\n" + error); + throw ioe; } - + + Message.verbose("Symlink helper responded: " + result); + + if (result == null || (!result.equals("ok") && !result.startsWith("error: "))) { + // EOF or unexpected response from script + Message.verbose("EOF or unexpected response from symlink helper script"); + synchronized (FileUtil.class) { + if (symlinkHelper != null) + symlinkHelper.destroy(); + symlinkHelper = null; + } + } + + if (!"ok".equals(result)) + throw new IOException("while symlinking " + src + " to " + dest + ": " + (result == null ? "helper script EOF" : result)); + // check if the creation of the symbolic link was successful if (!dest.exists()) { - throw new IOException("error symlinking: " + dest + " doesn't exists"); + throw new IOException("error symlinking: " + dest + " doesn't exist"); } // check if the result is a true symbolic link @@ -103,8 +151,6 @@ x.printStackTrace(new PrintWriter(buffer)); Message.debug(buffer.toString()); copy(src, dest, l, overwrite); - } catch (InterruptedException x) { - Thread.currentThread().interrupt(); } }