
org.microemu.cldc.file.FileSystemFileConnection Maven / Gradle / Ivy
/**
* MicroEmulator
* Copyright (C) 2006-2007 Bartek Teodorczyk
* Copyright (C) 2006-2007 Vlad Skarzhevskyy
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* @version $Id: FileSystemFileConnection.java 1593 2008-02-21 03:12:10Z vlads $
*/
package org.microemu.cldc.file;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.lang.reflect.Method;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.util.Enumeration;
import java.util.Vector;
import javax.microedition.io.file.ConnectionClosedException;
import javax.microedition.io.file.FileConnection;
public class FileSystemFileConnection implements FileConnection {
private String fsRootConfig;
private File fsRoot;
private String host;
private String fullPath;
private File file;
private boolean isRoot;
private boolean isDirectory;
private Throwable locationClosedFrom = null;
private FileSystemConnectorImpl notifyClosed;
private InputStream opendInputStream;
private OutputStream opendOutputStream;
private final static char DIR_SEP = '/';
private final static String DIR_SEP_STR = "/";
/* The context to be used when acessing filesystem */
private AccessControlContext acc;
private static boolean java15 = false;
FileSystemFileConnection(String fsRootConfig, String name, FileSystemConnectorImpl notifyClosed) throws IOException {
// /
int hostEnd = name.indexOf(DIR_SEP);
if (hostEnd == -1) {
throw new IOException("Invalid path " + name);
}
this.fsRootConfig = fsRootConfig;
this.notifyClosed = notifyClosed;
host = name.substring(0, hostEnd);
fullPath = name.substring(hostEnd + 1);
int rootEnd = fullPath.indexOf(DIR_SEP);
isRoot = ((rootEnd == -1) || (rootEnd == fullPath.length() - 1));
if (fullPath.charAt(fullPath.length() - 1) == DIR_SEP) {
fullPath = fullPath.substring(0, fullPath.length() - 1);
}
acc = AccessController.getContext();
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
fsRoot = getRoot(FileSystemFileConnection.this.fsRootConfig);
file = new File(fsRoot, fullPath);
isDirectory = file.isDirectory();
return null;
}
}, acc);
}
private Object doPrivilegedIO(PrivilegedExceptionAction action) throws IOException {
return FileSystemConnectorImpl.doPrivilegedIO(action, acc);
}
private abstract class PrivilegedBooleanAction implements PrivilegedAction {
public Object run() {
return new Boolean(getBoolean());
}
abstract boolean getBoolean();
}
private boolean doPrivilegedBoolean(PrivilegedBooleanAction action) {
return ((Boolean) AccessController.doPrivileged(action)).booleanValue();
}
public static File getRoot(String fsRootConfig) {
try {
if (fsRootConfig == null) {
File fsRoot = new File(System.getProperty("user.home") + "/.microemulator/filesystem");
if (!fsRoot.exists()) {
if (!fsRoot.mkdirs()) {
throw new RuntimeException("Can't create filesystem root " + fsRoot.getAbsolutePath());
}
}
return fsRoot;
} else {
File fsRoot = new File(fsRootConfig);
if (!fsRoot.isDirectory()) {
throw new RuntimeException("Can't find filesystem root " + fsRoot.getAbsolutePath());
}
return fsRoot;
}
} catch (SecurityException e) {
System.out.println("Cannot access user.home " + e);
return null;
}
}
static Enumeration listRoots(String fsRootConfig) {
File[] files = getRoot(fsRootConfig).listFiles();
if (files == null) { // null if security restricted
return (new Vector()).elements();
}
Vector list = new Vector();
for (int i = 0; i < files.length; i++) {
File file = files[i];
if (file.isHidden()) {
continue;
}
if (file.isDirectory()) {
list.add(file.getName() + DIR_SEP);
}
}
return list.elements();
}
public long availableSize() {
throwClosed();
if (fsRoot == null) {
return -1;
}
// TODO
return 10000000;
}
public long totalSize() {
throwClosed();
if (fsRoot == null) {
return -1;
}
// TODO
return 10000000;
}
public boolean canRead() {
throwClosed();
return doPrivilegedBoolean(new PrivilegedBooleanAction() {
public boolean getBoolean() {
return file.canRead();
}
});
}
public boolean canWrite() {
throwClosed();
return doPrivilegedBoolean(new PrivilegedBooleanAction() {
public boolean getBoolean() {
return file.canWrite();
}
});
}
public void create() throws IOException {
throwClosed();
doPrivilegedIO(new PrivilegedExceptionAction() {
public Object run() throws IOException {
if (!file.createNewFile()) {
throw new IOException("File already exists " + file.getAbsolutePath());
}
return null;
}
});
}
public void delete() throws IOException {
throwClosed();
doPrivilegedIO(new PrivilegedExceptionAction() {
public Object run() throws IOException {
if (!file.delete()) {
throw new IOException("Unable to delete " + file.getAbsolutePath());
}
return null;
}
});
}
public long directorySize(final boolean includeSubDirs) throws IOException {
throwClosed();
return ((Long) doPrivilegedIO(new PrivilegedExceptionAction() {
public Object run() throws IOException {
if (!file.isDirectory()) {
throw new IOException("Not a directory " + file.getAbsolutePath());
}
return new Long(directorySize(file, includeSubDirs));
}
})).longValue();
}
private static long directorySize(File dir, boolean includeSubDirs) throws IOException {
long size = 0;
File[] files = dir.listFiles();
if (files == null) { // null if security restricted
return 0L;
}
for (int i = 0; i < files.length; i++) {
File child = files[i];
if (includeSubDirs && child.isDirectory()) {
size += directorySize(child, true);
} else {
size += child.length();
}
}
return size;
}
public boolean exists() {
throwClosed();
return doPrivilegedBoolean(new PrivilegedBooleanAction() {
public boolean getBoolean() {
return file.exists();
}
});
}
public long fileSize() throws IOException {
throwClosed();
return ((Long) doPrivilegedIO(new PrivilegedExceptionAction() {
public Object run() throws IOException {
return new Long(file.length());
}
})).longValue();
}
public String getName() {
// TODO test on real device. Not declared
throwClosed();
if (isRoot) {
return "";
}
if (this.isDirectory) {
return this.file.getName() + DIR_SEP;
} else {
return this.file.getName();
}
}
public String getPath() {
// TODO test on real device. Not declared
throwClosed();
// returns Parent directory
// ///
if (isRoot) {
return DIR_SEP + fullPath + DIR_SEP;
}
int pathEnd = fullPath.lastIndexOf(DIR_SEP);
if (pathEnd == -1) {
return DIR_SEP_STR;
}
return DIR_SEP + fullPath.substring(0, pathEnd + 1);
}
public String getURL() {
// TODO test on real device. Not declared
throwClosed();
// file://///
// or
// file://////
return Connection.PROTOCOL + this.host + DIR_SEP + fullPath + ((this.isDirectory) ? DIR_SEP_STR : "");
}
public boolean isDirectory() {
throwClosed();
return this.isDirectory;
}
public boolean isHidden() {
throwClosed();
return doPrivilegedBoolean(new PrivilegedBooleanAction() {
public boolean getBoolean() {
return file.isHidden();
}
});
}
public long lastModified() {
throwClosed();
return ((Long) AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return new Long(file.lastModified());
}
}, acc)).longValue();
}
public void mkdir() throws IOException {
throwClosed();
doPrivilegedIO(new PrivilegedExceptionAction() {
public Object run() throws IOException {
if (!file.mkdir()) {
throw new IOException("Can't create directory " + file.getAbsolutePath());
}
return null;
}
});
}
public Enumeration list() throws IOException {
return this.list(null, false);
}
public Enumeration list(final String filter, final boolean includeHidden) throws IOException {
throwClosed();
return (Enumeration) doPrivilegedIO(new PrivilegedExceptionAction() {
public Object run() throws IOException {
return listPrivileged(filter, includeHidden);
}
});
}
private Enumeration listPrivileged(String filter, boolean includeHidden) throws IOException {
if (!this.file.isDirectory()) {
throw new IOException("Not a directory " + this.file.getAbsolutePath());
}
// TODO
FilenameFilter filenameFilter = null;
File[] files = this.file.listFiles(filenameFilter);
if (files == null) { // null if security restricted
return (new Vector()).elements();
}
Vector list = new Vector();
for (int i = 0; i < files.length; i++) {
File child = files[i];
if ((!includeHidden) && (child.isHidden())) {
continue;
}
if (child.isDirectory()) {
list.add(child.getName() + DIR_SEP);
} else {
list.add(child.getName());
}
}
return list.elements();
}
public boolean isOpen() {
return (this.file != null);
}
private void throwOpenDirectory() throws IOException {
if (this.isDirectory) {
throw new IOException("Unable to open Stream on directory");
}
}
public InputStream openInputStream() throws IOException {
throwClosed();
throwOpenDirectory();
if (this.opendInputStream != null) {
throw new IOException("InputStream already opened");
}
/**
* Trying to open more than one InputStream or more than one
* OutputStream from a StreamConnection causes an IOException.
*/
this.opendInputStream = (InputStream) doPrivilegedIO(new PrivilegedExceptionAction() {
public Object run() throws IOException {
return new FileInputStream(file) {
public void close() throws IOException {
FileSystemFileConnection.this.opendInputStream = null;
super.close();
}
};
}
});
return this.opendInputStream;
}
public DataInputStream openDataInputStream() throws IOException {
return new DataInputStream(openInputStream());
}
public OutputStream openOutputStream() throws IOException {
return openOutputStream(false);
}
private OutputStream openOutputStream(final boolean append) throws IOException {
throwClosed();
throwOpenDirectory();
if (this.opendOutputStream != null) {
throw new IOException("OutputStream already opened");
}
/**
* Trying to open more than one InputStream or more than one
* OutputStream from a StreamConnection causes an IOException.
*/
this.opendOutputStream = (OutputStream) doPrivilegedIO(new PrivilegedExceptionAction() {
public Object run() throws IOException {
return new FileOutputStream(file, append) {
public void close() throws IOException {
FileSystemFileConnection.this.opendOutputStream = null;
super.close();
}
};
}
});
return this.opendOutputStream;
}
public DataOutputStream openDataOutputStream() throws IOException {
return new DataOutputStream(openOutputStream());
}
public OutputStream openOutputStream(long byteOffset) throws IOException {
throwClosed();
throwOpenDirectory();
if (this.opendOutputStream != null) {
throw new IOException("OutputStream already opened");
}
truncate(byteOffset);
return openOutputStream(true);
}
public void rename(final String newName) throws IOException {
throwClosed();
if (newName.indexOf(DIR_SEP) != -1) {
throw new IllegalArgumentException("Name contains path specification " + newName);
}
doPrivilegedIO(new PrivilegedExceptionAction() {
public Object run() throws IOException {
File newFile = new File(file.getParentFile(), newName);
if (!file.renameTo(newFile)) {
throw new IOException("Unable to rename " + file.getAbsolutePath() + " to "
+ newFile.getAbsolutePath());
}
return null;
}
});
this.fullPath = this.getPath() + newName;
}
public void setFileConnection(String s) throws IOException {
throwClosed();
// TODO Auto-generated method stub
}
public void setHidden(boolean hidden) throws IOException {
throwClosed();
}
private void fileSetJava16(String mehtodName, final Boolean param) throws IOException {
if (java15) {
throw new IOException("Not supported on Java version < 6");
}
// Use Java6 function in reflection.
try {
final Method setWritable = file.getClass().getMethod(mehtodName, new Class[] { boolean.class });
doPrivilegedIO(new PrivilegedExceptionAction() {
public Object run() throws IOException {
try {
setWritable.invoke(file, new Object[] { param });
} catch (Exception e) {
throw new IOException(e.getCause().getMessage());
}
file.setReadOnly();
return null;
}
});
} catch (NoSuchMethodException e) {
java15 = true;
}
}
public void setReadable(boolean readable) throws IOException {
throwClosed();
fileSetJava16("setReadable", new Boolean(readable));
}
public void setWritable(boolean writable) throws IOException {
throwClosed();
if (!writable) {
doPrivilegedIO(new PrivilegedExceptionAction() {
public Object run() throws IOException {
file.setReadOnly();
return null;
}
});
} else {
fileSetJava16("setWritable", new Boolean(writable));
}
}
public void truncate(final long byteOffset) throws IOException {
throwClosed();
doPrivilegedIO(new PrivilegedExceptionAction() {
public Object run() throws IOException {
RandomAccessFile raf = new RandomAccessFile(file, "rw");
try {
raf.setLength(byteOffset);
} finally {
raf.close();
}
return null;
}
});
}
public long usedSize() {
try {
return fileSize();
} catch (IOException e) {
return -1;
}
}
public void close() throws IOException {
if (this.file != null) {
if (this.notifyClosed != null) {
this.notifyClosed.notifyClosed(this);
}
locationClosedFrom = new Throwable();
locationClosedFrom.fillInStackTrace();
this.file = null;
}
}
private void throwClosed() throws ConnectionClosedException {
if (this.file == null) {
if (locationClosedFrom != null) {
locationClosedFrom.printStackTrace();
}
throw new ConnectionClosedException("Connection already closed");
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy