/*
*
* Copyright (C) 2010 JFrog Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* /
*/
package org.jfrog.wharf.ivy.util;
import org.apache.ivy.util.CopyProgressListener;
import org.apache.ivy.util.FileUtil;
import org.apache.ivy.util.Message;
import java.io.*;
/**
* Utility class for windows
*
* @author Tomer Cohen
*/
public abstract class WindowsUtils {
private static boolean mklinkWorks = true;
// utility class
private WindowsUtils() {
}
/**
* Create a windows style symbolic link, which is slightly different than the linux symbolic links. The commands
* that can be run in an mklink can be seen <a href="http://technet.microsoft.com/en-us/library/cc753194(WS.10).aspx">here</a>.
* This operation will only work on Windows Vista and up, attempting to use this on Windows XP and below will result
* in an exception and will perform a regular copy.
*
* @param src The source file
* @param dest The destination file
* @param l A copy progress listener to be used to listen to operations during the mklink/copy
* @param overwrite A flag that if set to true, and the destination file already exists, then the operation will
* stop and the destination file will not be deleted.
* @throws IOException Will be thrown should anything happen during the mklink process on the filesystem.
*/
public static void windowsSymlink(File src, File dest, CopyProgressListener l, boolean overwrite)
throws IOException {
try {
if (dest.exists()) {
if (!dest.isFile()) {
throw new IOException("impossible to copy: destination is not a file: " + dest);
}
if (!overwrite) {
Message.verbose(dest + " already exists, nothing done");
return;
}
}
if (dest.getParentFile() != null) {
dest.getParentFile().mkdirs();
}
if (!mklinkWorks) {
FileUtil.copy(src, dest, l, overwrite);
} else {
Runtime runtime = Runtime.getRuntime();
Message.verbose("executing 'mklink " + src.getAbsolutePath() + " " + dest.getPath()
+ "'");
Process process = runtime.exec(new String[]{"cmd.exe", "/C", "mklink", dest.getAbsolutePath(),
src.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');
}
throw new IOException("error performing mklink " + src + " to " + dest + ":\n" + error);
}
// check if the creation of the symbolic link was successful
if (!dest.exists()) {
throw new IOException("error performing mklink: " + dest + " doesn't exists");
}
}
} catch (IOException x) {
if (mklinkWorks) {
Message.debug("mklink cannot be executed due to: " + x.getMessage() + "\n" +
"Make sure you are admin of this machine! Falling back to copy.");
mklinkWorks = false;
}
StringWriter buffer = new StringWriter();
x.printStackTrace(new PrintWriter(buffer));
Message.debug(buffer.toString());
FileUtil.copy(src, dest, l, overwrite);
} catch (InterruptedException x) {
Thread.currentThread().interrupt();
}
}
}