package org.primftpd.filesystem;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class AndroidFile<T> {
protected final Logger logger = LoggerFactory.getLogger(getClass());
protected final File file;
public AndroidFile(File file) {
super();
this.file = file;
}
protected abstract T createFile(File file);
public String getAbsolutePath() {
logger.trace("getAbsolutePath()");
return file.getAbsolutePath();
}
public String getName() {
logger.trace("getName()");
return file.getName();
}
public boolean isHidden() {
logger.trace("isHidden()");
return file.isHidden();
}
public boolean isDirectory() {
boolean isDirectory = file.isDirectory();
logger.trace(
"isDirectory(), ({}): {}",
file.getAbsolutePath(),
Boolean.valueOf(isDirectory));
return isDirectory;
}
public boolean isFile() {
boolean isFile = file.isFile();
logger.trace(
"isFile(), ({}): {}",
file.getAbsolutePath(),
Boolean.valueOf(isFile));
return isFile;
}
public boolean doesExist() {
boolean exists = file.exists();
boolean existsChecked = exists;
if (!exists) {
// exists may be false when we don't have read permission
// try to figure out if it really does not exist
File parentFile = file.getParentFile();
File[] children = parentFile.listFiles();
for (File child : children) {
if (file.equals(child)) {
existsChecked = true;
break;
}
}
}
logger.trace(
"doesExist(), ({}): orig val: {}, checked val: {}",
new Object[]{
file.getAbsolutePath(),
Boolean.valueOf(exists),
Boolean.valueOf(existsChecked)
});
return existsChecked;
}
public boolean isReadable() {
boolean canRead = file.canRead();
logger.trace(
"isReadable(), ({}): {}",
file.getAbsolutePath(),
Boolean.valueOf(canRead));
return canRead;
}
public boolean isWritable() {
logger.trace(
"writable: {}, exists: {}, file: '{}'",
new Object[]{
file.canWrite(),
file.exists(),
file.getName()
});
if (file.exists()) {
return file.canWrite();
}
// file does not exist, probably an upload of a new file, check parent
// must be done in loop as some clients to not issue mkdir commands
// like filezilla
File parent = file.getParentFile();
while (parent != null) {
if (parent.exists()) {
return parent.canWrite();
}
parent = parent.getParentFile();
}
return false;
}
public boolean isRemovable() {
logger.trace("isRemovable()");
return file.canWrite();
}
public int getLinkCount() {
logger.trace("getLinkCount()");
return 0;
}
public long getLastModified() {
long lastModified = file.lastModified();
logger.trace("getLastModified() -> {}", Long.valueOf(lastModified));
return lastModified;
}
public boolean setLastModified(long time) {
logger.trace("setLastModified({})", Long.valueOf(time));
return file.setLastModified(time);
}
public long getSize() {
long size = file.length();
logger.trace("getSize() -> {}", Long.valueOf(size));
return size;
}
public boolean mkdir() {
logger.trace("mkdir()");
return file.mkdir();
}
public boolean delete() {
logger.trace("delete()");
return file.delete();
}
public boolean move(AndroidFile<T> destination) {
logger.trace("move({})", destination.getAbsolutePath());
file.renameTo(new File(destination.getAbsolutePath()));
return true;
}
public List<T> listFiles() {
logger.trace("listFiles()");
File[] filesArray = file.listFiles();
if (filesArray != null) {
List<T> files = new ArrayList<T>(filesArray.length);
for (File file : filesArray) {
files.add(createFile(file));
}
return files;
}
logger.debug("file.listFiles() returned null. Path: {}", file.getAbsolutePath());
return new ArrayList<T>(0);
}
public static final int BUFFER_SIZE = 1024 * 1024;
public OutputStream createOutputStream(long offset) throws IOException {
logger.trace("createOutputStream({})", offset);
// may be necessary to create dirs
// see isWritable()
File parent = file.getParentFile();
if (!parent.exists()) {
parent.mkdirs();
}
// now create out stream
OutputStream os = null;
if (offset == 0) {
os = new FileOutputStream(file);
} else if (offset == this.file.length()) {
os = new FileOutputStream(file, true);
} else {
final RandomAccessFile raf = new RandomAccessFile(this.file, "rw");
raf.seek(offset);
os = new OutputStream() {
@Override
public void write(int oneByte) throws IOException {
raf.write(oneByte);
}
@Override
public void close() throws IOException {
raf.close();
}
};
}
BufferedOutputStream bos = new BufferedOutputStream(os, BUFFER_SIZE);
return bos;
}
public InputStream createInputStream(long offset) throws IOException {
logger.trace("createInputStream(), offset: {}, file: {}", offset, file.getAbsolutePath());
FileInputStream fis = new FileInputStream(file);
fis.skip(offset);
BufferedInputStream bis = new BufferedInputStream(fis, BUFFER_SIZE);
return bis;
}
public File getFile() {
return file;
}
}