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