/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.enterprise.config.backup.util;
import java.io.*;
import java.util.*;
public class FileUtils
{
private FileUtils()
{
}
///////////////////////////////////////////////////////////////////////////
public static boolean safeIsDirectory(File f)
{
if(f == null || !f.exists() || !f.isDirectory())
return false;
return true;
}
///////////////////////////////////////////////////////////////////////////
public static boolean safeIsDirectory(String s)
{
return safeIsDirectory(new File(s));
}
///////////////////////////////////////////////////////////////////////////
/*
public static boolean safeIsRealDirectory(String s)
{
return safeIsRealDirectory(new File(s));
}
*/
///////////////////////////////////////////////////////////////////////////
/*
public static boolean safeIsRealDirectory(File f)
{
if(safeIsDirectory(f) == false)
return false;
// these 2 values while be different for symbolic links
String canonical = safeGetCanonicalPath(f);
String absolute = f.getAbsolutePath();
if(canonical.equals(absolute))
return true;
*/
/* Bug 4715043 -- WHOA -- Bug Obscura!!
* In Windows, if you create the File object with, say, "d:/foo", then the
* absolute path will be "d:\foo" and the canonical path will be "D:\foo"
* and they won't match!!!
**/
/*
if(OS.isWindows() && canonical.equalsIgnoreCase(absolute))
return true;
return false;
}
*/
///////////////////////////////////////////////////////////////////////////
public static String safeGetCanonicalPath(File f)
{
if(f == null)
return null;
try
{
return f.getCanonicalPath();
}
catch(IOException e)
{
return f.getAbsolutePath();
}
}
///////////////////////////////////////////////////////////////////////////
public static File safeGetCanonicalFile(File f)
{
if(f == null)
return null;
try
{
return f.getCanonicalFile();
}
catch(IOException e)
{
return f.getAbsoluteFile();
}
}
///////////////////////////////////////////////////////////////////////////
public static boolean isZip(String filename)
{
return hasExtensionIgnoreCase(filename, ".zip");
}
///////////////////////////////////////////////////////////////////////////
public static boolean isZip(File f)
{
return hasExtensionIgnoreCase(f, ".zip");
}
/////////////////////////////////////////////////////////
public static void whack(File parent)
{
if(safeIsDirectory(parent))
{
File[] kids = parent.listFiles();
for(int i = 0; i < kids.length; i++)
{
File f = kids[i];
if(f.isDirectory())
whack(f);
if(!f.delete())
{
f.deleteOnExit();
}
}
}
parent.delete();
}
/**
*/
public static boolean protect(File f)
{
if(!f.exists())
return true;
if(OS.isUNIX())
return protectUNIX(f);
else
return protectWindows(f);
}
/**
**/
public static boolean makeExecutable(File f)
{
if(!OS.isUNIX())
return true; // no such thing in Windows...
if(!f.exists())
return true; // no harm, no foul...
if(!f.isDirectory())
return makeExecutable(new File[] { f} );
// if we get here -- f is a directory
return makeExecutable(f.listFiles());
}
/**
* Copies the entire tree to a new location.
*
* @param sourceTree File pointing at root of tree to copy
* @param destTree File pointing at root of new tree
*
* @exception IOException if an error while copying the content
*/
public static void copyTree(File din, File dout) throws IOException
{
if(!safeIsDirectory(din))
throw new IllegalArgumentException("Source isn't a directory");
dout.mkdirs();
if(!safeIsDirectory(dout))
throw new IllegalArgumentException("Can't create destination directory");
FileListerRelative flr = new FileListerRelative(din);
String[] files = flr.getFiles();
for(int i = 0; i < files.length; i++)
{
File fin = new File(din, files[i]);
File fout = new File(dout, files[i]);
copy(fin, fout);
}
}
///////////////////////////////////////////////////////////////////////////
////// PRIVATE METHODS ///////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
private static boolean hasExtension(String filename, String ext)
{
if(filename == null || filename.length() <= 0)
return false;
return filename.endsWith(ext);
}
///////////////////////////////////////////////////////////////////////////
private static boolean hasExtension(File f, String ext)
{
if(f == null || !f.exists())
return false;
return f.getName().endsWith(ext);
}
///////////////////////////////////////////////////////////////////////////
private static boolean hasExtensionIgnoreCase(String filename, String ext)
{
if(filename == null || filename.length() <= 0)
return false;
return filename.toLowerCase().endsWith(ext.toLowerCase());
}
///////////////////////////////////////////////////////////////////////////
private static boolean hasExtensionIgnoreCase(File f, String ext)
{
if(f == null || !f.exists())
return false;
return f.getName().toLowerCase().endsWith(ext.toLowerCase());
}
/**
* Copies the bytes from the given input stream to the output stream.
* It closes the streams afterwards.
*
* @param inStream input stream from the src
* @param outStream output stream to the destination
*
* @exception IOException if an error while copying the content
*/
private static void copy(InputStream inStream, OutputStream outStream) throws IOException
{
copyWithoutClose(inStream, outStream);
// closes the streams
inStream.close();
outStream.close();
}
/**
* Copies the bytes from the given input stream to the output stream.
* It does not close the streams afterwards.
*
* @param inStream input stream from the src
* @param outStream output stream to the destination
*
* @exception IOException if an error while copying the content
*/
private static void copyWithoutClose(InputStream inStream, OutputStream outStream) throws IOException
{
BufferedInputStream bis = new BufferedInputStream(inStream, BUFFER_SIZE);
BufferedOutputStream bos = new BufferedOutputStream(outStream, BUFFER_SIZE);
byte[] buf = new byte[BUFFER_SIZE];
int len = 0;
while (len != -1)
{
try
{
len = bis.read(buf, 0, buf.length);
}
catch (EOFException eof)
{
break;
}
if (len != -1)
{
bos.write(buf, 0, len);
}
}
bos.flush();
}
/**
* Copies a file.
*
* @param from Name of file to copy
* @param to Name of new file
* @exception IOException if an error while copying the content
*/
private static void copy(String from, String to) throws IOException
{
//if(!StringUtils.ok(from) || !StringUtils.ok(to))
if(from == null || to == null)
throw new IllegalArgumentException("null or empty filename argument");
File fin = new File(from);
File fout = new File(to);
copy(fin, fout);
}
/**
* Copies a file.
*
* @param from File to copy
* @param to New file
*
* @exception IOException if an error while copying the content
*/
private static void copy(File fin, File fout) throws IOException
{
if(safeIsDirectory(fin))
{
copyTree(fin, fout);
return;
}
if(!fin.exists())
throw new IllegalArgumentException("File source doesn't exist");
if(!safeIsDirectory(fout.getParentFile()))
fout.getParentFile().mkdirs();
copy(new FileInputStream(fin), new FileOutputStream(fout));
}
///////////////////////////////////////////////////////////////////////////
private static boolean protectUNIX(File f)
{
if(f == null)
return false;
try
{
List<String> cmds = new ArrayList<String>();
List<String> cmdsDirs = new ArrayList<String>();
File[] files = null;
ProcessBuilder pb = null;
Process p = null;
boolean ret = false;
if(f.isDirectory())
{
// chmod to rwx------
// and chmod files inside dir to rw-------
// 6580444 -- make any subdirs drwxr-xr-x (0755) otherwise we can't
// delete the whole tree as non-root for some reason.
// notice that the original file, if a directory, WILL have 0700
// this is exactly the way the permissions exist in the original
// domain files.
cmds.add("chmod");
cmds.add("0700");
cmds.add(safeGetCanonicalPath(f));
pb = new ProcessBuilder(cmds);
p = pb.start();
ret = p.waitFor() == 0 ? true : false;
files = f.listFiles();
if(files == null || files.length < 1)
return ret;
}
else
{
ret = true;
files = new File[] { f };
}
cmds.clear();
cmds.add("chmod");
cmds.add("0600");
cmdsDirs.add("chmod");
cmdsDirs.add("0755");
for(File file : files)
{
if(file.isDirectory())
cmdsDirs.add(safeGetCanonicalPath(file));
else
cmds.add(safeGetCanonicalPath(file));
}
pb = new ProcessBuilder(cmds);
p = pb.start();
// if any chmod returned false -- return false...
ret = ret && (p.waitFor() == 0 ? true : false);
if(cmdsDirs.size() > 0)
{
pb = new ProcessBuilder(cmdsDirs);
p = pb.start();
// if any chmod returned false -- return false...
ret = ret && (p.waitFor() == 0 ? true : false);
}
return ret;
}
catch(Exception e)
{
return false;
}
}
///////////////////////////////////////////////////////////////////////////
private static boolean protectWindows(File f)
{
// this is ugly. We'return calling a program installed with Windows.
// The program wants to confirm a change so we have to give it a 'Y'
// at runtime...
String fname = f.getAbsolutePath();
String uname = System.getProperty("user.name");
try
{
ProcessBuilder pb = new ProcessBuilder("cacls", fname, "/G", uname + ":F");
Process p = pb.start();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
writer.write('Y');
writer.newLine();
writer.flush();
return p.waitFor() == 0 ? true : false;
}
catch(Exception e)
{
return false;
}
}
///////////////////////////////////////////////////////////////////////////
private static boolean makeExecutable(File[] files)
{
// WBN October 2005
// dirspace bugfix -- what if there is a space in the dirname? trouble!
// changed the argument to a File array
// we are using a String here so that you can pass in a bunch
// of space-separated filenames. Doing it one at a time would be inefficient...
// make it executable for ONLY the user
// Jan 19, 2005 -- rolled back the fix for 6206176. It has been decided
// that this is not a bug but rather a security feature.
// BUGFIX: 6206176
// permissions changed from 744 to 755.
// The reason is that if user 'A' does a restore then user 'A' will be the only
// user allowed to start or stop a domain. Whether or not a user is allowed to start a domain
// needs to be based on the AppServer authentication mechanism (username-password) rather
// than on the OS authentication mechanism.
// This case actually is common: user 'A' does the restore, root tries to start the restored domain.
if(files == null || files.length <= 0)
return true;
List<String> cmds = new ArrayList<String>();
cmds.add("chmod");
cmds.add("0744");
for(File f : files)
cmds.add(safeGetCanonicalPath(f));
try
{
ProcessBuilder pb = new ProcessBuilder(cmds);
Process p = pb.start();
return p.waitFor() == 0 ? true : false;
}
catch(Exception e)
{
return false;
}
}
///////////////////////////////////////////////////////////////////////////
private static final int BUFFER_SIZE = 0x10000; // 64k
private final static char[] ILLEGAL_FILENAME_CHARS =
{'/', '\\', ':', '*', '?', '"', '<', '>', '|' };
private final static String ILLEGAL_FILENAME_STRING = "\\/:*?\"<>|";
private final static char REPLACEMENT_CHAR = '_';
private final static char BLANK = ' ';
private final static char DOT = '.';
private static String TMPFILENAME = "scratch";
}
|