/* * ==================================================================== * 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.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.*; import org.tmatesoft.svn.core.SVNDepth; import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNMergeRangeList; import org.tmatesoft.svn.core.SVNNodeKind; import org.tmatesoft.svn.core.SVNProperties; import org.tmatesoft.svn.core.SVNProperty; import org.tmatesoft.svn.core.SVNPropertyValue; import org.tmatesoft.svn.core.internal.util.SVNHashMap; import org.tmatesoft.svn.core.internal.util.SVNHashSet; import org.tmatesoft.svn.core.internal.util.SVNMergeInfoUtil; import org.tmatesoft.svn.core.internal.wc.admin.ISVNEntryHandler; import org.tmatesoft.svn.core.internal.wc.admin.SVNAdminArea; import org.tmatesoft.svn.core.internal.wc.admin.SVNEntry; import org.tmatesoft.svn.core.internal.wc.admin.SVNLog; import org.tmatesoft.svn.core.internal.wc.admin.SVNTranslator; import org.tmatesoft.svn.core.internal.wc.admin.SVNTranslatorOutputStream; import org.tmatesoft.svn.core.internal.wc.admin.SVNVersionedProperties; import org.tmatesoft.svn.core.internal.wc.admin.SVNWCAccess; import org.tmatesoft.svn.core.wc.ISVNOptions; import org.tmatesoft.svn.core.wc.SVNEvent; import org.tmatesoft.svn.core.wc.SVNEventAction; import org.tmatesoft.svn.core.wc.SVNStatusType; import org.tmatesoft.svn.util.SVNLogType; /** * @author TMate Software Ltd. * @version 1.3 */ public class SVNPropertiesManager { private static final Collection NOT_ALLOWED_FOR_FILE = new SVNHashSet(); private static final Collection NOT_ALLOWED_FOR_DIR = new SVNHashSet(); static { NOT_ALLOWED_FOR_FILE.add(SVNProperty.IGNORE); NOT_ALLOWED_FOR_FILE.add(SVNProperty.EXTERNALS); NOT_ALLOWED_FOR_FILE.add(SVNProperty.INHERITABLE_IGNORES); NOT_ALLOWED_FOR_FILE.add(SVNProperty.INHERITABLE_AUTO_PROPS); NOT_ALLOWED_FOR_DIR.add(SVNProperty.EXECUTABLE); NOT_ALLOWED_FOR_DIR.add(SVNProperty.KEYWORDS); NOT_ALLOWED_FOR_DIR.add(SVNProperty.EOL_STYLE); NOT_ALLOWED_FOR_DIR.add(SVNProperty.CHARSET); NOT_ALLOWED_FOR_DIR.add(SVNProperty.NEEDS_LOCK); NOT_ALLOWED_FOR_DIR.add(SVNProperty.MIME_TYPE); } public static void validateRevisionProperties(SVNProperties revisionProperties) throws SVNException { if (hasSVNProperties(revisionProperties)) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_PROPERTY_NAME, "Standard properties can't be set explicitly as revision properties"); SVNErrorManager.error(err, SVNLogType.NETWORK); } } public static boolean setWCProperty(SVNWCAccess access, File path, String propName, SVNPropertyValue propValue, boolean write) throws SVNException { SVNEntry entry = access.getVersionedEntry(path, false); SVNAdminArea dir = entry.getKind() == SVNNodeKind.DIR ? access.retrieve(path) : access.retrieve(path.getParentFile()); SVNVersionedProperties wcProps = dir.getWCProperties(entry.getName()); SVNPropertyValue oldValue = wcProps.getPropertyValue(propName); wcProps.setPropertyValue(propName, propValue); if (write) { dir.saveWCProperties(false); } return oldValue == null ? propValue != null : !oldValue.equals(propValue); } public static SVNPropertyValue getWCProperty(SVNWCAccess access, File path, String propName) throws SVNException { SVNEntry entry = access.getEntry(path, false); if (entry == null) { return null; } SVNAdminArea dir = entry.getKind() == SVNNodeKind.DIR ? access.retrieve(path) : access.retrieve(path.getParentFile()); return dir.getWCProperties(entry.getName()).getPropertyValue(propName); } public static void deleteWCProperties(SVNAdminArea dir, String name, boolean recursive) throws SVNException { if (name != null) { SVNVersionedProperties props = dir.getWCProperties(name); if (props != null) { props.removeAll(); } } if (recursive || name == null) { for (Iterator entries = dir.entries(false); entries.hasNext();) { SVNEntry entry = (SVNEntry) entries.next(); SVNVersionedProperties props = dir.getWCProperties(entry.getName()); if (props != null) { props.removeAll(); } if (entry.isFile() || dir.getThisDirName().equals(entry.getName())) { continue; } if (recursive) { SVNAdminArea childDir = dir.getWCAccess().retrieve(dir.getFile(entry.getName())); deleteWCProperties(childDir, null, true); } } } dir.saveWCProperties(false); } public static SVNPropertyValue getProperty(SVNWCAccess access, File path, String propName) throws SVNException { SVNEntry entry = access.getEntry(path, false); if (entry == null) { return null; } String[] cachableProperties = entry.getCachableProperties(); if (cachableProperties != null && contains(cachableProperties, propName)) { String[] presentProperties = entry.getPresentProperties(); if (presentProperties == null || !contains(presentProperties, propName)) { return null; } if (SVNProperty.isBooleanProperty(propName)) { return SVNProperty.getValueOfBooleanProperty(propName); } } if (SVNProperty.isWorkingCopyProperty(propName)) { return getWCProperty(access, path, propName); } else if (SVNProperty.isEntryProperty(propName)) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.BAD_PROP_KIND, "Property ''{0}'' is an entry property", propName); SVNErrorManager.error(err, SVNLogType.DEFAULT); } SVNAdminArea dir = entry.getKind() == SVNNodeKind.DIR ? access.retrieve(path) : access.retrieve(path.getParentFile()); return dir.getProperties(entry.getName()).getPropertyValue(propName); } public static boolean setProperty(final SVNWCAccess access, final File path, final String propName, SVNPropertyValue propValue, boolean skipChecks) throws SVNException { if (SVNProperty.isWorkingCopyProperty(propName)) { return setWCProperty(access, path, propName, propValue, true); } else if (SVNProperty.isEntryProperty(propName)) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.BAD_PROP_KIND, "Property ''{0}'' is an entry property", propName); SVNErrorManager.error(err, SVNLogType.DEFAULT); } SVNEntry entry = access.getVersionedEntry(path, false); SVNAdminArea dir = entry.isDirectory() ? access.retrieve(path) : access.retrieve(path.getParentFile()); boolean updateTimeStamp = SVNProperty.EOL_STYLE.equals(propName) || SVNProperty.CHARSET.equals(propName); if (propValue != null && SVNProperty.isSVNProperty(propName)) { propValue = validatePropertyValue(path, entry.getKind(), propName, propValue, skipChecks, access.getOptions(), new ISVNFileContentFetcher() { public void fetchFileContent(OutputStream os) throws SVNException { InputStream is = SVNFileUtil.openFileForReading(path, SVNLogType.WC); try { SVNTranslator.copy(is, os); } catch (IOExceptionWrapper ioew) { throw ioew.getOriginalException(); } catch (IOException e) { SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e, SVNLogType.DEFAULT); } finally { SVNFileUtil.closeFile(is); } } public boolean fileIsBinary() throws SVNException { SVNPropertyValue mimeType = SVNPropertiesManager.getProperty(access, path, SVNProperty.MIME_TYPE); return mimeType != null && SVNProperty.isBinaryMimeType(mimeType.getString()); } public SVNPropertyValue getProperty(String propertyName) throws SVNException { return SVNPropertiesManager.getProperty(access, path, propertyName); } }); } if (entry.getKind() == SVNNodeKind.FILE && SVNProperty.EXECUTABLE.equals(propName)) { if (propValue == null) { SVNFileUtil.setExecutable(path, false); } else { propValue = SVNProperty.getValueOfBooleanProperty(propName); SVNFileUtil.setExecutable(path, true); } } if (entry.getKind() == SVNNodeKind.FILE && SVNProperty.NEEDS_LOCK.equals(propName)) { if (propValue == null) { SVNFileUtil.setReadonly(path, false); } else { propValue = SVNProperty.getValueOfBooleanProperty(propName); } } SVNVersionedProperties properties = dir.getProperties(entry.getName()); SVNPropertyValue oldValue = properties.getPropertyValue(propName); SVNEventAction action; if (oldValue == null) { if (propValue == null) { action = SVNEventAction.PROPERTY_DELETE_NONEXISTENT; } else { action = SVNEventAction.PROPERTY_ADD; } } else { if (propValue == null) { action = SVNEventAction.PROPERTY_DELETE; } else { action = SVNEventAction.PROPERTY_MODIFY; } } if (!updateTimeStamp && (entry.getKind() == SVNNodeKind.FILE && SVNProperty.KEYWORDS.equals(propName))) { Collection oldKeywords = getKeywords(oldValue == null ? null : oldValue.getString()); Collection newKeywords = getKeywords(propValue == null ? null : propValue.getString()); updateTimeStamp = !oldKeywords.equals(newKeywords); } SVNLog log = dir.getLog(); if (updateTimeStamp) { SVNProperties command = new SVNProperties(); command.put(SVNLog.NAME_ATTR, entry.getName()); command.put(SVNProperty.shortPropertyName(SVNProperty.TEXT_TIME), (String) null); log.addCommand(SVNLog.MODIFY_ENTRY, command, false); } properties.setPropertyValue(propName, propValue); dir.saveVersionedProperties(log, false); log.save(); dir.runLogs(); final boolean modified = oldValue == null ? propValue != null : !oldValue.equals(propValue); if (modified || action == SVNEventAction.PROPERTY_DELETE_NONEXISTENT) { dir.getWCAccess().handleEvent(new SVNEvent(path, entry.getKind(), null, -1, null, null, null, null, action, action, null, null, null, null, null)); } return modified; } public static SVNStatusType mergeProperties(SVNWCAccess wcAccess, File path, SVNProperties baseProperties, SVNProperties diff, boolean baseMerge, boolean dryRun) throws SVNException { SVNEntry entry = wcAccess.getVersionedEntry(path, false); File parent = null; String name = null; if (entry.isDirectory()) { parent = path; name = ""; } else if (entry.isFile()) { parent = path.getParentFile(); name = entry.getName(); } SVNLog log = null; SVNAdminArea dir = wcAccess.retrieve(parent); if (!dryRun) { log = dir.getLog(); } SVNStatusType result = dir.mergeProperties(name, baseProperties, diff, null, null, baseMerge, dryRun, log); if (!dryRun) { log.save(); dir.runLogs(); } return result; } public static Map computeAutoProperties(ISVNOptions options, File file, Map properties) throws SVNException { properties = options.applyAutoProperties(file, properties); if (!properties.containsKey(SVNProperty.MIME_TYPE)) { String mimeType = SVNFileUtil.detectMimeType(file, options.getFileExtensionsToMimeTypes()); if (mimeType != null) { properties.put(SVNProperty.MIME_TYPE, mimeType); } } if (SVNProperty.isBinaryMimeType((String) properties.get(SVNProperty.MIME_TYPE))) { properties.remove(SVNProperty.EOL_STYLE); properties.remove(SVNProperty.CHARSET); } if (!properties.containsKey(SVNProperty.EXECUTABLE)) { if (SVNFileUtil.isExecutable(file)) { properties.put(SVNProperty.EXECUTABLE, ""); } } return properties; } public static Map getWorkingCopyPropertyValues(File path, SVNEntry entry, final String propName, SVNDepth depth, final boolean base) throws SVNException { final Map pathsToPropValues = new SVNHashMap(); ISVNEntryHandler handler = new ISVNEntryHandler() { public void handleEntry(File itemPath, SVNEntry itemEntry) throws SVNException { SVNAdminArea adminArea = itemEntry.getAdminArea(); if (itemEntry.isDirectory() && !itemEntry.getName().equals(adminArea.getThisDirName())) { return; } if ((itemEntry.isScheduledForAddition() && base) || (itemEntry.isScheduledForDeletion() && !base)) { return; } SVNPropertyValue propValue = null; SVNWCAccess access = adminArea.getWCAccess(); if (base) { SVNEntry pathEntry = access.getEntry(itemPath, false); if (pathEntry != null) { SVNAdminArea pathArea = pathEntry.getAdminArea(); SVNVersionedProperties baseProps = pathArea.getBaseProperties(pathEntry.getName()); propValue = baseProps.getPropertyValue(propName); } } else { SVNEntry pathEntry = access.getEntry(itemPath, true); if (pathEntry != null) { SVNAdminArea pathArea = pathEntry.getAdminArea(); SVNVersionedProperties workingProps = pathArea.getProperties(pathEntry.getName()); propValue = workingProps.getPropertyValue(propName); } } if (propValue != null) { pathsToPropValues.put(itemPath, propValue); } } public void handleError(File path, SVNErrorMessage error) throws SVNException { while (error.hasChildErrorMessage()) { error = error.getChildErrorMessage(); } if (error.getErrorCode() == SVNErrorCode.WC_PATH_NOT_FOUND) { return; } SVNErrorManager.error(error, SVNLogType.WC); } }; if (depth == SVNDepth.UNKNOWN) { depth = SVNDepth.INFINITY; } SVNAdminArea adminArea = entry.getAdminArea(); if (entry.isDirectory() && depth.compareTo(SVNDepth.FILES) >= 0) { SVNWCAccess wcAccess = adminArea.getWCAccess(); wcAccess.walkEntries(path, handler, false, depth); } else { handler.handleEntry(path, entry); } return pathsToPropValues; } public static void recordWCMergeInfo(File path, Map mergeInfo, SVNWCAccess wcAccess) throws SVNException { SVNPropertyValue value = null; if (mergeInfo != null) { value = SVNPropertyValue.create(SVNMergeInfoUtil.formatMergeInfoToString(mergeInfo, null)); } setProperty(wcAccess, path, SVNProperty.MERGE_INFO, value, true); } public static Map parseMergeInfo(File path, SVNEntry entry, boolean base) throws SVNException { Map fileToProp = SVNPropertiesManager.getWorkingCopyPropertyValues(path, entry, SVNProperty.MERGE_INFO, SVNDepth.EMPTY, base); Map result = null; SVNPropertyValue propValue = (SVNPropertyValue) fileToProp.get(path); if (propValue != null && propValue.getString() != null) { result = SVNMergeInfoUtil.parseMergeInfo(new StringBuffer(propValue.getString()), result); } return result; } public static boolean isValidPropertyName(String name) throws SVNException { if (name == null || name.length() == 0) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_PROPERTY_NAME, "Property name is empty"); SVNErrorManager.error(err, SVNLogType.DEFAULT); } if (!(Character.isLetter(name.charAt(0)) || name.charAt(0) == ':' || name.charAt(0) == '_')) { return false; } for (int i = 1; i < name.length(); i++) { if (!(Character.isLetterOrDigit(name.charAt(i)) || name.charAt(i) == '-' || name.charAt(i) == '.' || name.charAt(i) == ':' || name.charAt(i) == '_')) { return false; } } return true; } public static boolean propNeedsTranslation(String propertyName) { return SVNProperty.isSVNProperty(propertyName); } private static Collection getKeywords(String value) { Collection keywords = new SVNHashSet(); if (value == null || "".equals(value.trim())) { return keywords; } for (StringTokenizer tokens = new StringTokenizer(value, " \t\n\r"); tokens.hasMoreTokens();) { keywords.add(tokens.nextToken().toLowerCase()); } return keywords; } private static boolean contains(String[] values, String value) { for (int i = 0; value != null && i < values.length; i++) { if (values[i].equals(value)) { return true; } } return false; } public static SVNPropertyValue validatePropertyValue(Object path, SVNNodeKind kind, String name, SVNPropertyValue value, boolean force, ISVNOptions options, ISVNFileContentFetcher fileContentFetcher) throws SVNException { if (value == null) { return value; } validatePropertyName(path, name, kind); if (SVNProperty.isSVNProperty(name) && value.isString()) { String str = value.getString(); str = str.replaceAll("\r\n", "\n"); str = str.replace('\r', '\n'); value = SVNPropertyValue.create(str); } if (!force && SVNProperty.EOL_STYLE.equals(name)) { value = SVNPropertyValue.create(value.getString().trim()); if (SVNTranslator.getEOL(value.getString(), options) == null) { SVNErrorMessage error = SVNErrorMessage.create(SVNErrorCode.IO_UNKNOWN_EOL, "Unrecognized line ending style for ''{0}''", path); SVNErrorManager.error(error, SVNLogType.DEFAULT); } validateEOLProperty(path, fileContentFetcher); } else if (!force && SVNProperty.CHARSET.equals(name)) { value = SVNPropertyValue.create(value.getString().trim()); try { SVNTranslator.getCharset(value.getString(), null, path, options); } catch (SVNException e) { SVNErrorMessage error = SVNErrorMessage.create(SVNErrorCode.ILLEGAL_TARGET, "Charset ''{0}'' is not supported on this computer", value.getString()); SVNErrorManager.error(error, SVNLogType.DEFAULT); } if (fileContentFetcher != null && fileContentFetcher.fileIsBinary()) { SVNErrorMessage error = SVNErrorMessage.create(SVNErrorCode.ILLEGAL_TARGET, "File ''{0}'' has binary mime type property", path); SVNErrorManager.error(error, SVNLogType.DEFAULT); } } else if (!force && SVNProperty.MIME_TYPE.equals(name)) { value = SVNPropertyValue.create(value.getString().trim()); validateMimeType(value.getString()); if (SVNProperty.isBinaryMimeType(value.getString())) { if (fileContentFetcher != null && fileContentFetcher.getProperty(SVNProperty.EOL_STYLE) != null) { SVNErrorMessage error = SVNErrorMessage.create(SVNErrorCode.ILLEGAL_TARGET, "File ''{0}'' has svn:eol-style property set and thus cannot have binary mime type", path); SVNErrorManager.error(error, SVNLogType.DEFAULT); } } } else if (SVNProperty.IGNORE.equals(name) || SVNProperty.INHERITABLE_IGNORES.equals(name) || SVNProperty.EXTERNALS.equals(name)) { if (!value.getString().endsWith("\n")) { value = SVNPropertyValue.create(value.getString().concat("\n")); } if (SVNProperty.EXTERNALS.equals(name)) { SVNExternal[] externals = SVNExternal.parseExternals(path, value.getString()); List<String> duplicateTargets = SVNExternal.findTargetDuplications(externals); if (duplicateTargets != null && duplicateTargets.size() > 0) { StringBuilder moreString = new StringBuilder(); if (duplicateTargets.size() > 1) { moreString.append(" (").append(duplicateTargets.size()).append(" more duplicate targets found)"); } String absolutePath = path instanceof File ? ((File) path).getAbsolutePath() : new File(path.toString()).getAbsolutePath(); SVNErrorMessage errorMessage = SVNErrorMessage.create(SVNErrorCode.WC_DUPLICATE_EXTERNALS_TARGET, "Invalid {0} property on ''{1}'': " + "target ''{2}'' appears more than once{3}", SVNProperty.EXTERNALS, absolutePath, duplicateTargets.get(0), moreString.toString()); SVNErrorManager.error(errorMessage, SVNLogType.WC); } } } else if (SVNProperty.KEYWORDS.equals(name)) { value = SVNPropertyValue.create(value.getString().trim()); } else if (SVNProperty.EXECUTABLE.equals(name) || SVNProperty.SPECIAL.equals(name) || SVNProperty.NEEDS_LOCK.equals(name)) { value = SVNPropertyValue.create("*"); } else if (SVNProperty.MERGE_INFO.equals(name)) { Map<String, SVNMergeRangeList> mergeInfo = SVNMergeInfoUtil.parseMergeInfo(new StringBuffer(value.getString()), null); if (kind != SVNNodeKind.DIR && SVNMergeInfoUtil.isNonInheritable(mergeInfo)) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.MERGE_INFO_PARSE_ERROR, "Cannot set non-inheritable mergeinfo on a non-directory (''{0}'')", path); SVNErrorManager.error(err, SVNLogType.WC); } if (mergeInfo != null) { value = SVNPropertyValue.create(SVNMergeInfoUtil.formatMergeInfoToString(mergeInfo, null)); } } return value; } private static boolean hasSVNProperties(SVNProperties props) { if (props == null) { return false; } for (Iterator names = props.nameSet().iterator(); names.hasNext();) { String propName = (String) names.next(); if (SVNProperty.isSVNProperty(propName)) { return true; } } return false; } private static void validatePropertyName(Object path, String name, SVNNodeKind kind) throws SVNException { SVNErrorMessage err = null; if (kind == SVNNodeKind.DIR) { if (NOT_ALLOWED_FOR_DIR.contains(name)) { err = SVNErrorMessage.create(SVNErrorCode.ILLEGAL_TARGET, "Cannot set ''{0}'' on a directory (''{1}'')", new Object[]{name, path}); } } else if (kind == SVNNodeKind.FILE) { if (NOT_ALLOWED_FOR_FILE.contains(name)) { err = SVNErrorMessage.create(SVNErrorCode.ILLEGAL_TARGET, "Cannot set ''{0}'' on a file (''{1}'')", new Object[]{name, path}); } } else { err = SVNErrorMessage.create(SVNErrorCode.NODE_UNEXPECTED_KIND, "''{0}'' is not a file or directory", path); } if (err != null) { SVNErrorManager.error(err, SVNLogType.DEFAULT); } } public static void validateMimeType(String value) throws SVNException { String type = value.indexOf(';') >= 0 ? value.substring(0, value.indexOf(';')) : value; SVNErrorMessage err = null; if (type.length() == 0) { err = SVNErrorMessage.create(SVNErrorCode.BAD_MIME_TYPE, "MIME type ''{0}'' has empty media type", value); } else if (type.indexOf('/') < 0) { err = SVNErrorMessage.create(SVNErrorCode.BAD_MIME_TYPE, "MIME type ''{0}'' does not contain ''/''", value); } else if (!Character.isLetterOrDigit(type.charAt(type.length() - 1))) { err = SVNErrorMessage.create(SVNErrorCode.BAD_MIME_TYPE, "MIME type ''{0}'' ends with non-alphanumeric character", value); } if (err != null) { SVNErrorManager.error(err, SVNLogType.DEFAULT); } } public static String determineEncodingByMimeType(String mimeType) { if (mimeType == null) { return null; } if (!SVNProperty.isTextMimeType(mimeType)) { return null; } for (StringTokenizer tokenizer = new StringTokenizer(mimeType, ";", false); tokenizer.hasMoreTokens();) { String token = tokenizer.nextToken(); token = token.trim(); if (!token.startsWith("charset")) { continue; } token = token.substring("charset".length()).trim(); if (!token.startsWith("=")) { continue; } return token.substring("=".length()).trim(); } return null; } public static void validateEOLProperty(Object path, ISVNFileContentFetcher fetcher) throws SVNException { if (fetcher == null) { return; } final SVNPropertyValue charset = fetcher.getProperty(SVNProperty.CHARSET); final OutputStream out = SVNTranslator.getTranslatingOutputStream(SVNFileUtil.DUMMY_OUT, SVNPropertyValue.getPropertyAsString(charset), new byte[0], false, null, false); try { fetcher.fetchFileContent(out); } catch (SVNException e) { handleInconsistentEOL(e, path); throw e; } finally { try { out.close(); } catch (IOExceptionWrapper wrapper) { handleInconsistentEOL(wrapper.getOriginalException(), path); throw wrapper.getOriginalException(); } catch (IOException e) { SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), SVNLogType.DEFAULT); } } if (fetcher.fileIsBinary()) { SVNErrorMessage error = SVNErrorMessage.create(SVNErrorCode.ILLEGAL_TARGET, "File ''{0}'' has binary mime type property", path); SVNErrorManager.error(error, SVNLogType.WC); } } private static void handleInconsistentEOL(SVNException svne, Object path) throws SVNException { SVNErrorMessage errorMessage = svne.getErrorMessage(); while (errorMessage != null && errorMessage.getErrorCode() != SVNErrorCode.IO_INCONSISTENT_EOL) { errorMessage = errorMessage.getChildErrorMessage(); } if (errorMessage != null && errorMessage.getErrorCode() == SVNErrorCode.IO_INCONSISTENT_EOL) { SVNErrorMessage error = SVNErrorMessage.create(SVNErrorCode.ILLEGAL_TARGET, "File ''{0}'' has inconsistent newlines", path); SVNErrorManager.error(error, SVNLogType.DEFAULT); } Throwable cause = svne.getCause(); if (cause == null) { return; } if (cause instanceof SVNException) { handleInconsistentEOL((SVNException) cause, path); } else if (cause instanceof IOExceptionWrapper) { IOExceptionWrapper wrapper = (IOExceptionWrapper) cause; handleInconsistentEOL(wrapper.getOriginalException(), path); } } }