/**
* FUSE-J: Java bindings for FUSE (Filesystem in Userspace by Miklos Szeredi (mszeredi@inf.bme.hu))
*
* Copyright (C) 2003 Peter Levart (peter@select-tech.si)
*
* This program can be distributed under the terms of the GNU LGPL.
* See the file COPYING.LIB
*/
package fuse.zipfs;
import fuse.*;
import fuse.compat.Filesystem1;
import fuse.compat.FuseDirEnt;
import fuse.compat.FuseStat;
import fuse.zipfs.util.Node;
import fuse.zipfs.util.Tree;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;
public class ZipFilesystem implements Filesystem1
{
private static final Log log = LogFactory.getLog(ZipFilesystem.class);
private static final int blockSize = 512;
private ZipFile zipFile;
private long zipFileTime;
private ZipEntry rootEntry;
private Tree tree;
private FuseStatfs statfs;
private ZipFileDataReader zipFileDataReader;
public ZipFilesystem(File file) throws IOException
{
log.info("extracting zip file structure...");
zipFile = new ZipFile(file, ZipFile.OPEN_READ);
zipFileTime = file.lastModified();
rootEntry = new ZipEntry("")
{
public boolean isDirectory()
{
return true;
}
};
rootEntry.setTime(zipFileTime);
rootEntry.setSize(0);
zipFileDataReader = new ZipFileDataReader(zipFile);
tree = new Tree();
tree.addNode(rootEntry.getName(), rootEntry);
int files = 0;
int dirs = 0;
int blocks = 0;
for (Enumeration e = zipFile.entries(); e.hasMoreElements();)
{
ZipEntry entry = (ZipEntry) e.nextElement();
tree.addNode(entry.getName(), entry);
if (entry.isDirectory())
dirs++;
else
files++;
blocks += (entry.getSize() + blockSize - 1) / blockSize;
}
statfs = new FuseStatfs();
statfs.blocks = blocks;
statfs.blockSize = blockSize;
statfs.blocksFree = 0;
statfs.files = files + dirs;
statfs.filesFree = 0;
statfs.namelen = 2048;
log.info("zip file structure extracted: " + files + " files, " + dirs + " directories, " + blocks + " blocks (" + blockSize + " byte/block).");
}
public void chmod(String path, int mode) throws FuseException
{
throw new FuseException("Read Only").initErrno(FuseException.EACCES);
}
public void chown(String path, int uid, int gid) throws FuseException
{
throw new FuseException("Read Only").initErrno(FuseException.EACCES);
}
public FuseStat getattr(String path) throws FuseException
{
Node node = tree.lookupNode(path);
ZipEntry entry = null;
if (node == null || (entry = (ZipEntry)node.getValue()) == null)
throw new FuseException("No Such Entry").initErrno(FuseException.ENOENT);
FuseStat stat = new FuseStat();
stat.mode = entry.isDirectory() ? FuseFtype.TYPE_DIR | 0755 : FuseFtype.TYPE_FILE | 0644;
stat.nlink = 1;
stat.uid = 0;
stat.gid = 0;
stat.size = entry.getSize();
stat.atime = stat.mtime = stat.ctime = (int) (entry.getTime() / 1000L);
stat.blocks = (int) ((stat.size + 511L) / 512L);
return stat;
}
public FuseDirEnt[] getdir(String path) throws FuseException
{
Node node = tree.lookupNode(path);
ZipEntry entry = null;
if (node == null || (entry = (ZipEntry)node.getValue()) == null)
throw new FuseException("No Such Entry").initErrno(FuseException.ENOENT);
if (!entry.isDirectory())
throw new FuseException("Not A Directory").initErrno(FuseException.ENOTDIR);
Collection children = node.getChildren();
FuseDirEnt[] dirEntries = new FuseDirEnt[children.size()];
int i = 0;
for (Iterator iter = children.iterator(); iter.hasNext(); i++)
{
Node childNode = (Node)iter.next();
ZipEntry zipEntry = (ZipEntry)childNode.getValue();
FuseDirEnt dirEntry = new FuseDirEnt();
dirEntries[i] = dirEntry;
dirEntry.name = childNode.getName();
dirEntry.mode = zipEntry.isDirectory()? FuseFtype.TYPE_DIR : FuseFtype.TYPE_FILE;
}
return dirEntries;
}
public void link(String from, String to) throws FuseException
{
throw new FuseException("Read Only").initErrno(FuseException.EACCES);
}
public void mkdir(String path, int mode) throws FuseException
{
throw new FuseException("Read Only").initErrno(FuseException.EACCES);
}
public void mknod(String path, int mode, int rdev) throws FuseException
{
throw new FuseException("Read Only").initErrno(FuseException.EACCES);
}
public void open(String path, int flags) throws FuseException
{
ZipEntry entry = getFileZipEntry(path);
if (flags == O_WRONLY || flags == O_RDWR)
throw new FuseException("Read Only").initErrno(FuseException.EACCES);
}
public void rename(String from, String to) throws FuseException
{
throw new FuseException("Read Only").initErrno(FuseException.EACCES);
}
public void rmdir(String path) throws FuseException
{
throw new FuseException("Read Only").initErrno(FuseException.EACCES);
}
public FuseStatfs statfs() throws FuseException
{
return statfs;
}
public void symlink(String from, String to) throws FuseException
{
throw new FuseException("Read Only").initErrno(FuseException.EACCES);
}
public void truncate(String path, long size) throws FuseException
{
throw new FuseException("Read Only").initErrno(FuseException.EACCES);
}
public void unlink(String path) throws FuseException
{
throw new FuseException("Read Only").initErrno(FuseException.EACCES);
}
public void utime(String path, int atime, int mtime) throws FuseException
{
// noop
}
public String readlink(String path) throws FuseException
{
throw new FuseException("Not a link").initErrno(FuseException.ENOENT);
}
public void write(String path, ByteBuffer buf, long offset) throws FuseException
{
// noop
}
public void read(String path, ByteBuffer buf, long offset) throws FuseException
{
ZipEntry zipEntry = getFileZipEntry(path);
ZipEntryDataReader reader = zipFileDataReader.getZipEntryDataReader(zipEntry, offset, buf.capacity());
reader.read(buf, offset);
}
public void release(String path, int flags) throws FuseException
{
ZipEntry zipEntry = getFileZipEntry(path);
zipFileDataReader.releaseZipEntryDataReader(zipEntry);
}
//
// private methods
private ZipEntry getFileZipEntry(String path) throws FuseException
{
Node node = tree.lookupNode(path);
ZipEntry entry;
if (node == null || (entry = (ZipEntry)node.getValue()) == null)
throw new FuseException("No Such Entry").initErrno(FuseException.ENOENT);
if (entry.isDirectory())
throw new FuseException("Not A File").initErrno(FuseException.ENOENT);
return entry;
}
private ZipEntry getDirectoryZipEntry(String path) throws FuseException
{
Node node = tree.lookupNode(path);
ZipEntry entry;
if (node == null || (entry = (ZipEntry)node.getValue()) == null)
throw new FuseException("No Such Entry").initErrno(FuseException.ENOENT);
if (!entry.isDirectory())
throw new FuseException("Not A Directory").initErrno(FuseException.ENOENT);
return entry;
}
//
// Java entry point
public static void main(String[] args)
{
if (args.length < 1)
{
System.out.println("Must specify ZIP file");
System.exit(-1);
}
String fuseArgs[] = new String[args.length - 1];
System.arraycopy(args, 0, fuseArgs, 0, fuseArgs.length);
File zipFile = new File(args[args.length - 1]);
try
{
FuseMount.mount(fuseArgs, new ZipFilesystem(zipFile));
}
catch (Exception e)
{
e.printStackTrace();
}
}
}