package com.limegroup.gnutella.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.RandomAccessFile;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Arrays;
import com.limegroup.gnutella.FileDesc;
import com.limegroup.gnutella.RouterService;
/**
* This class provides static functions to load/store the files.
* @author Anurag Singla
*/
public class FileUtils
{
/**
* Writes the passed map to corresponding file
* @param filename The name of the file to which to write the passed map
* @param map The map to be stored
*/
public static void writeMap(String filename, Map map)
throws IOException, ClassNotFoundException
{
ObjectOutputStream out = null;
try
{
//open the file
out = new ObjectOutputStream(new FileOutputStream(filename));
//write to the file
out.writeObject(map);
}
finally
{
//close the stream
if(out != null)
out.close();
}
}
/**
* Reads the map stored, in serialized object form,
* in the passed file and returns it. from the file where it is stored
* @param filename The file from where to read the Map
* @return The map that was read
*/
public static Map readMap(String filename)
throws IOException, ClassNotFoundException
{
ObjectInputStream in = null;
try
{
//open the file
in = new ObjectInputStream(new FileInputStream(filename));
//read and return the object
return (Map)in.readObject();
}
finally
{
//close the file
if(in != null)
in.close();
}
}
/** Same as the f.listFiles() in JDK1.3. */
public static File[] listFiles(File f) {
return f.listFiles();
}
/**
* Same as f.listFiles(FileNameFilter) in JDK1.2
*/
public static File[] listFiles(File f, FilenameFilter filter) {
return f.listFiles(filter);
}
/**
* Same as f.getParentFile() in JDK1.3.
* @requires the File parameter must be a File object constructed
* with the canonical path.
*/
public static File getParentFile(File f) {
return f.getParentFile();
}
/**
* Gets the canonical path, catching buggy Windows errors
*/
public static String getCanonicalPath(File f) throws IOException {
try {
return f.getCanonicalPath();
} catch(IOException ioe) {
String msg = ioe.getMessage();
throw ioe;
}
}
/** Same as f.getCanonicalFile() in JDK1.3. */
public static File getCanonicalFile(File f) throws IOException {
try {
return f.getCanonicalFile();
} catch(IOException ioe) {
String msg = ioe.getMessage();
throw ioe;
}
}
/**
* Utility method that returns the file extension of the given file.
*
* @param f the <tt>File</tt> instance that the extension should
* be extracted from
* @return the file extension string, or <tt>null</tt> if the extension
* could not be extracted
*/
public static String getFileExtension(File f) {
String name = f.getName();
int index = name.lastIndexOf(".");
if(index == -1) return null;
// the file must have a name other than the extension
if(index == 0) return null;
// if the last character of the string is the ".", then there's
// no extension
if(index == (name.length()-1)) return null;
return name.substring(index+1);
}
/**
* Utility method to set a file as non read only.
* If the file is already writable, does nothing.
*
* @param f the <tt>File</tt> instance whose read only flag should
* be unset.
*
* @return whether or not <tt>f</tt> is writable after trying to make it
* writeable -- note that if the file doesn't exist, then this returns
* <tt>true</tt>
*/
public static boolean setWriteable(File f) {
if(!f.exists())
return true;
// non Windows-based systems return the wrong value
// for canWrite when the argument is a directory --
// writing is based on the 'x' attribute, not the 'w'
// attribute for directories.
if(f.canWrite()) {
if(!f.isDirectory())
return true;
}
String fName;
try {
fName = f.getCanonicalPath();
} catch(IOException ioe) {
fName = f.getPath();
}
String cmds[] = null;
if(f.isDirectory())
cmds = new String[] { "chmod", "u+w+x", fName };
else
cmds = new String[] { "chmod", "u+w", fName};
if( cmds != null ) {
try {
Process p = Runtime.getRuntime().exec(cmds);
p.waitFor();
}
catch(SecurityException ignored) { }
catch(IOException ignored) { }
catch(InterruptedException ignored) { }
}
return f.canWrite();
}
/**
* Touches a file, to ensure it exists.
*/
public static void touch(File f) throws IOException {
if(f.exists())
return;
File parent = f.getParentFile();
if(parent != null)
parent.mkdirs();
try {
f.createNewFile();
} catch(IOException failed) {
// Okay, createNewFile failed. Let's try the old way.
FileOutputStream fos = null;
try {
fos = new FileOutputStream(f);
} catch(IOException ioe) {
ioe.initCause(failed);
throw ioe;
} finally {
if(fos != null) {
try {
fos.close();
} catch(IOException ignored) {}
}
}
}
}
public static boolean forceRename(File a, File b) {
// First attempt to rename it.
boolean success = a.renameTo(b);
// If that didn't work, try copying the file.
if (!success) {
success = CommonUtils.copy(a, b);
//if copying succeeded, get rid of the original
//at this point any active uploads will have been killed
if (success)
a.delete();
}
return success;
}
/**
* Saves the data iff it was written exactly as we wanted.
*/
public static boolean verySafeSave(File dir, String name, byte[] data) {
File tmp;
try {
tmp = File.createTempFile(name, "tmp", dir);
} catch(IOException hrorible) {
return false;
}
File out = new File(dir, name);
OutputStream os = null;
try {
os = new BufferedOutputStream(new FileOutputStream(tmp));
os.write(data);
os.flush();
} catch(IOException bad) {
return false;
} finally {
IOUtils.close(os);
}
//verify that we wrote everything correctly
byte[] read = readFileFully(tmp);
if(read == null || !Arrays.equals(read, data))
return false;
return forceRename(tmp, out);
}
/**
* Reads a file, filling a byte array.
*/
public static byte[] readFileFully(File source) {
DataInputStream raf = null;
int length = (int)source.length();
if(length <= 0)
return null;
byte[] data = new byte[length];
try {
raf = new DataInputStream(new BufferedInputStream(new FileInputStream(source)));
raf.readFully(data);
} catch(IOException ioe) {
return null;
} finally {
IOUtils.close(raf);
}
return data;
}
}