/*
* ====================================================================
* Copyright (c) 2004-2012 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.wc;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.CharsetDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import org.tmatesoft.svn.core.ISVNCanceller;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.internal.util.SVNFormatUtil;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.util.SVNUUIDGenerator;
import org.tmatesoft.svn.core.internal.util.jna.SVNJNAUtil;
import org.tmatesoft.svn.core.internal.util.jna.SVNOS2Util;
import org.tmatesoft.svn.core.internal.wc.admin.SVNTranslator;
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
import org.tmatesoft.svn.core.wc.ISVNOptions;
import org.tmatesoft.svn.util.SVNDebugLog;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.3
* @author TMate Software Ltd., Peter Skoog
*/
public class SVNFileUtil {
private static final String ID_COMMAND;
private static final String LN_COMMAND;
public static final String LS_COMMAND;
private static final String CHMOD_COMMAND;
private static final String ATTRIB_COMMAND;
private static final String ENV_COMMAND;
private static final String STAT_COMMAND;
public static final boolean logNativeCalls;
public static final boolean isWindows;
public static final boolean isOS2;
public static final boolean isOSX;
public static final boolean isBSD;
public static boolean isLinux;
public static final boolean isSolaris;
public static final boolean isOpenVMS;
public static final boolean is32Bit;
public static final boolean is64Bit;
public static final int STREAM_CHUNK_SIZE = 16384;
public static final int FILE_CREATION_ATTEMPTS_COUNT;
public final static OutputStream DUMMY_OUT = new OutputStream() {
public void write(int b) throws IOException {
}
};
public final static InputStream DUMMY_IN = new InputStream() {
public int read() throws IOException {
return -1;
}
};
private static boolean ourUseUnsafeCopyOnly = Boolean.TRUE.toString().equalsIgnoreCase(System.getProperty("svnkit.no.safe.copy", System.getProperty("javasvn.no.safe.copy", "false")));
private static boolean ourCopyOnSetWritable = Boolean.TRUE.toString().equalsIgnoreCase(System.getProperty("svnkit.fast.setWritable", "true"));
private static boolean ourUseNIOCopying = Boolean.TRUE.toString().equalsIgnoreCase(System.getProperty("svnkit.nio.copy", "true"));
private static String nativeEOLMarker;
private static String ourGroupID;
private static String ourUserID;
private static File ourAppDataPath;
private static String ourAdminDirectoryName;
private static File ourSystemAppDataPath;
private static Method ourSetWritableMethod;
private static Method ourSetExecutableMethod;
private static volatile boolean ourIsSleepForTimeStamp = true;
public static final String BINARY_MIME_TYPE = "application/octet-stream";
static {
final String logNativeCallsString = System.getProperty("svnkit.log.native.calls", "false");
logNativeCalls = logNativeCallsString == null ? false : Boolean.parseBoolean(logNativeCallsString);
String retryCountStr = System.getProperty("svnkit.fs.win32_retry_count", "100");
int retryCount = -1;
try {
retryCount = Integer.parseInt(retryCountStr);
} catch (NumberFormatException nfe) {
retryCount = -1;
}
if (retryCount < 0) {
retryCount = 100;
}
FILE_CREATION_ATTEMPTS_COUNT = retryCount;
String osName = System.getProperty("os.name");
String osNameLC = osName == null ? null : osName.toLowerCase();
boolean windows = osName != null && osNameLC.indexOf("windows") >= 0;
if (!windows && osName != null) {
windows = osNameLC.indexOf("os/2") >= 0;
isOS2 = windows;
} else {
isOS2 = false;
}
isWindows = windows;
isOSX = osName != null && (osNameLC.indexOf("mac") >= 0 || osNameLC.indexOf("darwin") >= 0);
isLinux = osName != null && (osNameLC.indexOf("linux") >= 0 || osNameLC.indexOf("hp-ux") >= 0);
isBSD = !isLinux && osName != null && osNameLC.indexOf("bsd") >= 0;
isSolaris = !isLinux && !isBSD && osName != null && (osNameLC.indexOf("solaris") >= 0 || osNameLC.indexOf("sunos") >= 0);
isOpenVMS = !isOSX && osName != null && osNameLC.indexOf("openvms") >= 0;
if (!isWindows && !isOSX && !isLinux && !isBSD && !isSolaris && !isOpenVMS && !isOS2) {
// fallback to some default.
isLinux = true;
}
is32Bit = "32".equals(System.getProperty("sun.arch.data.model", "32"));
is64Bit = "64".equals(System.getProperty("sun.arch.data.model", "64"));
if (isOpenVMS) {
setAdminDirectoryName("_svn");
}
String prefix = "svnkit.program.";
Properties props = new Properties();
InputStream is = SVNFileUtil.class.getResourceAsStream("/svnkit.runtime.properties");
if (is != null) {
try {
props.load(is);
} catch (IOException e) {
} finally {
SVNFileUtil.closeFile(is);
}
}
ID_COMMAND = props.getProperty(prefix + "id", "id");
LN_COMMAND = props.getProperty(prefix + "ln", "ln");
LS_COMMAND = props.getProperty(prefix + "ls", "ls");
CHMOD_COMMAND = props.getProperty(prefix + "chmod", "chmod");
ATTRIB_COMMAND = props.getProperty(prefix + "attrib", "attrib");
ENV_COMMAND = props.getProperty(prefix + "env", "env");
STAT_COMMAND = props.getProperty(prefix + "stat", "stat");
try {
ourSetWritableMethod = File.class.getMethod("setWritable", new Class[] {
Boolean.TYPE
});
} catch (SecurityException e) {
} catch (NoSuchMethodException e) {
}
try {
ourSetExecutableMethod = File.class.getMethod("setExecutable", new Class[] {
Boolean.TYPE, Boolean.TYPE,
});
} catch (SecurityException e) {
} catch (NoSuchMethodException e) {
}
}
public static boolean isCaseInsensitiveFS() {
return isWindows || isOS2;
}
public static synchronized boolean useUnsafeCopyOnly() {
return ourUseUnsafeCopyOnly;
}
public static synchronized void setUseUnsafeCopyOnly(boolean useUnsafeCopyOnly) {
ourUseUnsafeCopyOnly = useUnsafeCopyOnly;
}
public static synchronized boolean useCopyOnSetWritable() {
return ourCopyOnSetWritable;
}
public static synchronized void setUseCopyOnSetWritable(boolean useCopyOnSetWritable) {
ourCopyOnSetWritable = useCopyOnSetWritable;
}
public static synchronized boolean useNIOCopying() {
return ourUseNIOCopying;
}
public static synchronized void setUseNIOCopying(boolean useNIOCopy) {
ourUseNIOCopying = useNIOCopy;
}
public static String getIdCommand() {
return ID_COMMAND;
}
public static String getLnCommand() {
return LN_COMMAND;
}
public static String getLsCommand() {
return LS_COMMAND;
}
public static String getChmodCommand() {
return CHMOD_COMMAND;
}
public static String getAttribCommand() {
return ATTRIB_COMMAND;
}
public static String getEnvCommand() {
return ENV_COMMAND;
}
public static String getStatCommand() {
return STAT_COMMAND;
}
public static File getParentFile(File file) {
if (file == null) {
return null;
}
String path = file.getAbsolutePath();
path = path.replace(File.separatorChar, '/');
path = SVNPathUtil.canonicalizePath(path);
int up = 0;
while (path.endsWith("/..")) {
path = SVNPathUtil.removeTail(path);
up++;
}
for (int i = 0; i < up; i++) {
path = SVNPathUtil.removeTail(path);
}
path = path.replace('/', File.separatorChar);
file = new File(path);
return file.getParentFile();
}
public static byte[] readFully(File file) throws SVNException {
final byte[] buffer = new byte[(int) file.length()];
final InputStream inputStream = SVNFileUtil.openFileForReading(file);
try {
final int read = SVNFileUtil.readIntoBuffer(inputStream, buffer, 0, buffer.length);
if (read != buffer.length) {
SVNErrorMessage errorMessage = SVNErrorMessage.create(SVNErrorCode.STREAM_UNEXPECTED_EOF);
SVNErrorManager.error(errorMessage, SVNLogType.DEFAULT);
}
return buffer;
} catch (IOException e) {
SVNErrorMessage errorMessage = SVNErrorMessage.create(SVNErrorCode.IO_ERROR);
SVNErrorManager.error(errorMessage, e, SVNLogType.DEFAULT);
} finally {
SVNFileUtil.closeFile(inputStream);
}
return null;
}
public static String readFile(File file) throws SVNException {
InputStream is = null;
try {
is = openFileForReading(file, SVNLogType.WC);
return readFile(is);
} catch (IOException ioe) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot read from file ''{0}'': {1}", new Object[] {
file, ioe.getMessage()
});
SVNErrorManager.error(err, Level.FINE, SVNLogType.WC);
} finally {
closeFile(is);
}
return null;
}
public static String readFile(InputStream input) throws IOException {
byte[] buf = new byte[STREAM_CHUNK_SIZE];
StringBuffer result = new StringBuffer();
int r = -1;
while ((r = input.read(buf)) != -1) {
if (r == 0) {
continue;
}
result.append(new String(buf, 0, r, "UTF-8"));
}
return result.toString();
}
public static int readIntoBuffer(InputStream is, byte[] buff, int off, int len) throws IOException {
int read = 0;
while (len > 0) {
int r = is.read(buff, off + read, len);
if (r < 0) {
if (read == 0) {
read = -1;
}
break;
}
read += r;
len -= r;
}
return read;
}
public static String getBasePath(File file) {
File base = SVNFileUtil.getFileDir(file);
while (base != null) {
if (base.isDirectory()) {
File adminDir = new File(base, getAdminDirectoryName());
if (adminDir.exists() && adminDir.isDirectory()) {
break;
}
}
base = SVNFileUtil.getFileDir(base);
}
String path = file.getAbsolutePath();
if (base != null) {
path = path.substring(base.getAbsolutePath().length());
}
path = path.replace(File.separatorChar, '/');
if (path.startsWith("/")) {
path = path.substring(1);
}
return path;
}
public static void createEmptyFile(File file) throws SVNException {
boolean created;
if (file != null && SVNFileUtil.getFileDir(file) != null && !SVNFileUtil.getFileDir(file).exists()) {
SVNFileUtil.getFileDir(file).mkdirs();
}
IOException ioError = null;
try {
created = createNewFile(file);
} catch (IOException ioe) {
created = false;
ioError = ioe;
}
if (!created) {
SVNErrorMessage err = null;
if (ioError != null) {
err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot create new file ''{0}'': {1}", new Object[] {
file, ioError.getMessage()
});
} else {
err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot create new file ''{0}''", file);
}
SVNErrorManager.error(err, ioError != null ? ioError : new Exception(), Level.FINE, SVNLogType.WC);
}
}
public static boolean createNewFile(File file) throws IOException {
if (file == null) {
return false;
}
boolean created = false;
int count = SVNFileUtil.isWindows ? FILE_CREATION_ATTEMPTS_COUNT : 1;
long sleep = 1;
while (!created && (count > 0)) {
IOException ioError = null;
try {
created = file.createNewFile();
} catch (IOException e) {
ioError = e;
}
if (ioError != null) {
if (count == 1) {
throw ioError;
}
try {
Thread.sleep(sleep);
} catch (InterruptedException ie) {
SVNDebugLog.getDefaultLog().log(SVNLogType.DEFAULT, ie, Level.FINEST);
}
if (sleep < 128) {
sleep = sleep * 2;
}
}
if (ioError == null && !created) {
return false;
}
count--;
}
return created;
}
/**
* An internal method for ASCII bytes to write only!
*
* @param file
* @param contents
* @throws SVNException
*/
public static void createFile(File file, String contents, String charSet) throws SVNException {
createEmptyFile(file);
if (contents == null || contents.length() == 0) {
return;
}
OutputStream os = null;
try {
os = SVNFileUtil.openFileForWriting(file);
if (charSet != null) {
os.write(contents.getBytes(charSet));
} else {
os.write(contents.getBytes());
}
} catch (IOException ioe) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot write to file ''{0}'': {1}", new Object[] {
file, ioe.getMessage()
});
SVNErrorManager.error(err, ioe, Level.FINE, SVNLogType.DEFAULT);
} catch (SVNException svne) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot write to file ''{0}''", file);
SVNErrorManager.error(err, svne, Level.FINE, SVNLogType.DEFAULT);
} finally {
SVNFileUtil.closeFile(os);
}
}
public static void writeToFile(File file, String contents, String charSet) throws SVNException {
if (contents == null || contents.length() == 0) {
return;
}
OutputStream os = null;
try {
os = SVNFileUtil.openFileForWriting(file);
if (charSet != null) {
os.write(contents.getBytes(charSet));
} else {
os.write(contents.getBytes());
}
} catch (IOException ioe) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot write to file ''{0}'': {1}", new Object[] {
file, ioe.getMessage()
});
SVNErrorManager.error(err, ioe, Level.FINE, SVNLogType.DEFAULT);
} catch (SVNException svne) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot write to file ''{0}''", file);
SVNErrorManager.error(err, svne, Level.FINE, SVNLogType.DEFAULT);
} finally {
SVNFileUtil.closeFile(os);
}
}
public static void writeToFile(File file, byte[] contents) throws SVNException {
if (contents == null) {
return;
}
OutputStream os = null;
try {
os = SVNFileUtil.openFileForWriting(file);
os.write(contents);
} catch (IOException ioe) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot write to file ''{0}'': {1}", new Object[] {
file, ioe.getMessage()
});
SVNErrorManager.error(err, ioe, Level.FINE, SVNLogType.DEFAULT);
} catch (SVNException svne) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot write to file ''{0}''", file);
SVNErrorManager.error(err, svne, Level.FINE, SVNLogType.DEFAULT);
} finally {
SVNFileUtil.closeFile(os);
}
}
public static void writeVersionFile(File file, int version) throws SVNException {
if (version < 0) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.INCORRECT_PARAMS, "Version {0} is not non-negative", new Integer(version));
SVNErrorManager.error(err, Level.FINE, SVNLogType.WC);
}
String contents = version + "\n";
File tmpFile = SVNFileUtil.createUniqueFile(SVNFileUtil.getFileDir(file), SVNFileUtil.getFileName(file), ".tmp", false);
OutputStream os = null;
try {
os = SVNFileUtil.openFileForWriting(tmpFile);
os.write(contents.getBytes("US-ASCII"));
} catch (IOException e) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e.getMessage());
SVNErrorManager.error(err, e, Level.FINE, SVNLogType.DEFAULT);
} finally {
SVNFileUtil.closeFile(os);
}
if (isWindows) {
setReadonly(file, false);
}
SVNFileUtil.rename(tmpFile, file);
setReadonly(file, true);
}
public static synchronized File createUniqueFile(File parent, String name, String suffix, boolean useUUIDGenerator) throws SVNException {
StringBuffer fileName = new StringBuffer();
fileName.append(name);
if (useUUIDGenerator) {
fileName.append(".");
fileName.append(SVNUUIDGenerator.generateUUIDString());
}
fileName.append(suffix);
File file = new File(parent, fileName.toString());
int i = 2;
do {
if (SVNFileType.getType(file) == SVNFileType.NONE) {
createEmptyFile(file);
return file;
}
fileName.setLength(0);
fileName.append(name);
fileName.append(".");
if (useUUIDGenerator) {
fileName.append(SVNUUIDGenerator.generateUUIDString());
} else {
fileName.append(i);
}
fileName.append(suffix);
file = new File(parent, fileName.toString());
i++;
} while (i < 99999);
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_UNIQUE_NAMES_EXHAUSTED, "Unable to make name for ''{0}''", new File(parent, name));
SVNErrorManager.error(err, Level.FINE, SVNLogType.WC);
return null;
}
public static synchronized File createUniqueDir(File parent, String name, String suffix, boolean useUUIDGenerator) throws SVNException {
StringBuffer fileName = new StringBuffer();
fileName.append(name);
if (useUUIDGenerator) {
fileName.append(".");
fileName.append(SVNUUIDGenerator.generateUUIDString());
}
fileName.append(suffix);
File file = new File(parent, fileName.toString());
int i = 2;
do {
if (SVNFileType.getType(file) == SVNFileType.NONE) {
file.mkdir();
return file;
}
fileName.setLength(0);
fileName.append(name);
fileName.append(".");
if (useUUIDGenerator) {
fileName.append(SVNUUIDGenerator.generateUUIDString());
} else {
fileName.append(i);
}
fileName.append(suffix);
file = new File(parent, fileName.toString());
i++;
} while (i < 99999);
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_UNIQUE_NAMES_EXHAUSTED, "Unable to make name for ''{0}''", new File(parent, name));
SVNErrorManager.error(err, Level.FINE, SVNLogType.WC);
return null;
}
public static void moveFile(File src, File dst) throws SVNException {
File tmpPath = SVNFileUtil.createUniqueFile(SVNFileUtil.getFileDir(dst), SVNFileUtil.getFileName(src), "tmp", false);
try {
SVNFileUtil.copyFile(src, tmpPath, true);
}
catch (SVNException ex) {
try {
SVNFileUtil.deleteFile(tmpPath);
} catch (SVNException ex2) {}
throw ex;
}
try {
SVNFileUtil.rename(tmpPath, dst);
}
catch (SVNException ex) {
try {
SVNFileUtil.deleteFile(tmpPath);
} catch (SVNException ex2) {}
throw ex;
}
try {
SVNFileUtil.deleteFile(src);
}
catch (SVNException ex) {
try {
SVNFileUtil.deleteFile(dst);
} catch (SVNException ex2) {}
throw ex;
}
}
public static void moveDir(File src, File dst) throws SVNException {
File tmpPath = SVNFileUtil.createUniqueDir(SVNFileUtil.getFileDir(dst), SVNFileUtil.getFileName(src), "tmp", false);
try {
SVNFileUtil.copyDirectory(src, tmpPath, false, null);
}
catch (SVNException ex) {
SVNFileUtil.deleteAll(tmpPath, true);
throw ex;
}
try {
SVNFileUtil.rename(tmpPath, dst);
}
catch (SVNException ex) {
SVNFileUtil.deleteAll(tmpPath, true);
throw ex;
}
try {
SVNFileUtil.deleteAll(src, true, null);
}
catch (SVNException ex) {
SVNFileUtil.deleteAll(dst, true);
throw ex;
}
}
/*
err = svn_io_remove_file2(from_path, FALSE, pool);
if (! err)
return SVN_NO_ERROR;
svn_error_clear(svn_io_remove_file2(to_path, FALSE, pool));
return err;
failed_tmp:
svn_error_clear(svn_io_remove_file2(tmp_to_path, FALSE, pool));
}
return err;
*/
public static void rename(File src, File dst) throws SVNException {
if (SVNFileType.getType(src) == SVNFileType.NONE) {
deleteFile(dst);
return;
}
//TODO directory cannot be renamed????
/*
if (dst.isDirectory()) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot rename file ''{0}'' to ''{1}''; file ''{1}'' is a directory", new Object[] {
src, dst
});
SVNErrorManager.error(err, Level.FINE, SVNLogType.WC);
}
*/
boolean renamed = false;
if (!isWindows) {
renamed = src.renameTo(dst);
if (!renamed && src.isFile() && !dst.exists()) {
copyFile(src, dst, true);
if (!dst.isFile()) {
copyFile(src, dst, false);
}
boolean deleted = deleteFile(src);
renamed = deleted && dst.isFile();
}
} else {
// check for os/2 first because on os/2
// isWindows is also true
if (isOS2) {
if (SVNOS2Util.moveFile(src, dst)) {
renamed = true;
}
} else if (SVNJNAUtil.moveFile(src, dst)) {
renamed = true;
}
if (!renamed) {
boolean caseOnly = dst.getAbsolutePath().equalsIgnoreCase(src.getAbsolutePath());
boolean wasRO = dst.exists() && !dst.canWrite();
setReadonly(src, false);
if (!caseOnly) {
setReadonly(dst, false);
}
// try simple atomic rename first
if (src.renameTo(dst)) {
return;
}
// use special loop on windows.
long sleep = 1;
for (int i = 0; i < FILE_CREATION_ATTEMPTS_COUNT; i++) {
if (!caseOnly) {
dst.delete();
}
if (src.renameTo(dst)) {
if (wasRO && !isOpenVMS) {
dst.setReadOnly();
}
return;
}
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
}
if (sleep < 128) {
sleep = sleep * 2;
}
}
}
}
if (!renamed) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot rename file ''{0}'' to ''{1}''", new Object[] {
src, dst
});
SVNErrorManager.error(err, Level.FINE, SVNLogType.WC);
}
}
public static boolean setReadonly(File file, boolean readonly) {
if (!file.exists()) {
return false;
}
if (isOpenVMS) {
// Never set readOnly for OpenVMS
return true;
}
if (readonly) {
return file.setReadOnly();
} else if (ourSetWritableMethod != null) {
try {
Object result = ourSetWritableMethod.invoke(file, new Object[] {
Boolean.TRUE
});
if (Boolean.TRUE.equals(result)) {
return true;
}
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
}
// check for os/2 first because on os/2
// isWindows is also true
if (isOS2) {
if (SVNOS2Util.setWritable(file)) {
return true;
}
} else if (isWindows) {
if (SVNJNAUtil.setWritable(file)) {
return true;
}
} else if (isLinux || isOSX || isBSD || SVNFileUtil.isSolaris) {
if (SVNJNAUtil.setWritable(file)) {
return true;
}
}
try {
SVNFileType fileType = SVNFileType.getType(file);
if (fileType == SVNFileType.FILE && useCopyOnSetWritable() && file.length() < 1024 * 100) {
// faster way for small files.
File tmp = createUniqueFile(SVNFileUtil.getFileDir(file), SVNFileUtil.getFileName(file), ".ro", true);
copyFile(file, tmp, false);
copyFile(tmp, file, false);
deleteFile(tmp);
} else {
if (isWindows) {
Process p = null;
try {
p = Runtime.getRuntime().exec(ATTRIB_COMMAND + " -R \"" + file.getAbsolutePath() + "\"");
p.waitFor();
} finally {
if (p != null) {
closeFile(p.getInputStream());
closeFile(p.getOutputStream());
closeFile(p.getErrorStream());
p.destroy();
}
}
} else {
execCommand(new String[] {
CHMOD_COMMAND, "ugo+w", file.getAbsolutePath()
});
}
}
} catch (Throwable th) {
SVNDebugLog.getDefaultLog().logFinest(SVNLogType.DEFAULT, th);
return false;
}
return true;
}
public static void setExecutable(File file, boolean executable) {
if (isWindows || isOpenVMS || file == null || !file.exists() || SVNFileType.getType(file) == SVNFileType.SYMLINK) {
return;
}
if (ourSetExecutableMethod != null) {
try {
ourSetExecutableMethod.invoke(file, new Object[] {
Boolean.valueOf(executable),
Boolean.FALSE,
});
return;
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
}
if (SVNJNAUtil.setExecutable(file, executable)) {
return;
}
try {
if (file.canWrite()) {
execCommand(new String[] {
CHMOD_COMMAND, executable ? "ugo+x" : "ugo-x", file.getAbsolutePath()
});
}
} catch (Throwable th) {
SVNDebugLog.getDefaultLog().logFinest(SVNLogType.DEFAULT, th);
}
}
public static boolean symlinksSupported() {
return !(isWindows || isOpenVMS) && SVNFileType.isSymlinkSupportEnabled();
}
public static void setSGID(File dir) {
if (isWindows || isOpenVMS || dir == null || !dir.exists() || !dir.isDirectory()) {
return;
}
if (SVNJNAUtil.setSGID(dir)) {
return;
}
try {
execCommand(new String[] {
CHMOD_COMMAND, "g+s", dir.getAbsolutePath()
});
} catch (Throwable th) {
SVNDebugLog.getDefaultLog().logFinest(SVNLogType.DEFAULT, th);
}
}
public static File resolveSymlinkToFile(File file) {
if (!symlinksSupported()) {
return null;
}
File targetFile = resolveSymlink(file);
if (targetFile == null || !targetFile.isFile()) {
return null;
}
return targetFile;
}
public static File resolveSymlink(File file) {
if (!symlinksSupported()) {
return null;
}
File targetFile = file;
while (SVNFileType.getType(targetFile) == SVNFileType.SYMLINK) {
String symlinkName = getSymlinkName(targetFile);
if (symlinkName == null) {
return null;
}
if (symlinkName.startsWith("/")) {
targetFile = new File(symlinkName);
} else {
targetFile = new File(SVNFileUtil.getFileDir(targetFile), symlinkName);
}
}
return targetFile;
}
public static void copy(File src, File dst, boolean safe, boolean copyAdminDirectories) throws SVNException {
SVNFileType srcType = SVNFileType.getType(src);
if (srcType == SVNFileType.FILE) {
copyFile(src, dst, safe);
} else if (srcType == SVNFileType.DIRECTORY) {
copyDirectory(src, dst, copyAdminDirectories, null);
} else if (srcType == SVNFileType.SYMLINK) {
String name = SVNFileUtil.getSymlinkName(src);
if (name != null) {
SVNFileUtil.createSymlink(dst, name);
}
}
}
public static void copyFile(File src, File dst, boolean safe) throws SVNException {
copyFile(src, dst, safe, true);
}
public static void copyFile(File src, File dst, boolean safe, boolean keepTimestamp) throws SVNException {
if (src == null || dst == null) {
return;
}
if (src.equals(dst)) {
return;
}
if (!src.exists()) {
dst.delete();
return;
}
File tmpDst = dst;
if (SVNFileType.getType(dst) != SVNFileType.NONE) {
if (safe && !useUnsafeCopyOnly()) {
tmpDst = createUniqueFile(SVNFileUtil.getFileDir(dst), ".copy", ".tmp", true);
} else {
dst.delete();
}
}
boolean executable = isExecutable(src);
SVNFileUtil.getFileDir(dst).mkdirs();
SVNErrorMessage error = null;
final boolean useNIO = useNIOCopying();
if (useNIO) {
FileChannel srcChannel = null;
FileChannel dstChannel = null;
FileInputStream is = null;
FileOutputStream os = null;
try {
is = createFileInputStream(src);
srcChannel = is.getChannel();
os = createFileOutputStream(tmpDst, false);
dstChannel = os.getChannel();
long totalSize = srcChannel.size();
long toCopy = totalSize;
while (toCopy > 0) {
toCopy -= dstChannel.transferFrom(srcChannel, totalSize - toCopy, toCopy);
}
} catch (IOException e) {
error = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot copy file ''{0}'' to ''{1}'': {2}", new Object[] {
src, dst, e.getLocalizedMessage()
});
} finally {
if (srcChannel != null) {
try {
srcChannel.close();
} catch (IOException e) {
//
}
}
if (dstChannel != null) {
try {
dstChannel.close();
} catch (IOException e) {
//
}
}
SVNFileUtil.closeFile(is);
SVNFileUtil.closeFile(os);
}
}
if (!useNIO || error != null) {
error = null;
InputStream sis = null;
OutputStream dos = null;
try {
sis = SVNFileUtil.openFileForReading(src, SVNLogType.WC);
dos = SVNFileUtil.openFileForWriting(tmpDst);
SVNTranslator.copy(sis, dos);
} catch (IOException e) {
error = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot copy file ''{0}'' to ''{1}'': {2}", new Object[] {
src, dst, e.getLocalizedMessage()
});
} finally {
SVNFileUtil.closeFile(dos);
SVNFileUtil.closeFile(sis);
}
}
if (error != null) {
SVNErrorManager.error(error, Level.FINE, SVNLogType.WC);
}
if (safe && tmpDst != dst) {
rename(tmpDst, dst);
}
if (executable) {
setExecutable(dst, true);
}
if (keepTimestamp) {
SVNFileUtil.setLastModified(dst, src.lastModified());
}
}
public static boolean setLastModified(File file, long timestamp) {
if (file != null && timestamp >= 0) {
return file.setLastModified(timestamp);
}
return false;
}
public static boolean createSymlink(File link, File linkName) throws SVNException {
if (!symlinksSupported()) {
return false;
}
if (SVNFileType.getType(link) != SVNFileType.NONE) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot create symbolic link ''{0}''; file already exists", link);
SVNErrorManager.error(err, Level.FINE, SVNLogType.WC);
}
String fileContents = "";
try {
fileContents = readSingleLine(linkName);
} catch (IOException e) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e.getMessage());
SVNErrorManager.error(err, e, Level.FINE, SVNLogType.DEFAULT);
}
if (fileContents.startsWith("link ")) {
fileContents = fileContents.substring("link".length()).trim();
return createSymlink(link, fileContents);
}
// create file using internal representation
createFile(link, fileContents, "UTF-8");
return true;
}
public static boolean createSymlink(File link, String linkName) {
if (!symlinksSupported()) {
return false;
}
if (SVNJNAUtil.createSymlink(link, linkName)) {
return true;
}
try {
execCommand(new String[] {
LN_COMMAND, "-s", linkName, link.getAbsolutePath()
});
} catch (Throwable th) {
SVNDebugLog.getDefaultLog().logFinest(SVNLogType.DEFAULT, th);
}
return SVNFileType.getType(link) == SVNFileType.SYMLINK;
}
public static boolean detranslateSymlink(File src, File linkFile) throws SVNException {
if (!symlinksSupported()) {
return false;
}
if (SVNFileType.getType(src) != SVNFileType.SYMLINK) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot detranslate symbolic link ''{0}''; file does not exist or not a symbolic link", src);
SVNErrorManager.error(err, Level.FINE, SVNLogType.WC);
}
String linkPath = getSymlinkName(src);
if (linkPath == null) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot detranslate symbolic link ''{0}''; file does not exist or not a symbolic link", src);
SVNErrorManager.error(err, Level.FINE, SVNLogType.WC);
}
OutputStream os = openFileForWriting(linkFile);
try {
os.write("link ".getBytes("UTF-8"));
os.write(linkPath.getBytes("UTF-8"));
} catch (IOException e) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e.getMessage());
SVNErrorManager.error(err, e, Level.FINE, SVNLogType.DEFAULT);
} finally {
SVNFileUtil.closeFile(os);
}
return true;
}
public static String getSymlinkName(File link) {
if (!symlinksSupported() || link == null) {
return null;
}
String ls = null;
ls = SVNJNAUtil.getLinkTarget(link);
if (ls != null) {
return ls;
}
try {
ls = execCommand(new String[] {
LS_COMMAND, "-ld", link.getAbsolutePath()
});
} catch (Throwable th) {
SVNDebugLog.getDefaultLog().logFinest(SVNLogType.DEFAULT, th);
}
if (ls == null || ls.lastIndexOf(" -> ") < 0) {
return null;
}
int index = ls.lastIndexOf(" -> ") + " -> ".length();
if (index <= ls.length()) {
return ls.substring(index);
}
return null;
}
public static void copySymlink(File source, File target) throws SVNException {
if (source.equals(target)) {
return;
}
SVNFileUtil.createSymlink(target, SVNFileUtil.getSymlinkName(source));
}
public static String computeChecksum(String line) {
if (line == null) {
return null;
}
MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
return null;
}
if (digest == null) {
return null;
}
digest.update(line.getBytes());
return toHexDigest(digest);
}
public static String computeChecksum(File file) throws SVNException {
if (file == null || file.isDirectory() || !file.exists()) {
return null;
}
MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "MD5 implementation not found: {0}", e.getMessage());
SVNErrorManager.error(err, e, Level.FINE, SVNLogType.DEFAULT);
return null;
}
InputStream is = openFileForReading(file, SVNLogType.WC);
byte[] buffer = new byte[1024 * 16];
try {
while (true) {
int l = is.read(buffer);
if (l < 0) {
break;
} else if (l == 0) {
continue;
}
digest.update(buffer, 0, l);
}
} catch (IOException e) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e.getMessage());
SVNErrorManager.error(err, e, Level.FINE, SVNLogType.DEFAULT);
} finally {
closeFile(is);
}
return toHexDigest(digest);
}
public static boolean compareFiles(File f1, File f2, MessageDigest digest) throws SVNException {
if (f1 == null || f2 == null) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.INCORRECT_PARAMS, "NULL paths are supported in compareFiles method");
SVNErrorManager.error(err, Level.FINE, SVNLogType.WC);
return false;
}
if (f1.equals(f2)) {
return true;
}
boolean equals = true;
if (f1.length() != f2.length()) {
if (digest == null) {
return false;
}
equals = false;
}
InputStream is1 = openFileForReading(f1, SVNLogType.WC);
InputStream is2 = openFileForReading(f2, SVNLogType.WC);
try {
while (true) {
int b1 = is1.read();
int b2 = is2.read();
if (b1 != b2) {
if (digest == null) {
return false;
}
equals = false;
}
if (b1 < 0) {
break;
}
if (digest != null) {
digest.update((byte) (b1 & 0xFF));
}
}
} catch (IOException e) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e.getMessage());
SVNErrorManager.error(err, e, Level.FINE, SVNLogType.DEFAULT);
} finally {
closeFile(is1);
closeFile(is2);
}
return equals;
}
public static void truncate(File file, long truncateToSize) throws IOException {
RandomAccessFile raf = null;
try {
raf = openRAFileForWriting(file, false);
raf.setLength(truncateToSize);
} catch (SVNException e) {
throw (IOException) new IOException(e.getMessage()).initCause(e);
} finally {
closeFile(raf);
}
}
public static void setHidden(File file, boolean hidden) {
// check for os/2 first because on os/2
// isWindows is also true
if (isOS2 && SVNOS2Util.setHidden(file, hidden)) {
return;
}
if (isWindows && SVNJNAUtil.setHidden(file)) {
return;
}
if (!isWindows || file == null || !file.exists() || file.isHidden()) {
return;
}
Process p = null;
try {
p = Runtime.getRuntime().exec("attrib " + (hidden ? "+" : "-") + "H \"" + file.getAbsolutePath() + "\"");
} catch (Throwable th) {
SVNDebugLog.getDefaultLog().logFinest(SVNLogType.DEFAULT, th);
} finally {
if (p != null) {
closeFile(p.getErrorStream());
closeFile(p.getInputStream());
closeFile(p.getOutputStream());
p.destroy();
}
}
}
public static void deleteAll(File dir, ISVNEventHandler cancelBaton) throws SVNException {
deleteAll(dir, true, cancelBaton);
}
public static void deleteAll(File dir, boolean deleteDirs) {
try {
deleteAll(dir, deleteDirs, null);
} catch (SVNException e) {
// should never happen as cancell handler is null.
}
}
public static void deleteAll(File dir, boolean deleteDirs, ISVNCanceller cancelBaton) throws SVNException {
if (dir == null) {
return;
}
SVNFileType fileType = SVNFileType.getType(dir);
File[] children = fileType == SVNFileType.DIRECTORY ? SVNFileListUtil.listFiles(dir) : null;
if (children != null) {
if (cancelBaton != null) {
cancelBaton.checkCancelled();
}
for (int i = 0; i < children.length; i++) {
File child = children[i];
deleteAll(child, deleteDirs, cancelBaton);
}
if (cancelBaton != null) {
cancelBaton.checkCancelled();
}
}
if (fileType == SVNFileType.DIRECTORY && !deleteDirs) {
return;
}
deleteFile(dir);
}
public static boolean deleteFile(File file) throws SVNException {
if (file == null) {
return true;
}
if (!isWindows || file.isDirectory() || !file.exists()) {
return file.delete();
}
long sleep = 1;
for (int i = 0; i < FILE_CREATION_ATTEMPTS_COUNT; i++) {
if (file.delete() && !file.exists()) {
return true;
}
if (!file.exists()) {
return true;
}
setReadonly(file, false);
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
}
if (sleep < 128) {
sleep = sleep * 2;
}
}
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot delete file ''{0}''", file);
SVNErrorManager.error(err, Level.FINE, SVNLogType.WC);
return false;
}
public static String toHexDigest(MessageDigest digest) {
if (digest == null) {
return null;
}
byte[] result = digest.digest();
StringBuffer hexDigest = new StringBuffer();
for (int i = 0; i < result.length; i++) {
SVNFormatUtil.appendHexNumber(hexDigest, result[i]);
}
return hexDigest.toString();
}
public static String toHexDigest(byte[] digest) {
if (digest == null) {
return null;
}
StringBuffer hexDigest = new StringBuffer();
for (int i = 0; i < digest.length; i++) {
SVNFormatUtil.appendHexNumber(hexDigest, digest[i]);
}
return hexDigest.toString();
}
public static byte[] fromHexDigest(String hexDigest) {
if (hexDigest == null || hexDigest.length() == 0) {
return null;
}
hexDigest = hexDigest.toLowerCase();
int digestLength = hexDigest.length() / 2;
if (digestLength == 0 || 2 * digestLength != hexDigest.length()) {
return null;
}
byte[] digest = new byte[digestLength];
for (int i = 0; i < hexDigest.length() / 2; i++) {
if (!isHex(hexDigest.charAt(2 * i)) || !isHex(hexDigest.charAt(2 * i + 1))) {
return null;
}
int hi = Character.digit(hexDigest.charAt(2 * i), 16) << 4;
int lo = Character.digit(hexDigest.charAt(2 * i + 1), 16);
Integer ib = new Integer(hi | lo);
byte b = ib.byteValue();
digest[i] = b;
}
return digest;
}
public static String getNativeEOLMarker(ISVNOptions options) {
if (nativeEOLMarker == null) {
nativeEOLMarker = new String(options.getNativeEOL());
}
return nativeEOLMarker;
}
public static long roundTimeStamp(long tstamp) {
return (tstamp / 1000) * 1000;
}
public static void sleepForTimestamp() {
if (!ourIsSleepForTimeStamp) {
return;
}
long time = System.currentTimeMillis();
time = 1100 - (time - (time / 1000) * 1000);
try {
Thread.sleep(time);
} catch (InterruptedException e) {
//
}
}
public static void setSleepForTimestamp(boolean sleep) {
ourIsSleepForTimeStamp = sleep;
}
public static String readLineFromStream(InputStream is, StringBuffer buffer, CharsetDecoder decoder) throws IOException {
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
int r = -1;
while ((r = is.read()) != '\n') {
if (r == -1) {
String out = decode(decoder, byteBuffer.toByteArray());
buffer.append(out);
return null;
}
byteBuffer.write(r);
}
String out = decode(decoder, byteBuffer.toByteArray());
buffer.append(out);
return out;
}
public static String detectMimeType(InputStream is) throws IOException {
byte[] buffer = new byte[1024];
int read = readIntoBuffer(is, buffer, 0, buffer.length);
int binaryCount = 0;
for (int i = 0; i < read; i++) {
byte b = buffer[i];
if (b == 0) {
return BINARY_MIME_TYPE;
}
if (b < 0x07 || (b > 0x0d && b < 0x20) || b > 0x7F) {
binaryCount++;
}
}
if (read > 0 && binaryCount * 1000 / read > 850) {
return BINARY_MIME_TYPE;
}
return null;
}
public static String detectMimeType(File file, Map<String,String> mimeTypes) throws SVNException {
if (file == null || !file.exists()) {
return null;
}
SVNFileType kind = SVNFileType.getType(file);
if (kind != SVNFileType.FILE) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.BAD_FILENAME, "Can''t detect MIME type of non-file ''{0}''", file);
SVNErrorManager.error(err, Level.FINE, SVNLogType.WC);
}
if (mimeTypes != null) {
String name = SVNFileUtil.getFileName(file);
String pathExt = "";
int dotInd = name.lastIndexOf('.');
if (dotInd != -1 && dotInd != 0 && dotInd != name.length() - 1) {
pathExt = name.substring(dotInd + 1);
}
String mimeType = (String) mimeTypes.get(pathExt);
if (mimeType != null) {
return mimeType;
}
}
InputStream is = null;
try {
is = openFileForReading(file, SVNLogType.WC);
return detectMimeType(is);
} catch (IOException e) {
return null;
} catch (SVNException e) {
return null;
} finally {
closeFile(is);
}
}
public static boolean isExecutable(File file) throws SVNException {
if (isWindows || isOpenVMS) {
return false;
}
Boolean executable = SVNJNAUtil.isExecutable(file);
if (executable != null) {
return executable.booleanValue();
}
String[] commandLine = new String[] {
LS_COMMAND, "-ln", file.getAbsolutePath()
};
String line = null;
try {
if (file.canRead()) {
line = execCommand(commandLine);
}
} catch (Throwable th) {
SVNDebugLog.getDefaultLog().logFinest(SVNLogType.DEFAULT, th);
}
if (line == null || line.indexOf(' ') < 0) {
return false;
}
int index = 0;
String mod = null;
String fuid = null;
String fgid = null;
for (StringTokenizer tokens = new StringTokenizer(line, " \t"); tokens.hasMoreTokens();) {
String token = tokens.nextToken();
if (index == 0) {
mod = token;
} else if (index == 2) {
fuid = token;
} else if (index == 3) {
fgid = token;
} else if (index > 3) {
break;
}
index++;
}
if (mod == null) {
return false;
}
if (getCurrentUser().equals(fuid)) {
return mod.toLowerCase().indexOf('x') >= 0 && mod.toLowerCase().indexOf('x') < 4;
} else if (getCurrentGroup().equals(fgid)) {
return mod.toLowerCase().indexOf('x', 4) >= 4 && mod.toLowerCase().indexOf('x', 4) < 7;
} else {
return mod.toLowerCase().indexOf('x', 7) >= 7;
}
}
public static File ensureDirectoryExists(File path) throws SVNException {
SVNFileType type = SVNFileType.getType(path);
SVNNodeKind kind = SVNFileType.getNodeKind(type);
if (kind != SVNNodeKind.NONE && kind != SVNNodeKind.DIR) {
SVNErrorMessage error = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "''{0}'' is not a directory", path);
SVNErrorManager.error(error, SVNLogType.WC);
} else if (kind == SVNNodeKind.NONE) {
boolean created = path.mkdirs();
if (!created) {
SVNErrorMessage error = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Unable to make directories", path);
SVNErrorManager.error(error, SVNLogType.WC);
}
}
return path;
}
public static void copyDirectory(File srcDir, File dstDir, boolean copyAdminDir, ISVNEventHandler cancel) throws SVNException {
if (!dstDir.exists()) {
dstDir.mkdirs();
SVNFileUtil.setLastModified(dstDir, srcDir.lastModified());
}
File[] files = SVNFileListUtil.listFiles(srcDir);
for (int i = 0; files != null && i < files.length; i++) {
File file = files[i];
if (SVNFileUtil.getFileName(file).equals("..") || SVNFileUtil.getFileName(file).equals(".") || file.equals(dstDir)) {
continue;
}
if (cancel != null) {
cancel.checkCancelled();
}
if (!copyAdminDir && SVNFileUtil.getFileName(file).equals(getAdminDirectoryName())) {
continue;
}
SVNFileType fileType = SVNFileType.getType(file);
File dst = new File(dstDir, SVNFileUtil.getFileName(file));
if (fileType == SVNFileType.FILE) {
boolean executable = isExecutable(file);
copyFile(file, dst, false);
if (executable) {
setExecutable(dst, executable);
}
} else if (fileType == SVNFileType.DIRECTORY) {
copyDirectory(file, dst, copyAdminDir, cancel);
if (file.isHidden() || getAdminDirectoryName().equals(SVNFileUtil.getFileName(file))) {
setHidden(dst, true);
}
} else if (fileType == SVNFileType.SYMLINK) {
String name = getSymlinkName(file);
if (name != null) {
createSymlink(dst, name);
}
}
}
}
public static OutputStream openFileForWriting(File file) throws SVNException {
return openFileForWriting(file, false);
}
public static OutputStream openFileForWriting(File file, boolean append) throws SVNException {
if (file == null) {
return null;
}
if (SVNFileUtil.getFileDir(file) != null && !SVNFileUtil.getFileDir(file).exists()) {
SVNFileUtil.getFileDir(file).mkdirs();
}
if (isOpenVMS && !append && file.isFile()) {
deleteFile(file);
} else if (file.isFile() && !file.canWrite()) {
// force writable.
setReadonly(file, false);
}
OutputStream fos = null;
OutputStream result = null;
try {
fos = createFileOutputStream(file, append);
result = new BufferedOutputStream(fos);
} catch (IOException e) {
closeFile(fos);
closeFile(result);
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot write to ''{0}'': {1}", new Object[] {
file, e.getMessage()
});
SVNErrorManager.error(err, e, Level.FINE, SVNLogType.DEFAULT);
} finally {
if (result == null) {
closeFile(fos);
}
}
return result;
}
public static FileOutputStream createFileOutputStream(File file, boolean append) throws IOException {
int retryCount = SVNFileUtil.isWindows ? FILE_CREATION_ATTEMPTS_COUNT : 1;
FileOutputStream os = null;
long sleep = 1;
for (int i = 0; i < retryCount; i++) {
try {
os = new FileOutputStream(file, append);
break;
} catch (IOException e) {
SVNFileUtil.closeFile(os);
if (i + 1 >= retryCount) {
throw e;
}
if (file.exists() && file.isFile() && file.canWrite()) {
try {
Thread.sleep(sleep);
} catch (InterruptedException e1) {
}
if (sleep < 128) {
sleep = sleep * 2;
}
continue;
}
throw e;
}
}
return os;
}
public static RandomAccessFile openRAFileForWriting(File file, boolean append) throws SVNException {
if (file == null) {
return null;
}
if (SVNFileUtil.getFileDir(file) != null && !SVNFileUtil.getFileDir(file).exists()) {
SVNFileUtil.getFileDir(file).mkdirs();
}
RandomAccessFile raf = null;
RandomAccessFile result = null;
try {
raf = new RandomAccessFile(file, "rw");
if (append) {
raf.seek(raf.length());
}
result = raf;
} catch (FileNotFoundException e) {
closeFile(raf);
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Can not write to file ''{0}'': {1}", new Object[] {
file, e.getMessage()
});
SVNErrorManager.error(err, e, Level.FINE, SVNLogType.DEFAULT);
} catch (IOException ioe) {
closeFile(raf);
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Can not set position pointer in file ''{0}'': {1}", new Object[] {
file, ioe.getMessage()
});
SVNErrorManager.error(err, ioe, Level.FINE, SVNLogType.DEFAULT);
} finally {
if (result == null) {
closeFile(raf);
}
}
return result;
}
public static InputStream openFileForReading(File file) throws SVNException {
return openFileForReading(file, Level.FINE, SVNLogType.DEFAULT);
}
public static InputStream openFileForReading(File file, SVNLogType logType) throws SVNException {
return openFileForReading(file, Level.FINE, logType);
}
public static InputStream openFileForReading(File file, Level logLevel, SVNLogType logType) throws SVNException {
if (file == null) {
return null;
}
InputStream fis = null;
InputStream result = null;
try {
fis = createFileInputStream(file);
result = new BufferedInputStream(fis);
} catch (FileNotFoundException nfe) {
closeFile(fis);
closeFile(result);
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot read from ''{0}'': {1}", new Object[] {
file, nfe.getMessage()
});
SVNErrorManager.error(err, logLevel, logType);
} catch (IOException e) {
closeFile(fis);
closeFile(result);
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot read from ''{0}'': {1}", new Object[] {
file, e.getMessage()
});
SVNErrorManager.error(err, e, logLevel, logType);
} finally {
if (result == null) {
closeFile(fis);
}
}
return result;
}
public static FileInputStream createFileInputStream(File file) throws IOException {
int retryCount = SVNFileUtil.isWindows ? FILE_CREATION_ATTEMPTS_COUNT : 1;
FileInputStream is = null;
long sleep = 1;
for (int i = 0; i < retryCount; i++) {
try {
is = new FileInputStream(file);
break;
} catch (IOException e) {
SVNFileUtil.closeFile(is);
if (i + 1 >= retryCount) {
throw e;
}
if (file.exists() && file.isFile() && file.canRead()) {
try {
Thread.sleep(sleep);
} catch (InterruptedException e1) {
}
if (sleep < 128) {
sleep = sleep * 2;
}
continue;
}
throw e;
}
}
return is;
}
public static RandomAccessFile openRAFileForReading(File file) throws SVNException {
if (file == null) {
return null;
}
if (!file.isFile() || !file.canRead()) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot read from ''{0}'': path refers to a directory or read access is denied", file);
SVNErrorManager.error(err, Level.FINE, SVNLogType.WC);
}
if (!file.exists()) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "File ''{0}'' does not exist", file);
SVNErrorManager.error(err, Level.FINE, SVNLogType.WC);
}
try {
return new RandomAccessFile(file, "r");
} catch (FileNotFoundException e) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot read from ''{0}'': {1}", new Object[] {
file, e.getMessage()
});
SVNErrorManager.error(err, Level.FINE, SVNLogType.WC);
}
return null;
}
public static void closeFile(InputStream is) {
if (is == null) {
return;
}
try {
is.close();
} catch (IOException e) {
//
}
}
public static void closeFile(ISVNInputFile inFile) {
if (inFile == null) {
return;
}
try {
inFile.close();
} catch (IOException e) {
//
}
}
public static void closeFile(OutputStream os) {
if (os == null) {
return;
}
try {
os.close();
} catch (IOException e) {
//
}
}
public static void closeFile(RandomAccessFile raf) {
if (raf == null) {
return;
}
try {
raf.close();
} catch (IOException e) {
//
}
}
public static String execCommand(String[] commandLine) throws SVNException {
return execCommand(commandLine, false, null);
}
public static String execCommand(String[] commandLine, boolean waitAfterRead, ISVNReturnValueCallback callback) throws SVNException {
return execCommand(commandLine, null, waitAfterRead, callback);
}
public static String execCommand(String[] commandLine, String[] env, boolean waitAfterRead, ISVNReturnValueCallback callback) throws SVNException {
InputStream is = null;
boolean handleOutput = callback != null && callback.isHandleProgramOutput();
StringBuffer result = handleOutput ? null : new StringBuffer();
Process process = null;
try {
process = Runtime.getRuntime().exec(commandLine, env);
is = process.getInputStream();
if (!waitAfterRead) {
int rc = process.waitFor();
if (callback != null) {
callback.handleReturnValue(rc);
}
if (rc != 0) {
return null;
}
}
int r;
while ((r = is.read()) >= 0) {
char ch = (char) (r & 0xFF);
if (handleOutput) {
callback.handleChar(ch);
} else {
result.append(ch);
}
}
if (waitAfterRead) {
int rc = process.waitFor();
if (callback != null) {
callback.handleReturnValue(rc);
}
if (rc != 0) {
return null;
}
}
return handleOutput ? null : result.toString().trim();
} catch (IOException e) {
SVNDebugLog.getDefaultLog().logFinest(SVNLogType.DEFAULT, e);
} catch (InterruptedException e) {
SVNDebugLog.getDefaultLog().logFinest(SVNLogType.DEFAULT, e);
} finally {
closeFile(is);
if (process != null) {
process.destroy();
}
}
return null;
}
public static void closeFile(Writer os) {
if (os != null) {
try {
os.close();
} catch (IOException e) {
//
}
}
}
public static void closeFile(Reader is) {
if (is != null) {
try {
is.close();
} catch (IOException e) {
//
}
}
}
public static String getAdminDirectoryName() {
if (ourAdminDirectoryName == null) {
String defaultAdminDir = ".svn";
if (getEnvironmentVariable("SVN_ASP_DOT_NET_HACK") != null) {
defaultAdminDir = "_svn";
}
ourAdminDirectoryName = System.getProperty("svnkit.admindir", System.getProperty("javasvn.admindir", defaultAdminDir));
if (ourAdminDirectoryName == null || "".equals(ourAdminDirectoryName.trim())) {
ourAdminDirectoryName = defaultAdminDir;
}
}
return ourAdminDirectoryName;
}
public static void setAdminDirectoryName(String name) {
ourAdminDirectoryName = name;
}
public static File getApplicationDataPath() {
if (ourAppDataPath != null) {
return ourAppDataPath;
}
String jnaAppData = SVNJNAUtil.getApplicationDataPath(false);
if (jnaAppData != null) {
ourAppDataPath = new File(jnaAppData);
return ourAppDataPath;
}
String envAppData = getEnvironmentVariable("APPDATA");
if (envAppData == null) {
// no appdata for that user, fallback to system one.
ourAppDataPath = getSystemApplicationDataPath();
} else {
ourAppDataPath = new File(envAppData);
}
return ourAppDataPath;
}
public static File getSystemApplicationDataPath() {
if (ourSystemAppDataPath != null) {
return ourSystemAppDataPath;
}
String jnaAppData = SVNJNAUtil.getApplicationDataPath(true);
if (jnaAppData != null) {
ourSystemAppDataPath = new File(jnaAppData);
return ourSystemAppDataPath;
}
String envAppData = getEnvironmentVariable("ALLUSERSPROFILE");
if (envAppData == null) {
ourSystemAppDataPath = new File(new File("C:/Documents and Settings/All Users"), "Application Data");
} else {
ourSystemAppDataPath = new File(envAppData, "Application Data");
}
return ourSystemAppDataPath;
}
public static String getEnvironmentVariable(String name) {
try {
// pre-Java 1.5 this throws an Error. On Java 1.5 it
// returns the environment variable
Method getenv = System.class.getMethod("getenv", new Class[] {
String.class
});
if (getenv != null) {
Object value = getenv.invoke(null, new Object[] {
name
});
if (value instanceof String) {
return (String) value;
}
}
} catch (Throwable e) {
try {
// This means we are on 1.4. Get all variables into
// a Properties object and get the variable from that
return getEnvironment().getProperty(name);
} catch (Throwable e1) {
SVNDebugLog.getDefaultLog().logFinest(SVNLogType.DEFAULT, e);
SVNDebugLog.getDefaultLog().logFinest(SVNLogType.DEFAULT, e1);
return null;
}
}
return null;
}
private static String ourTestEditor = null;
private static String ourTestMergeTool = null;
private static String ourTestFunction = null;
public static void setTestEnvironment(String editor, String mergeTool, String function) {
ourTestEditor = editor;
ourTestMergeTool = mergeTool;
ourTestFunction = function;
}
public static String[] getTestEnvironment() {
return new String[] {
ourTestEditor, ourTestMergeTool, ourTestFunction
};
}
public static Properties getEnvironment() throws Throwable {
Process p = null;
Properties envVars = new Properties();
Runtime r = Runtime.getRuntime();
if (isWindows) {
if (System.getProperty("os.name").toLowerCase().indexOf("windows 9") >= 0) {
p = r.exec("command.com /c set");
} else {
p = r.exec("cmd.exe /c set");
}
} else {
p = r.exec(ENV_COMMAND); // if OpenVMS ENV_COMMAND could be "mcr
// gnu:[bin]env"
}
if (p != null) {
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = br.readLine()) != null) {
int idx = line.indexOf('=');
if (idx >= 0) {
String key = line.substring(0, idx);
String value = line.substring(idx + 1);
envVars.setProperty(key, value);
}
}
}
return envVars;
}
public static File createTempDirectory(String name) throws SVNException {
File tmpFile = null;
try {
tmpFile = File.createTempFile("svnkit" + name, ".tmp");
} catch (IOException e) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot create temporary directory: {0}", e.getMessage());
SVNErrorManager.error(err, e, Level.FINE, SVNLogType.DEFAULT);
}
if (tmpFile.exists()) {
tmpFile.delete();
}
tmpFile.mkdirs();
return tmpFile;
}
public static File createTempFile(String prefix, String suffix) throws SVNException {
File tmpFile = null;
try {
if (prefix.length() < 3) {
prefix = "svn" + prefix;
}
tmpFile = File.createTempFile(prefix, suffix);
} catch (IOException e) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot create temporary file: {0}", e.getMessage());
SVNErrorManager.error(err, e, Level.FINE, SVNLogType.DEFAULT);
}
return tmpFile;
}
public static File getSystemConfigurationDirectory() {
if (isWindows) {
return new File(getSystemApplicationDataPath(), "Subversion");
} else if (isOpenVMS) {
return new File("/sys$config", "subversion").getAbsoluteFile();
}
return new File("/etc/subversion");
}
public static String readSingleLine(File file) throws IOException {
if (!file.isFile() || !file.canRead()) {
throw new IOException("can't open file '" + file.getAbsolutePath() + "'");
}
BufferedReader reader = null;
String line = null;
InputStream is = null;
try {
is = createFileInputStream(file);
reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
line = reader.readLine();
} finally {
closeFile(is);
}
return line;
}
private static String decode(CharsetDecoder decoder, byte[] in) {
ByteBuffer inBuf = ByteBuffer.wrap(in);
CharBuffer outBuf = CharBuffer.allocate(inBuf.capacity() * Math.round(decoder.maxCharsPerByte() + 0.5f));
decoder.decode(inBuf, outBuf, true);
decoder.flush(outBuf);
decoder.reset();
return outBuf.flip().toString();
}
public static String getCurrentUser() throws SVNException {
if (isWindows || isOpenVMS) {
return System.getProperty("user.name");
}
if (ourUserID == null) {
ourUserID = execCommand(new String[] {
ID_COMMAND, "-u"
});
if (ourUserID == null) {
ourUserID = "0";
}
}
return ourUserID;
}
public static String getCurrentGroup() throws SVNException {
if (isWindows || isOpenVMS) {
return System.getProperty("user.name");
}
if (ourGroupID == null) {
ourGroupID = execCommand(new String[] {
ID_COMMAND, "-g"
});
if (ourGroupID == null) {
ourGroupID = "0";
}
}
return ourGroupID;
}
private static boolean isHex(char ch) {
return Character.isDigit(ch) || (Character.toUpperCase(ch) >= 'A' && Character.toUpperCase(ch) <= 'F');
}
public static boolean isAbsolute(File path) {
return path != null && path.isAbsolute();
}
public static String getFilePath(File file) {
if (file == null)
return null;
String path = file.getPath();
if (File.separatorChar != '/') {
path = path.replace(File.separatorChar, '/');
}
return path;
}
public static String getFileName(File file) {
if (file == null)
return null;
return file.getName();
}
public static File getFileDir(File file) {
if (file == null || "".equals(file.getPath()))
return null;
File parentFile = file.getParentFile();
return parentFile != null ? parentFile : new File("");
}
public static File createFilePath(String path) {
if (path == null)
return null;
return new File(path);
}
public static File createFilePath(File parent, File child) {
if (child == null) {
return parent;
}
if (isAbsolute(child)) {
return child;
}
return createFilePath(parent, child.toString());
}
public static File createFilePath(File parent, String child) {
if (child == null)
return parent;
if (parent == null)
return createFilePath(child);
return createFilePath(parent.toString(), child.toString());
}
public static File createFilePath(String parent, String child) {
if (child == null)
return null;
if (parent == null || "".equals(parent))
return createFilePath(child);
if (SVNPathUtil.isAbsolute(child))
return createFilePath(child);
return new File(parent, child.toString());
}
public static File skipAncestor(File parent, File child) {
String parentPath = SVNFileUtil.getFilePath(parent);
String childPath = SVNFileUtil.getFilePath(child);
if (SVNPathUtil.isAncestor(parentPath, childPath)) {
return SVNFileUtil.createFilePath(SVNPathUtil.getRelativePath(parentPath, childPath));
}
return null;
}
public static String getFileExtension(File path) {
if (path == null)
return null;
return getFileNameExtension(path.getName());
}
public static String getFileNameExtension(String name) {
if (name == null)
return null;
int dotInd = name.lastIndexOf('.');
if (dotInd != -1 && dotInd != 0 && dotInd != name.length() - 1) {
return name.substring(dotInd + 1);
}
return null;
}
public static boolean compare(InputStream is, InputStream old) {
try {
while(true) {
int r1 = is.read();
int r2 = old.read();
if (r1 != r2) {
return false;
}
if (r1 < 0) {
break;
}
}
} catch (IOException e) {
return false;
}
return true;
}
public static InputStream readSymlink(File link) throws SVNException {
if (symlinksSupported()) {
SVNFileType type = SVNFileType.getType(link);
if (type == SVNFileType.SYMLINK) {
StringBuffer sb = new StringBuffer();
sb.append("link ");
sb.append(getSymlinkName(link));
try {
return new ByteArrayInputStream(sb.toString().getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
return new ByteArrayInputStream(sb.toString().getBytes());
}
}
}
return openFileForReading(link);
}
public static long getFileLength(File file) {
if (symlinksSupported()) {
SVNFileType type = SVNFileType.getType(file);
if (type == SVNFileType.SYMLINK) {
try {
return getSymlinkName(file).getBytes("UTF-8").length;
} catch (UnsupportedEncodingException e) {
return getSymlinkName(file).getBytes().length;
}
}
}
return file.length();
}
public static long getFileLastModified(File file) {
if (symlinksSupported()) {
SVNFileType type = SVNFileType.getType(file);
if (type == SVNFileType.SYMLINK) {
Long lastModified = SVNJNAUtil.getSymlinkLastModified(file);
if (lastModified != null) {
return lastModified;
}
try {
String output = execCommand(new String[]{
STAT_COMMAND, "-c", "%Y", file.getAbsolutePath()
});
if (output != null) {
try {
return Long.parseLong(output) * 1000;
} catch (NumberFormatException e) {
}
}
} catch (Throwable th) {
SVNDebugLog.getDefaultLog().logFinest(SVNLogType.DEFAULT, th);
}
}
}
return file.lastModified();
}
private static Method java7readAttributesMethod = null;
private static Method java7toPathMethod = null;
private static Method java7lastModifiedTimeMethod = null;
private static Method java7setLastModifiedTimeMethod = null;
private static Method java7toTimeMethod = null;
private static Method java7fromTimeMethod = null;
private static Class<?> java7BasciFileAttributesClazz = null;
private static Class<?> java7FileTimeClazz = null;
private static Object java7noFollowLinksParam= null;
static {
final ClassLoader loader = SVNFileUtil.class.getClassLoader();
try {
final Class<?> filesClazz = loader.loadClass("java.nio.file.Files");
final Class<?> pathClazz = loader.loadClass("java.nio.file.Path");
java7BasciFileAttributesClazz = loader.loadClass("java.nio.file.attribute.BasicFileAttributes");
final Class<?> linkOption = loader.loadClass("java.nio.file.LinkOption");
java7FileTimeClazz = loader.loadClass("java.nio.file.attribute.FileTime");
java7noFollowLinksParam = Array.newInstance(linkOption, 1);
if (linkOption.getEnumConstants() != null && linkOption.getEnumConstants().length >= 1) {
Array.set(java7noFollowLinksParam, 0, linkOption.getEnumConstants()[0]);
} else {
java7noFollowLinksParam = Array.newInstance(linkOption, 0);
}
java7readAttributesMethod = filesClazz.getMethod("readAttributes",
pathClazz, Class.class, java7noFollowLinksParam.getClass());
java7toPathMethod = File.class.getMethod("toPath");
java7lastModifiedTimeMethod = java7BasciFileAttributesClazz.getMethod("lastModifiedTime");
java7setLastModifiedTimeMethod = filesClazz.getMethod("setLastModifiedTime", pathClazz, java7FileTimeClazz);
java7toTimeMethod = java7FileTimeClazz.getMethod("to", TimeUnit.class);
java7fromTimeMethod = java7FileTimeClazz.getMethod("from", Long.TYPE, TimeUnit.class);
} catch (ClassNotFoundException e) {
java7BasciFileAttributesClazz = null;
} catch (NoSuchMethodException e) {
java7BasciFileAttributesClazz = null;
} catch (SecurityException e) {
java7BasciFileAttributesClazz = null;
}
}
public static void setFileLastModifiedMicros(File file, long timeInMicros) {
if (java7BasciFileAttributesClazz != null && timeInMicros >=0 && file != null) {
try {
final Object path = java7toPathMethod.invoke(file);
if (path != null) {
final Object fileTime = java7fromTimeMethod.invoke(null, timeInMicros, TimeUnit.MICROSECONDS);
if (fileTime != null) {
java7setLastModifiedTimeMethod.invoke(null, path, fileTime);
return;
}
}
} catch (SecurityException e) {
} catch (IllegalAccessException e) {
} catch (IllegalArgumentException e) {
} catch (InvocationTargetException e) {
}
}
setLastModified(file, timeInMicros / 1000);
}
public static long getFileLastModifiedMicros(File file) {
if (java7BasciFileAttributesClazz != null) {
try {
final Object path = java7toPathMethod.invoke(file);
if (path != null) {
final Object attrs = java7readAttributesMethod.invoke(null,
path,
java7BasciFileAttributesClazz,
java7noFollowLinksParam);
if (attrs != null) {
final Object time = java7lastModifiedTimeMethod.invoke(attrs);
if (time != null) {
final Object result = java7toTimeMethod.invoke(time, TimeUnit.MICROSECONDS);
if (result instanceof Long) {
return (Long) result;
}
}
}
}
} catch (SecurityException e) {
} catch (IllegalAccessException e) {
} catch (IllegalArgumentException e) {
} catch (InvocationTargetException e) {
}
}
return getFileLastModified(file) * 1000;
}
}