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.activemq.util; 018 019import java.io.File; 020import java.io.FileInputStream; 021import java.io.FileOutputStream; 022import java.io.FilenameFilter; 023import java.io.IOException; 024import java.io.InputStream; 025import java.io.OutputStream; 026import java.util.ArrayList; 027import java.util.List; 028import java.util.Stack; 029 030/** 031 * 032 */ 033public final class IOHelper { 034 035 protected static final int MAX_DIR_NAME_LENGTH; 036 protected static final int MAX_FILE_NAME_LENGTH; 037 private static final int DEFAULT_BUFFER_SIZE = 4096; 038 039 private IOHelper() { 040 } 041 042 public static String getDefaultDataDirectory() { 043 return getDefaultDirectoryPrefix() + "activemq-data"; 044 } 045 046 public static String getDefaultStoreDirectory() { 047 return getDefaultDirectoryPrefix() + "amqstore"; 048 } 049 050 /** 051 * Allows a system property to be used to overload the default data 052 * directory which can be useful for forcing the test cases to use a target/ 053 * prefix 054 */ 055 public static String getDefaultDirectoryPrefix() { 056 try { 057 return System.getProperty("org.apache.activemq.default.directory.prefix", ""); 058 } catch (Exception e) { 059 return ""; 060 } 061 } 062 063 /** 064 * Converts any string into a string that is safe to use as a file name. The 065 * result will only include ascii characters and numbers, and the "-","_", 066 * and "." characters. 067 * 068 * @param name 069 * @return 070 */ 071 public static String toFileSystemDirectorySafeName(String name) { 072 return toFileSystemSafeName(name, true, MAX_DIR_NAME_LENGTH); 073 } 074 075 public static String toFileSystemSafeName(String name) { 076 return toFileSystemSafeName(name, false, MAX_FILE_NAME_LENGTH); 077 } 078 079 /** 080 * Converts any string into a string that is safe to use as a file name. The 081 * result will only include ascii characters and numbers, and the "-","_", 082 * and "." characters. 083 * 084 * @param name 085 * @param dirSeparators 086 * @param maxFileLength 087 * @return 088 */ 089 public static String toFileSystemSafeName(String name, boolean dirSeparators, int maxFileLength) { 090 int size = name.length(); 091 StringBuffer rc = new StringBuffer(size * 2); 092 for (int i = 0; i < size; i++) { 093 char c = name.charAt(i); 094 boolean valid = c >= 'a' && c <= 'z'; 095 valid = valid || (c >= 'A' && c <= 'Z'); 096 valid = valid || (c >= '0' && c <= '9'); 097 valid = valid || (c == '_') || (c == '-') || (c == '.') || (c == '#') || (dirSeparators && ((c == '/') || (c == '\\'))); 098 099 if (valid) { 100 rc.append(c); 101 } else { 102 // Encode the character using hex notation 103 rc.append('#'); 104 rc.append(HexSupport.toHexFromInt(c, true)); 105 } 106 } 107 String result = rc.toString(); 108 if (result.length() > maxFileLength) { 109 result = result.substring(result.length() - maxFileLength, result.length()); 110 } 111 return result; 112 } 113 114 public static boolean delete(File top) { 115 boolean result = true; 116 Stack<File> files = new Stack<File>(); 117 // Add file to the stack to be processed... 118 files.push(top); 119 // Process all files until none remain... 120 while (!files.isEmpty()) { 121 File file = files.pop(); 122 if (file.isDirectory()) { 123 File list[] = file.listFiles(); 124 if (list == null || list.length == 0) { 125 // The current directory contains no entries... 126 // delete directory and continue... 127 result &= file.delete(); 128 } else { 129 // Add back the directory since it is not empty.... 130 // and when we process it again it will be empty and can be 131 // deleted safely... 132 files.push(file); 133 for (File dirFile : list) { 134 if (dirFile.isDirectory()) { 135 // Place the directory on the stack... 136 files.push(dirFile); 137 } else { 138 // This is a simple file, delete it... 139 result &= dirFile.delete(); 140 } 141 } 142 } 143 } else { 144 // This is a simple file, delete it... 145 result &= file.delete(); 146 } 147 } 148 return result; 149 } 150 151 public static boolean deleteFile(File fileToDelete) { 152 if (fileToDelete == null || !fileToDelete.exists()) { 153 return true; 154 } 155 boolean result = deleteChildren(fileToDelete); 156 result &= fileToDelete.delete(); 157 return result; 158 } 159 160 public static boolean deleteChildren(File parent) { 161 if (parent == null || !parent.exists()) { 162 return false; 163 } 164 boolean result = true; 165 if (parent.isDirectory()) { 166 File[] files = parent.listFiles(); 167 if (files == null) { 168 result = false; 169 } else { 170 for (int i = 0; i < files.length; i++) { 171 File file = files[i]; 172 if (file.getName().equals(".") || file.getName().equals("..")) { 173 continue; 174 } 175 if (file.isDirectory()) { 176 result &= deleteFile(file); 177 } else { 178 result &= file.delete(); 179 } 180 } 181 } 182 } 183 184 return result; 185 } 186 187 public static void moveFile(File src, File targetDirectory) throws IOException { 188 if (!src.renameTo(new File(targetDirectory, src.getName()))) { 189 throw new IOException("Failed to move " + src + " to " + targetDirectory); 190 } 191 } 192 193 public static void moveFiles(File srcDirectory, File targetDirectory, FilenameFilter filter) throws IOException { 194 if (!srcDirectory.isDirectory()) { 195 throw new IOException("source is not a directory"); 196 } 197 198 if (targetDirectory.exists() && !targetDirectory.isDirectory()) { 199 throw new IOException("target exists and is not a directory"); 200 } else { 201 mkdirs(targetDirectory); 202 } 203 204 List<File> filesToMove = new ArrayList<File>(); 205 getFiles(srcDirectory, filesToMove, filter); 206 207 for (File file : filesToMove) { 208 if (!file.isDirectory()) { 209 moveFile(file, targetDirectory); 210 } 211 } 212 } 213 214 public static void copyFile(File src, File dest) throws IOException { 215 copyFile(src, dest, null); 216 } 217 218 public static void copyFile(File src, File dest, FilenameFilter filter) throws IOException { 219 if (src.getCanonicalPath().equals(dest.getCanonicalPath()) == false) { 220 if (src.isDirectory()) { 221 222 mkdirs(dest); 223 List<File> list = getFiles(src, filter); 224 for (File f : list) { 225 if (f.isFile()) { 226 File target = new File(getCopyParent(src, dest, f), f.getName()); 227 copySingleFile(f, target); 228 } 229 } 230 231 } else if (dest.isDirectory()) { 232 mkdirs(dest); 233 File target = new File(dest, src.getName()); 234 copySingleFile(src, target); 235 } else { 236 copySingleFile(src, dest); 237 } 238 } 239 } 240 241 static File getCopyParent(File from, File to, File src) { 242 File result = null; 243 File parent = src.getParentFile(); 244 String fromPath = from.getAbsolutePath(); 245 if (parent.getAbsolutePath().equals(fromPath)) { 246 // one level down 247 result = to; 248 } else { 249 String parentPath = parent.getAbsolutePath(); 250 String path = parentPath.substring(fromPath.length()); 251 result = new File(to.getAbsolutePath() + File.separator + path); 252 } 253 return result; 254 } 255 256 static List<File> getFiles(File dir, FilenameFilter filter) { 257 List<File> result = new ArrayList<File>(); 258 getFiles(dir, result, filter); 259 return result; 260 } 261 262 static void getFiles(File dir, List<File> list, FilenameFilter filter) { 263 if (!list.contains(dir)) { 264 list.add(dir); 265 String[] fileNames = dir.list(filter); 266 for (int i = 0; i < fileNames.length; i++) { 267 File f = new File(dir, fileNames[i]); 268 if (f.isFile()) { 269 list.add(f); 270 } else { 271 getFiles(dir, list, filter); 272 } 273 } 274 } 275 } 276 277 public static void copySingleFile(File src, File dest) throws IOException { 278 FileInputStream fileSrc = new FileInputStream(src); 279 FileOutputStream fileDest = new FileOutputStream(dest); 280 copyInputStream(fileSrc, fileDest); 281 } 282 283 public static void copyInputStream(InputStream in, OutputStream out) throws IOException { 284 byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; 285 int len = in.read(buffer); 286 while (len >= 0) { 287 out.write(buffer, 0, len); 288 len = in.read(buffer); 289 } 290 in.close(); 291 out.close(); 292 } 293 294 static { 295 MAX_DIR_NAME_LENGTH = Integer.getInteger("MaximumDirNameLength", 200); 296 MAX_FILE_NAME_LENGTH = Integer.getInteger("MaximumFileNameLength", 64); 297 } 298 299 public static int getMaxDirNameLength() { 300 return MAX_DIR_NAME_LENGTH; 301 } 302 303 public static int getMaxFileNameLength() { 304 return MAX_FILE_NAME_LENGTH; 305 } 306 307 public static void mkdirs(File dir) throws IOException { 308 if (dir.exists()) { 309 if (!dir.isDirectory()) { 310 throw new IOException("Failed to create directory '" + dir + 311 "', regular file already existed with that name"); 312 } 313 314 } else { 315 if (!dir.mkdirs()) { 316 throw new IOException("Failed to create directory '" + dir + "'"); 317 } 318 } 319 } 320}