/**************************************************************************
* Parts copyright (c) 2001 by Punch Telematix. All rights reserved. *
* Parts copyright (c) 2003, 2009 by /k/ Embedded Java Solutions. *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions *
* are met: *
* 1. Redistributions of source code must retain the above copyright *
* notice, this list of conditions and the following disclaimer. *
* 2. Redistributions in binary form must reproduce the above copyright *
* notice, this list of conditions and the following disclaimer in the *
* documentation and/or other materials provided with the distribution. *
* 3. Neither the name of Punch Telematix or of /k/ Embedded Java Solutions*
* nor the names of other contributors may be used to endorse or promote*
* products derived from this software without specific prior written *
* permission. *
* *
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. *
* IN NO EVENT SHALL PUNCH TELEMATIX, /K/ EMBEDDED JAVA SOLUTIONS OR OTHER *
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
**************************************************************************/
package java.io;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.Vector;
import wonka.vm.SecurityConfiguration;
public class File implements Comparable, Serializable {
private static final long serialVersionUID = 301077366599181567L;
static Vector toBeDeleted;
public static final String separator;
public static final char separatorChar;
public static final String pathSeparator;
public static final char pathSeparatorChar;
private static String current_working_dir;
private static String fsroot_dir;
private static String fsrootedPrefix;
private static Random prng;
/**
** Name by which the File object was created ('path' parameter of the constructor).
*/
private transient String fullname;
/*
** If the path begins with '/', this is stripped off and 'absolute' is set.
** If the path begins with '{}/', this is stripped off and 'fsrooted' is set.
** The remainder of the path is then split at the last '/':
** - everything up to the last '/' (exclusive) goes in 'dirpath'.
** - everything after the last '/' (exclusive) goes in 'filename'.
*/
private transient boolean empty;
private transient boolean absolute;
private transient boolean fsrooted;
private transient String dirpath;
private transient String filename;
private transient int hashcode;
/**
** The absolute path used to open the file, after path mungeing.
*/
private transient String absolutePath;
/**
** Same as absolutePath, but after eliminating './' and '../' sequences.
** Generated on demand by toURL().
*/
private transient String canonicalPath;
/**
** Same as absolutePath. Used by the native functions to access the file.
*/
final transient String absname;
private static native String get_CWD();
private static native String get_fsroot();
private static String extractPathFromURI(URI uri) throws IllegalArgumentException {
if (!uri.isAbsolute()) {
throw new IllegalArgumentException("URI is not absolute: " + uri);
}
if (!uri.getRawSchemeSpecificPart().startsWith("/")) {
throw new IllegalArgumentException("URI is not hierarchical: " + uri);
}
if (!"file".equalsIgnoreCase(uri.getScheme())) {
throw new IllegalArgumentException("URI has wrong scheme: " + uri);
}
if (uri.getRawPath() == null || uri.getRawPath().length() == 0) {
throw new IllegalArgumentException("URI has no path: " + uri);
}
if (uri.getRawAuthority() != null) {
throw new IllegalArgumentException("URI contains an authority: " + uri);
}
if (uri.getRawQuery() != null) {
throw new IllegalArgumentException("URI contains a query: " + uri);
}
if (uri.getRawFragment() != null) {
throw new IllegalArgumentException("URI contains a fragment: " + uri);
}
return uri.getPath();
}
static {
separator = GetSystemProperty.FILE_SEPARATOR;
pathSeparator = GetSystemProperty.PATH_SEPARATOR;
separatorChar = separator.charAt(0);
pathSeparatorChar = pathSeparator.charAt(0);
fsrootedPrefix = "{}" + separator;
current_working_dir = get_CWD();
fsroot_dir = get_fsroot() + separator;
current_working_dir = current_working_dir + separator;
// TODO: shouldn't we have a GetSystemProperty-like mechanism here?
System.getProperties().setProperty("user.dir", current_working_dir);
}
public static File[] listRoots() {
return new File[] { new File("/") };
}
public static File createTempFile(String pre, String suf) throws IllegalArgumentException, IOException {
return createTempFile(pre, suf, null);
}
public static synchronized File createTempFile(String pre, String suf, File dir) throws IllegalArgumentException, IOException, SecurityException {
if(dir == null) {
dir = new File(GetSystemProperty.TMPDIR);
}
if(suf == null) {
suf = ".tmp";
}
if(pre == null || pre.length() < 3) {
throw new IllegalArgumentException("prefix must be at least three chars: " + pre);
}
if (prng == null) {
prng = new Random();
}
File result = new File(dir, pre + prng.nextLong() + suf);
result.createNewFile();
return result;
}
private String pack(String path) {
String result = "";
LinkedList list = new LinkedList();
StringTokenizer st = new StringTokenizer(path, "/");
try {
while (true) {
String token = st.nextToken();
if(!token.equals(".")) {
if(!token.equals("..")) {
list.add(token);
} else {
if(list.size() > 0)
list.removeLast();
}
}
}
}
catch(NoSuchElementException e) {
}
Iterator iter = list.iterator();
while(iter.hasNext())
result += "/" + (String)iter.next();
if(!path.startsWith("/") && (result.length() > 0)) result = result.substring(1);
return result;
}
private String stripSlashes(String path) {
String result = path;
int i = result.indexOf("//");
while (i >= 0) {
result = result.substring(0, i) + result.substring(i + 1);
i = result.indexOf("//");
}
i = result.lastIndexOf('/');
if (i > 0 && i == result.length() - 1) {
result = result.substring(0, i);
}
return result;
}
public File(String path) throws NullPointerException {
String relpath;
hashcode = path.hashCode() ^ 1234321;
if(path.length() == 0) {
path = current_working_dir;
relpath = ".";
empty = true;
} else if(path.charAt(0) == separatorChar) { // Absolute path
relpath = path.substring(1);
absolute = true;
} else if(path.startsWith(fsrootedPrefix)) { // fsrooted path
relpath = path.substring(3);
fsrooted = true;
} else {
relpath = path;
}
relpath = stripSlashes(relpath);
try {
int dirpathlen = relpath.lastIndexOf(separatorChar);
if (dirpathlen < 0) {
dirpath = null;
filename = relpath;
} else {
dirpath = relpath.substring(0, dirpathlen);
filename = relpath.substring(dirpathlen + 1);
}
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
}
fullname = empty ? "" : stripSlashes(path);
if (absolute) {
absolutePath = fullname;
}
else if (fsrooted) {
absolutePath = fsroot_dir + fullname.substring(3);
}
else {
absolutePath = current_working_dir + fullname;
}
int len = absolutePath.length() - 1;
if(len > 0 && absolutePath.charAt(len) == '/') {
absolutePath = absolutePath.substring(0, len);
}
absname = absolutePath;
}
public File(String dirname, String name) throws NullPointerException {
this(name == null ? null : (dirname == null ? "" : (dirname.equals("") ? "" : dirname.endsWith("/") ? dirname : dirname + separatorChar)) + name);
}
public File(File dir, String name) throws NullPointerException {
this((dir == null ? "" : dir.getPath()), name);
}
public File(URI uri) throws NullPointerException, IllegalArgumentException {
this(extractPathFromURI(uri));
}
public String toString() {
return fullname;
}
public boolean equals(Object obj) {
if ((obj != null) && obj instanceof File) {
return (((File)obj).getPath().equals(getPath()));
}
return false;
}
public int compareTo(File pathname) {
return (getPath().compareTo(pathname.getPath()));
}
public int compareTo(Object obj) {
if (obj instanceof File) {
return (absolutePath.compareTo(((File)obj).getAbsolutePath()));
} else { throw new ClassCastException(); }
}
public int hashCode() {
return hashcode;
}
public String getName() {
if (empty) {
return "";
}
String result = new String(filename);
int snip = filename.lastIndexOf(separatorChar);
if (snip >= 0) {
result = result.substring(snip+1);
}
return result;
}
public String getPath() {
return empty ? "" : fullname;
}
public String getAbsolutePath() {
// bizarre but it seems to be what Sun is doing
if (empty) {
return "./";
}
return absolutePath;
}
public File getAbsoluteFile() {
return new File(absolutePath);
}
public String getCanonicalPath() throws IOException {
if(canonicalPath == null) {
canonicalPath = pack(absolutePath);
}
return canonicalPath;
}
public File getCanonicalFile() throws IOException {
return new File(getCanonicalPath());
}
public String getParent() {
if (dirpath == null || dirpath.length() + filename.length() == 0) {
return null;
}
String prefix = absolute ? separator : fsrooted ? fsrootedPrefix : "";
if (filename.length() == 0) {
return new File(prefix + dirpath).getParent();
}
return prefix + dirpath;
}
public File getParentFile() {
String parentName = getParent();
if (parentName == null) {
return null;
}
return new File(parentName);
}
public boolean isAbsolute() {
return absolute;
}
public boolean isHidden() throws SecurityException {
readCheck();
return (filename.charAt(0) == '.');
}
// TODO: this is supposed to be atomic wrt any other file ops!
// Well at least we can make the method synchronized ...
public synchronized boolean createNewFile() throws IOException, SecurityException {
writeCheck();
return _createNew();
}
public native boolean _createNew() throws IOException;
public boolean exists() throws SecurityException {
readCheck();
return _exists();
}
public native boolean _exists();
public String[] list() throws SecurityException {
readCheck();
return _list();
}
public native String[] _list();
public String[] list(FilenameFilter filter) throws SecurityException {
String[] files = this.list();
if (files == null){
return null;
}
if (filter == null){
return files;
}
ArrayList alist = new ArrayList(files.length);
for(int i=0; i < files.length; i++){
if(filter.accept(this, files[i])){
alist.add(files[i]);
}
}
String[] result = new String[alist.size()];
return (String[])alist.toArray(result);
}
public File[] listFiles() throws SecurityException {
String[] filenames = this.list();
if(filenames == null){
return null;
}
File[] files = new File[filenames.length];
for(int i=0; i<filenames.length; i++)
files[i] = new File(this, filenames[i]);
return files;
}
public File[] listFiles(FilenameFilter filter) throws SecurityException {
String[] filenames = this.list(filter);
if(filenames == null){
return null;
}
File[] files = new File[filenames.length];
for(int i=0; i<filenames.length; i++)
files[i] = new File(this, filenames[i]);
return files;
}
public File[] listFiles(FileFilter filter) throws SecurityException {
File[] files = this.listFiles();
if (files == null){
return null;
}
if (filter == null){
return files;
}
ArrayList alist = new ArrayList(files.length);
for(int i=0; i < files.length; i++){
if(filter.accept(files[i])){
alist.add(files[i]);
}
}
File[] result = new File[alist.size()];
return (File[])alist.toArray(result);
}
public boolean canRead() throws SecurityException {
readCheck();
return _canRead();
}
public native boolean _canRead();
public boolean canWrite() throws SecurityException {
writeCheck();
return _canWrite();
}
public native boolean _canWrite();
public boolean isFile() throws SecurityException {
readCheck();
return _isFile();
}
public native boolean _isFile();
public boolean isDirectory() throws SecurityException {
readCheck();
return _isDirectory();
}
public native boolean _isDirectory();
public long lastModified() throws SecurityException {
readCheck();
return _lastModified();
}
public native long _lastModified();
public boolean setLastModified(long time) throws SecurityException {
writeCheck();
return _setLastModified(time);
}
public native boolean _setLastModified(long time);
public void deleteOnExit() throws SecurityException {
deleteCheck();
if(toBeDeleted == null) {
createShutdownHook();
}
toBeDeleted.add(this);
}
private synchronized static void createShutdownHook(){
if(toBeDeleted == null) {
toBeDeleted = new Vector();
Runtime.getRuntime().addShutdownHook(new Thread("File:deleteOnExit") {
public void run() {
Iterator iter = File.toBeDeleted.iterator();
while(iter.hasNext()) {
File f = (File)iter.next();
try {
if(f != null) f.delete();
}
catch(Exception e) {
}
}
}
});
}
}
public boolean setReadOnly() throws SecurityException {
writeCheck();
if (empty) {
// imitate Sun
return false;
}
return _setReadOnly();
}
public native boolean _setReadOnly();
public long length() throws SecurityException {
readCheck();
return _length();
}
public native long _length();
public boolean mkdir() throws SecurityException {
writeCheck();
return _mkdir();
}
public native boolean _mkdir();
public boolean mkdirs() throws SecurityException {
boolean result = false;
if(!absolutePath.equals(separator) && !absolutePath.equals(fsrootedPrefix)) {
File parent = getParentFile();
if (parent != null) {
parent.mkdirs();
}
result = mkdir();
}
return result;
}
private native boolean _rename(String src, String dest);
public boolean renameTo(File dest) throws SecurityException {
writeCheck();
dest.writeCheck();
return _rename(absolutePath, dest.getAbsolutePath());
}
public boolean delete() throws SecurityException {
deleteCheck();
return _delete();
}
public native boolean _delete();
public URL toURL() throws MalformedURLException {
if (empty) {
return new URL("file:./");
}
if(canonicalPath == null) {
canonicalPath = pack(absolutePath);
}
return new URL("file", "", isDirectory() ? canonicalPath + "/" : canonicalPath);
}
public URI toURI() {
String uriPath = empty ? "./" : canonicalPath;
if(uriPath == null) {
canonicalPath = pack(absolutePath);
uriPath = canonicalPath;
}
try {
return new URI("file", null, uriPath, null, null);
} catch (URISyntaxException e) {
return null;
}
}
private void readCheck() {
if (SecurityConfiguration.ENABLE_SECURITY_CHECKS) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkRead(fullname);
}
}
}
private void writeCheck() {
if (SecurityConfiguration.ENABLE_SECURITY_CHECKS) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkWrite(fullname);
}
}
}
private void deleteCheck() {
if (SecurityConfiguration.ENABLE_SECURITY_CHECKS) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkDelete(fullname);
}
}
}
}