View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.util;
18  
19  import java.io.File;
20  import java.io.IOException;
21  import java.net.URI;
22  import java.net.URISyntaxException;
23  import java.net.URL;
24  import java.nio.file.FileSystems;
25  import java.nio.file.Files;
26  import java.nio.file.Path;
27  import java.nio.file.attribute.GroupPrincipal;
28  import java.nio.file.attribute.PosixFileAttributeView;
29  import java.nio.file.attribute.PosixFilePermission;
30  import java.nio.file.attribute.UserPrincipal;
31  import java.nio.file.attribute.UserPrincipalLookupService;
32  import java.util.Objects;
33  import java.util.Set;
34  
35  import org.apache.logging.log4j.Logger;
36  import org.apache.logging.log4j.status.StatusLogger;
37  
38  /**
39   * File utilities.
40   */
41  public final class FileUtils {
42  
43      /** Constant for the file URL protocol. */
44      private static final String PROTOCOL_FILE = "file";
45  
46      private static final String JBOSS_FILE = "vfsfile";
47  
48      private static final Logger LOGGER = StatusLogger.getLogger();
49  
50      private FileUtils() {
51      }
52  
53      /**
54       * Tries to convert the specified URI to a file object. If this fails, <b>null</b> is returned.
55       *
56       * @param uri the URI
57       * @return the resulting file object
58       */
59      public static File fileFromUri(URI uri) {
60          if (uri == null) {
61              return null;
62          }
63          if (uri.isAbsolute()) {
64              if (JBOSS_FILE.equals(uri.getScheme())) try {
65                  // patch the scheme
66                  uri = new URI(PROTOCOL_FILE, uri.getSchemeSpecificPart(), uri.getFragment());
67              } catch (URISyntaxException use) {
68                  // should not happen, ignore
69              }
70              try {
71                  if (PROTOCOL_FILE.equals(uri.getScheme())) {
72                      return new File(uri);
73                  }
74              } catch (final Exception ex) {
75                  LOGGER.warn("Invalid URI {}", uri);
76              }
77          } else {
78              File file = new File(uri.toString());
79              try {
80                  if (file.exists()) {
81                      return file;
82                  }
83                  final String path = uri.getPath();
84                  return new File(path);
85              } catch (final Exception ex) {
86                  LOGGER.warn("Invalid URI {}", uri);
87              }
88          }
89          return null;
90      }
91  
92      public static boolean isFile(final URL url) {
93          return url != null && (url.getProtocol().equals(PROTOCOL_FILE) || url.getProtocol().equals(JBOSS_FILE));
94      }
95  
96      public static String getFileExtension(final File file) {
97          final String fileName = file.getName();
98          if (fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") != 0) {
99              return fileName.substring(fileName.lastIndexOf(".") + 1);
100         }
101         return null;
102     }
103 
104     /**
105      * Asserts that the given directory exists and creates it if necessary.
106      * 
107      * @param dir the directory that shall exist
108      * @param createDirectoryIfNotExisting specifies if the directory shall be created if it does not exist.
109      * @throws java.io.IOException thrown if the directory could not be created.
110      */
111     public static void mkdir(final File dir, final boolean createDirectoryIfNotExisting) throws IOException {
112         // commons io FileUtils.forceMkdir would be useful here, we just want to omit this dependency
113         if (!dir.exists()) {
114             if (!createDirectoryIfNotExisting) {
115                 throw new IOException("The directory " + dir.getAbsolutePath() + " does not exist.");
116             }
117             if (!dir.mkdirs()) {
118                 throw new IOException("Could not create directory " + dir.getAbsolutePath());
119             }
120         }
121         if (!dir.isDirectory()) {
122             throw new IOException("File " + dir + " exists and is not a directory. Unable to create directory.");
123         }
124     }
125     
126     /**
127      * Creates the parent directories for the given File.
128      * 
129      * @param file
130      * @throws IOException
131      */
132     public static void makeParentDirs(final File file) throws IOException {
133         final File parent = Objects.requireNonNull(file, "file").getCanonicalFile().getParentFile();
134         if (parent != null) {
135             mkdir(parent, true);
136         }
137     }
138 
139     /**
140      * Define file posix attribute view on a path/file.
141      *
142      * @param path Target path
143      * @param filePermissions Permissions to apply
144      * @param fileOwner File owner
145      * @param fileGroup File group
146      * @throws IOException If IO error during definition of file attribute view
147      */
148     public static void defineFilePosixAttributeView(final Path path,
149             final Set<PosixFilePermission> filePermissions,
150             final String fileOwner,
151             final String fileGroup) throws IOException {
152         final PosixFileAttributeView view = Files.getFileAttributeView(path, PosixFileAttributeView.class);
153         if (view != null) {
154             final UserPrincipalLookupService lookupService = FileSystems.getDefault()
155                     .getUserPrincipalLookupService();
156             if (fileOwner != null) {
157                 final UserPrincipal userPrincipal = lookupService.lookupPrincipalByName(fileOwner);
158                 if (userPrincipal != null) {
159                     // If not sudoers member, it will throw Operation not permitted
160                     // Only processes with an effective user ID equal to the user ID
161                     // of the file or with appropriate privileges may change the ownership of a file.
162                     // If _POSIX_CHOWN_RESTRICTED is in effect for path
163                     view.setOwner(userPrincipal);
164                 }
165             }
166             if (fileGroup != null) {
167                 final GroupPrincipal groupPrincipal = lookupService.lookupPrincipalByGroupName(fileGroup);
168                 if (groupPrincipal != null) {
169                     // The current user id should be members of this group,
170                     // if not will raise Operation not permitted
171                     view.setGroup(groupPrincipal);
172                 }
173             }
174             if (filePermissions != null) {
175                 view.setPermissions(filePermissions);
176             }
177         }
178     }
179 
180     /**
181      * Check if posix file attribute view is supported on the default FileSystem.
182      *
183      * @return true if posix file attribute view supported, false otherwise
184      */
185     public static boolean isFilePosixAttributeViewSupported() {
186         return FileSystems.getDefault().supportedFileAttributeViews().contains("posix");
187     }
188 }