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 */ 017package org.apache.logging.log4j.core.util; 018 019import java.io.File; 020import java.io.IOException; 021import java.net.URI; 022import java.net.URISyntaxException; 023import java.net.URL; 024import java.nio.file.FileSystems; 025import java.nio.file.Files; 026import java.nio.file.Path; 027import java.nio.file.attribute.GroupPrincipal; 028import java.nio.file.attribute.PosixFileAttributeView; 029import java.nio.file.attribute.PosixFilePermission; 030import java.nio.file.attribute.UserPrincipal; 031import java.nio.file.attribute.UserPrincipalLookupService; 032import java.util.Objects; 033import java.util.Set; 034 035import org.apache.logging.log4j.Logger; 036import org.apache.logging.log4j.status.StatusLogger; 037 038/** 039 * File utilities. 040 */ 041public final class FileUtils { 042 043 /** Constant for the file URL protocol. */ 044 private static final String PROTOCOL_FILE = "file"; 045 046 private static final String JBOSS_FILE = "vfsfile"; 047 048 private static final Logger LOGGER = StatusLogger.getLogger(); 049 050 private FileUtils() { 051 } 052 053 /** 054 * Tries to convert the specified URI to a file object. If this fails, <b>null</b> is returned. 055 * 056 * @param uri the URI 057 * @return the resulting file object 058 */ 059 public static File fileFromUri(URI uri) { 060 if (uri == null) { 061 return null; 062 } 063 if (uri.isAbsolute()) { 064 if (JBOSS_FILE.equals(uri.getScheme())) { 065 try { 066 // patch the scheme 067 uri = new URI(PROTOCOL_FILE, uri.getSchemeSpecificPart(), uri.getFragment()); 068 } catch (URISyntaxException use) { 069 // should not happen, ignore 070 } 071 } 072 try { 073 if (PROTOCOL_FILE.equals(uri.getScheme())) { 074 return new File(uri); 075 } 076 } catch (final Exception ex) { 077 LOGGER.warn("Invalid URI {}", uri); 078 } 079 } else { 080 File file = new File(uri.toString()); 081 try { 082 if (file.exists()) { 083 return file; 084 } 085 final String path = uri.getPath(); 086 return new File(path); 087 } catch (final Exception ex) { 088 LOGGER.warn("Invalid URI {}", uri); 089 } 090 } 091 return null; 092 } 093 094 public static boolean isFile(final URL url) { 095 return url != null && (url.getProtocol().equals(PROTOCOL_FILE) || url.getProtocol().equals(JBOSS_FILE)); 096 } 097 098 public static String getFileExtension(final File file) { 099 final String fileName = file.getName(); 100 if (fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") != 0) { 101 return fileName.substring(fileName.lastIndexOf(".") + 1); 102 } 103 return null; 104 } 105 106 /** 107 * Asserts that the given directory exists and creates it if necessary. 108 * 109 * @param dir the directory that shall exist 110 * @param createDirectoryIfNotExisting specifies if the directory shall be created if it does not exist. 111 * @throws java.io.IOException thrown if the directory could not be created. 112 */ 113 public static void mkdir(final File dir, final boolean createDirectoryIfNotExisting) throws IOException { 114 // commons io FileUtils.forceMkdir would be useful here, we just want to omit this dependency 115 if (!dir.exists()) { 116 if (!createDirectoryIfNotExisting) { 117 throw new IOException("The directory " + dir.getAbsolutePath() + " does not exist."); 118 } 119 if (!dir.mkdirs()) { 120 throw new IOException("Could not create directory " + dir.getAbsolutePath()); 121 } 122 } 123 if (!dir.isDirectory()) { 124 throw new IOException("File " + dir + " exists and is not a directory. Unable to create directory."); 125 } 126 } 127 128 /** 129 * Creates the parent directories for the given File. 130 * 131 * @param file 132 * @throws IOException 133 */ 134 public static void makeParentDirs(final File file) throws IOException { 135 final File parent = Objects.requireNonNull(file, "file").getCanonicalFile().getParentFile(); 136 if (parent != null) { 137 mkdir(parent, true); 138 } 139 } 140 141 /** 142 * Define file posix attribute view on a path/file. 143 * 144 * @param path Target path 145 * @param filePermissions Permissions to apply 146 * @param fileOwner File owner 147 * @param fileGroup File group 148 * @throws IOException If IO error during definition of file attribute view 149 */ 150 public static void defineFilePosixAttributeView(final Path path, 151 final Set<PosixFilePermission> filePermissions, 152 final String fileOwner, 153 final String fileGroup) throws IOException { 154 final PosixFileAttributeView view = Files.getFileAttributeView(path, PosixFileAttributeView.class); 155 if (view != null) { 156 final UserPrincipalLookupService lookupService = FileSystems.getDefault() 157 .getUserPrincipalLookupService(); 158 if (fileOwner != null) { 159 final UserPrincipal userPrincipal = lookupService.lookupPrincipalByName(fileOwner); 160 if (userPrincipal != null) { 161 // If not sudoers member, it will throw Operation not permitted 162 // Only processes with an effective user ID equal to the user ID 163 // of the file or with appropriate privileges may change the ownership of a file. 164 // If _POSIX_CHOWN_RESTRICTED is in effect for path 165 view.setOwner(userPrincipal); 166 } 167 } 168 if (fileGroup != null) { 169 final GroupPrincipal groupPrincipal = lookupService.lookupPrincipalByGroupName(fileGroup); 170 if (groupPrincipal != null) { 171 // The current user id should be members of this group, 172 // if not will raise Operation not permitted 173 view.setGroup(groupPrincipal); 174 } 175 } 176 if (filePermissions != null) { 177 view.setPermissions(filePermissions); 178 } 179 } 180 } 181 182 /** 183 * Check if posix file attribute view is supported on the default FileSystem. 184 * 185 * @return true if posix file attribute view supported, false otherwise 186 */ 187 public static boolean isFilePosixAttributeViewSupported() { 188 return FileSystems.getDefault().supportedFileAttributeViews().contains("posix"); 189 } 190}