blob: 2c0d7fa60f286f3881c5c6f4f06856fe5d3a3793 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache license, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the license for the specific language governing permissions and
* limitations under the license.
*/
package org.apache.logging.log4j.core.util;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.GroupPrincipal;
import java.nio.file.attribute.PosixFileAttributeView;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.UserPrincipal;
import java.nio.file.attribute.UserPrincipalLookupService;
import java.util.Objects;
import java.util.Set;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.status.StatusLogger;
/**
* File utilities.
*/
public final class FileUtils {
/** Constant for the file URL protocol. */
private static final String PROTOCOL_FILE = "file";
private static final String JBOSS_FILE = "vfsfile";
private static final Logger LOGGER = StatusLogger.getLogger();
private FileUtils() {
}
/**
* Tries to convert the specified URI to a file object. If this fails, <b>null</b> is returned.
*
* @param uri the URI
* @return the resulting file object
*/
public static File fileFromUri(URI uri) {
if (uri == null) {
return null;
}
if (uri.isAbsolute()) {
if (JBOSS_FILE.equals(uri.getScheme())) try {
// patch the scheme
uri = new URI(PROTOCOL_FILE, uri.getSchemeSpecificPart(), uri.getFragment());
} catch (final URISyntaxException use) {
// should not happen, ignore
}
try {
if (PROTOCOL_FILE.equals(uri.getScheme())) {
return new File(uri);
}
} catch (final Exception ex) {
LOGGER.warn("Invalid URI {}", uri);
}
} else {
final File file = new File(uri.toString());
try {
if (file.exists()) {
return file;
}
final String path = uri.getPath();
return new File(path);
} catch (final Exception ex) {
LOGGER.warn("Invalid URI {}", uri);
}
}
return null;
}
public static boolean isFile(final URL url) {
return url != null && (url.getProtocol().equals(PROTOCOL_FILE) || url.getProtocol().equals(JBOSS_FILE));
}
public static String getFileExtension(final File file) {
final String fileName = file.getName();
if (fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") != 0) {
return fileName.substring(fileName.lastIndexOf(".") + 1);
}
return null;
}
/**
* Asserts that the given directory exists and creates it if necessary.
*
* @param dir the directory that shall exist
* @param createDirectoryIfNotExisting specifies if the directory shall be created if it does not exist.
* @throws java.io.IOException thrown if the directory could not be created.
*/
public static void mkdir(final File dir, final boolean createDirectoryIfNotExisting) throws IOException {
// commons io FileUtils.forceMkdir would be useful here, we just want to omit this dependency
if (!dir.exists()) {
if (!createDirectoryIfNotExisting) {
throw new IOException("The directory " + dir.getAbsolutePath() + " does not exist.");
}
if (!dir.mkdirs()) {
throw new IOException("Could not create directory " + dir.getAbsolutePath());
}
}
if (!dir.isDirectory()) {
throw new IOException("File " + dir + " exists and is not a directory. Unable to create directory.");
}
}
/**
* Creates the parent directories for the given File.
*
* @param file
* @throws IOException
*/
public static void makeParentDirs(final File file) throws IOException {
final File parent = Objects.requireNonNull(file, "file").getCanonicalFile().getParentFile();
if (parent != null) {
mkdir(parent, true);
}
}
/**
* Define file posix attribute view on a path/file.
*
* @param path Target path
* @param filePermissions Permissions to apply
* @param fileOwner File owner
* @param fileGroup File group
* @throws IOException If IO error during definition of file attribute view
*/
public static void defineFilePosixAttributeView(final Path path,
final Set<PosixFilePermission> filePermissions,
final String fileOwner,
final String fileGroup) throws IOException {
final PosixFileAttributeView view = Files.getFileAttributeView(path, PosixFileAttributeView.class);
if (view != null) {
final UserPrincipalLookupService lookupService = FileSystems.getDefault()
.getUserPrincipalLookupService();
if (fileOwner != null) {
final UserPrincipal userPrincipal = lookupService.lookupPrincipalByName(fileOwner);
if (userPrincipal != null) {
// If not sudoers member, it will throw Operation not permitted
// Only processes with an effective user ID equal to the user ID
// of the file or with appropriate privileges may change the ownership of a file.
// If _POSIX_CHOWN_RESTRICTED is in effect for path
view.setOwner(userPrincipal);
}
}
if (fileGroup != null) {
final GroupPrincipal groupPrincipal = lookupService.lookupPrincipalByGroupName(fileGroup);
if (groupPrincipal != null) {
// The current user id should be members of this group,
// if not will raise Operation not permitted
view.setGroup(groupPrincipal);
}
}
if (filePermissions != null) {
view.setPermissions(filePermissions);
}
}
}
/**
* Check if posix file attribute view is supported on the default FileSystem.
*
* @return true if posix file attribute view supported, false otherwise
*/
public static boolean isFilePosixAttributeViewSupported() {
return FileSystems.getDefault().supportedFileAttributeViews().contains("posix");
}
}