    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements. See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache license, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License. You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the license for the specific language governing permissions and
    015     * limitations under the license.
    016     */
    017    package org.apache.logging.log4j.core.util;
    018
    019    import java.io.File;
    020    import java.io.IOException;
    021    import java.io.UnsupportedEncodingException;
    022    import java.net.MalformedURLException;
    023    import java.net.URI;
    024    import java.net.URISyntaxException;
    025    import java.net.URL;
    026    import java.net.URLDecoder;
    027    import java.util.regex.Pattern;
    028
    029    import org.apache.logging.log4j.Logger;
    030    import org.apache.logging.log4j.status.StatusLogger;
    031
    032    /**
    033     * File utilities.
    034     */
    035    public final class FileUtils {
    036
    037        /** Constant for the file URL protocol.*/
    038        private static final String PROTOCOL_FILE = "file";
    039
    040        private static final String JBOSS_FILE = "vfsfile";
    041
    042        private static final Logger LOGGER = StatusLogger.getLogger();
    043        private static final Pattern WINDOWS_DIRECTORY_SEPARATOR = Pattern.compile("\\\\+");
    044
    045        private FileUtils() {
    046        }
    047
    048          /**
    049         * Tries to convert the specified URI to a file object. If this fails,
    050         * <b>null</b> is returned.
    051         *
    052         * @param uri the URI
    053         * @return the resulting file object
    054         */
    055        public static File fileFromUri(URI uri) {
    056            // There MUST be a better way to do this. TODO Search other ASL projects...
    057            if (uri == null
    058                    || (uri.getScheme() != null && (!PROTOCOL_FILE.equals(uri.getScheme()) && !JBOSS_FILE.equals(uri
    059                            .getScheme())))) {
    060                return null;
    061            }
    062            if (uri.getScheme() == null) {
    063                File file = new File(uri.toString());
    064                if (file.exists()) {
    065                    return file;
    066                }
    067                try {
    068                    final String path = uri.getPath();
    069                    file = new File(path);
    070                    if (file.exists()) {
    071                        return file;
    072                    }
    073                    uri = new File(path).toURI();
    074                } catch (final Exception ex) {
    075                    LOGGER.warn("Invalid URI {}", uri);
    076                    return null;
    077                }
    078            }
    079            final String charsetName = Constants.UTF_8.name();
    080            try {
    081                String fileName = uri.toURL().getFile();
    082                if (new File(fileName).exists()) { // LOG4J2-466
    083                    return new File(fileName); // allow files with '+' char in name
    084                }
    085                fileName = URLDecoder.decode(fileName, charsetName);
    086                return new File(fileName);
    087            } catch (final MalformedURLException ex) {
    088                LOGGER.warn("Invalid URL {}", uri, ex);
    089            } catch (final UnsupportedEncodingException uee) {
    090                LOGGER.warn("Invalid encoding: {}", charsetName, uee);
    091            }
    092            return null;
    093        }
    094
    095        public static boolean isFile(final URL url) {
    096            return url != null && (url.getProtocol().equals(PROTOCOL_FILE) || url.getProtocol().equals(JBOSS_FILE));
    097        }
    098
    099        /**
    100         * Asserts that the given directory exists and creates it if necessary.
    101         * @param dir the directory that shall exist
    102         * @param createDirectoryIfNotExisting specifies if the directory shall be created if it does not exist.
    103         * @throws java.io.IOException thrown if the directory could not be created.
    104         */
    105        public static void mkdir(final File dir, final boolean createDirectoryIfNotExisting ) throws IOException {
    106            // commons io FileUtils.forceMkdir would be useful here, we just want to omit this dependency
    107            if (!dir.exists()) {
    108                if(!createDirectoryIfNotExisting) {
    109                    throw new IOException("The directory " + dir.getAbsolutePath() + " does not exist.");
    110                }
    111                if(!dir.mkdirs()) {
    112                    throw new IOException("Could not create directory " + dir.getAbsolutePath());
    113                }
    114            }
    115            if (!dir.isDirectory()) {
    116                throw new IOException("File " + dir + " exists and is not a directory. Unable to create directory.");
    117            }
    118        }
    119
    120        /**
    121         * Takes a given URI string which may contain backslashes (illegal in URIs) in it due to user input or variable
    122         * substitution and returns a URI with the backslashes replaced with forward slashes.
    123         *
    124         * @param uri The URI string
    125         * @return the URI.
    126         * @throws URISyntaxException if instantiating the URI threw a {@code URISyntaxException}.
    127         */
    128        public static URI getCorrectedFilePathUri(final String uri) throws URISyntaxException {
    129            return new URI(WINDOWS_DIRECTORY_SEPARATOR.matcher(uri).replaceAll("/"));
    130        }
    131    }