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     */
017    package org.apache.activemq.util;
018    
019    import java.io.File;
020    import java.io.FileInputStream;
021    import java.io.FileOutputStream;
022    import java.io.FilenameFilter;
023    import java.io.IOException;
024    import java.io.InputStream;
025    import java.io.OutputStream;
026    import java.util.ArrayList;
027    import java.util.List;
028    import java.util.Stack;
029    
030    /**
031     *
032     */
033    public 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.
065         * The result will only include ascii characters and numbers, and the "-","_", and "." characters.
066         *
067         * @param name
068         * @return
069         */
070        public static String toFileSystemDirectorySafeName(String name) {
071            return toFileSystemSafeName(name, true, MAX_DIR_NAME_LENGTH);
072        }
073    
074        public static String toFileSystemSafeName(String name) {
075            return toFileSystemSafeName(name, false, MAX_FILE_NAME_LENGTH);
076        }
077    
078        /**
079         * Converts any string into a string that is safe to use as a file name.
080         * The result will only include ascii characters and numbers, and the "-","_", and "." characters.
081         *
082         * @param name
083         * @param dirSeparators
084         * @param maxFileLength
085         * @return
086         */
087        public static String toFileSystemSafeName(String name,boolean dirSeparators,int maxFileLength) {
088            int size = name.length();
089            StringBuffer rc = new StringBuffer(size * 2);
090            for (int i = 0; i < size; i++) {
091                char c = name.charAt(i);
092                boolean valid = c >= 'a' && c <= 'z';
093                valid = valid || (c >= 'A' && c <= 'Z');
094                valid = valid || (c >= '0' && c <= '9');
095                valid = valid || (c == '_') || (c == '-') || (c == '.') || (c=='#')
096                        ||(dirSeparators && ( (c == '/') || (c == '\\')));
097    
098                if (valid) {
099                    rc.append(c);
100                } else {
101                    // Encode the character using hex notation
102                    rc.append('#');
103                    rc.append(HexSupport.toHexFromInt(c, true));
104                }
105            }
106            String result = rc.toString();
107            if (result.length() > maxFileLength) {
108                result = result.substring(result.length()-maxFileLength,result.length());
109            }
110            return result;
111        }
112    
113        public static boolean delete(File top) {
114            boolean result = true;
115            Stack<File> files = new Stack<File>();
116            // Add file to the stack to be processed...
117            files.push(top);
118            // Process all files until none remain...
119            while (!files.isEmpty()) {
120                File file = files.pop();
121                if (file.isDirectory()) {
122                    File list[] = file.listFiles();
123                    if (list == null || list.length == 0) {
124                        // The current directory contains no entries...
125                        // delete directory and continue...
126                        result &= file.delete();
127                    } else {
128                        // Add back the directory since it is not empty....
129                        // and when we process it again it will be empty and can be
130                        // deleted safely...
131                        files.push(file);
132                        for (File dirFile : list) {
133                            if (dirFile.isDirectory()) {
134                                // Place the directory on the stack...
135                                files.push(dirFile);
136                            } else {
137                                // This is a simple file, delete it...
138                                result &= dirFile.delete();
139                            }
140                        }
141                    }
142                } else {
143                    // This is a simple file, delete it...
144                    result &= file.delete();
145                }
146            }
147            return result;
148        }
149    
150        public static boolean deleteFile(File fileToDelete) {
151            if (fileToDelete == null || !fileToDelete.exists()) {
152                return true;
153            }
154            boolean result = deleteChildren(fileToDelete);
155            result &= fileToDelete.delete();
156            return result;
157        }
158    
159        public static boolean deleteChildren(File parent) {
160            if (parent == null || !parent.exists()) {
161                return false;
162            }
163            boolean result = true;
164            if (parent.isDirectory()) {
165                File[] files = parent.listFiles();
166                if (files == null) {
167                    result = false;
168                } else {
169                    for (int i = 0; i < files.length; i++) {
170                        File file = files[i];
171                        if (file.getName().equals(".")
172                                || 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 copyFile(File src, File dest) throws IOException {
194            copyFile(src, dest, null);
195        }
196    
197        public static void copyFile(File src, File dest, FilenameFilter filter) throws IOException {
198            if (src.getCanonicalPath().equals(dest.getCanonicalPath()) == false) {
199                if (src.isDirectory()) {
200    
201                    mkdirs(dest);
202                    List<File> list = getFiles(src, filter);
203                    for (File f : list) {
204                        if (f.isFile()) {
205                            File target = new File(getCopyParent(src, dest, f), f.getName());
206                            copySingleFile(f, target);
207                        }
208                    }
209    
210                } else if (dest.isDirectory()) {
211                    mkdirs(dest);
212                    File target = new File(dest, src.getName());
213                    copySingleFile(src, target);
214                } else {
215                    copySingleFile(src, dest);
216                }
217            }
218        }
219    
220        static File getCopyParent(File from, File to, File src) {
221            File result = null;
222            File parent = src.getParentFile();
223            String fromPath = from.getAbsolutePath();
224            if (parent.getAbsolutePath().equals(fromPath)) {
225                //one level down
226                result = to;
227            }else {
228                String parentPath = parent.getAbsolutePath();
229                String path = parentPath.substring(fromPath.length());
230                result = new File(to.getAbsolutePath()+File.separator+path);
231            }
232            return result;
233        }
234    
235        static List<File> getFiles(File dir,FilenameFilter filter){
236            List<File> result = new ArrayList<File>();
237            getFiles(dir,result,filter);
238            return result;
239        }
240    
241        static void getFiles(File dir,List<File> list,FilenameFilter filter) {
242            if (!list.contains(dir)) {
243                list.add(dir);
244                String[] fileNames=dir.list(filter);
245                for (int i =0; i < fileNames.length;i++) {
246                    File f = new File(dir,fileNames[i]);
247                    if (f.isFile()) {
248                        list.add(f);
249                    }else {
250                        getFiles(dir,list,filter);
251                    }
252                }
253            }
254        }
255    
256        public static void copySingleFile(File src, File dest) throws IOException {
257            FileInputStream fileSrc = new FileInputStream(src);
258            FileOutputStream fileDest = new FileOutputStream(dest);
259            copyInputStream(fileSrc, fileDest);
260        }
261    
262        public static void copyInputStream(InputStream in, OutputStream out) throws IOException {
263            byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
264            int len = in.read(buffer);
265            while (len >= 0) {
266                out.write(buffer, 0, len);
267                len = in.read(buffer);
268            }
269            in.close();
270            out.close();
271        }
272    
273        static {
274            MAX_DIR_NAME_LENGTH = Integer.getInteger("MaximumDirNameLength", 200);
275            MAX_FILE_NAME_LENGTH = Integer.getInteger("MaximumFileNameLength", 64);
276        }
277    
278        public static int getMaxDirNameLength() {
279            return MAX_DIR_NAME_LENGTH;
280        }
281    
282        public static int getMaxFileNameLength() {
283            return MAX_FILE_NAME_LENGTH;
284        }
285    
286        public static void mkdirs(File dir) throws IOException {
287            if (dir.exists()) {
288                if (!dir.isDirectory()) {
289                    throw new IOException("Failed to create directory '" + dir +"', regular file already existed with that name");
290                }
291    
292            } else {
293                if (!dir.mkdirs()) {
294                    throw new IOException("Failed to create directory '" + dir+"'");
295                }
296            }
297        }
298    }