Author: nextgens
Date: 2008-10-01 21:59:33 +0000 (Wed, 01 Oct 2008)
New Revision: 22907

Added:
   trunk/freenet/test/org/apache/
   trunk/freenet/test/org/apache/tools/
Modified:
   trunk/freenet/src/freenet/client/ArchiveManager.java
   trunk/freenet/src/freenet/client/ArchiveStoreContext.java
   trunk/freenet/src/freenet/client/Metadata.java
   trunk/freenet/src/freenet/client/async/SimpleManifestPutter.java
   trunk/freenet/src/freenet/client/async/SingleFileFetcher.java
   trunk/freenet/src/freenet/client/async/SingleFileInserter.java
   trunk/freenet/src/org/
   trunk/freenet/test/org/
Log:
Implements tar.bz2 archive manifests (bug #71)

It doesn't work yet but isn't enabled by default... And it needs to be reviewed 
by a client-layer expert ;)
Especially the change to the Metadata constructor! Do we need to set 
archiveType when it's a simple manifest?

Modified: trunk/freenet/src/freenet/client/ArchiveManager.java
===================================================================
--- trunk/freenet/src/freenet/client/ArchiveManager.java        2008-10-01 
21:01:09 UTC (rev 22906)
+++ trunk/freenet/src/freenet/client/ArchiveManager.java        2008-10-01 
21:59:33 UTC (rev 22907)
@@ -18,7 +18,12 @@
 import freenet.support.MutableBoolean;
 import freenet.support.api.Bucket;
 import freenet.support.api.BucketFactory;
+import freenet.support.compress.Bzip2Compressor;
 import freenet.support.io.BucketTools;
+import freenet.support.io.Closer;
+import org.apache.tools.bzip2.CBZip2InputStream;
+import org.apache.tools.tar.TarEntry;
+import org.apache.tools.tar.TarInputStream;

 /**
  * Cache of recently decoded archives:
@@ -34,6 +39,52 @@
        public static final String METADATA_NAME = ".metadata";
        private static boolean logMINOR;

+       public enum ARCHIVE_TYPE {
+               ZIP((short)0, new String[] { "application/zip", 
"application/x-zip" }),         /* eventually get rid of ZIP support at some 
point */
+               TAR((short)1, new String[] { "application/x-tar" });
+               
+               public final short metadataID;
+               public final String[] mimeTypes;
+               
+               private ARCHIVE_TYPE(short metadataID, String[] mimeTypes) {
+                       this.metadataID = metadataID;
+                       this.mimeTypes = mimeTypes;
+               }
+               
+               public static boolean isValidMetadataID(short id) {
+                       for(ARCHIVE_TYPE current : values())
+                               if(id == current.metadataID)
+                                       return true;
+                       return false;
+               }
+
+               /**
+                * Is the given MIME type an archive type that we can deal with?
+                */
+               public static boolean isUsableArchiveType(String type) {
+                       for(ARCHIVE_TYPE current : values())
+                               for(String ctype : current.mimeTypes)
+                                       if(ctype.equalsIgnoreCase(type))
+                                               return true;
+                       return false;
+               }
+
+               /** If the given MIME type is an archive type that we can deal 
with,
+                * get its archive type number (see the ARCHIVE_ constants in 
Metadata).
+                */
+               public static ARCHIVE_TYPE getArchiveType(String type) {
+                       for(ARCHIVE_TYPE current : values())
+                               for(String ctype : current.mimeTypes)
+                                       if(ctype.equalsIgnoreCase(type))
+                                               return current;
+                       return null;
+               }
+               
+               public final static ARCHIVE_TYPE getDefault() {
+                       return ZIP;
+               }
+       }
+       
        final long maxArchivedFileSize;

        // ArchiveHandler's
@@ -154,7 +205,7 @@
        /**
         * Extract data to cache. Call synchronized on ctx.
         * @param key The key the data was fetched from.
-        * @param archiveType The archive type. Must be Metadata.ARCHIVE_ZIP.
+        * @param archiveType The archive type. Must be Metadata.ARCHIVE_ZIP | 
Metadata.ARCHIVE_TAR.
         * @param data The actual data fetched.
         * @param archiveContext The context for the whole fetch process.
         * @param ctx The ArchiveStoreContext for this key.
@@ -198,9 +249,94 @@
                }
                if(data.size() > archiveContext.maxArchiveSize)
                        throw new ArchiveFailureException("Archive too big 
("+data.size()+" > "+archiveContext.maxArchiveSize+")!");
-               if(archiveType != Metadata.ARCHIVE_ZIP)
+               if(ARCHIVE_TYPE.ZIP.metadataID ==  archiveType)
+                       handleZIPArchive(ctx, key, data, element, callback, 
gotElement, throwAtExit);
+               else if(ARCHIVE_TYPE.TAR.metadataID == archiveType)
+                       handleTARArchive(ctx, key, data, element, callback, 
gotElement, throwAtExit);
+               else
                        throw new ArchiveFailureException("Unknown or 
unsupported archive algorithm "+archiveType);
-               
+       }
+       
+       private void handleTARArchive(ArchiveStoreContext ctx, FreenetURI key, 
Bucket data, String element, ArchiveExtractCallback callback, MutableBoolean 
gotElement, boolean throwAtExit) throws ArchiveFailureException, 
ArchiveRestartException {
+               if(logMINOR) Logger.minor(this, "Handling a TAR Archive");
+               CBZip2InputStream bz2is = null;
+               TarInputStream tarIS = null;
+               try {
+                       bz2is = new CBZip2InputStream(data.getInputStream());
+                       tarIS = new TarInputStream(bz2is);
+                       
+                       // MINOR: Assumes the first entry in the tarball is a 
directory. 
+                       TarEntry entry;
+                       
+                       byte[] buf = new byte[32768];
+                       HashSet names = new HashSet();
+                       boolean gotMetadata = false;
+                       
+outerTAR:              while(true) {
+                               entry = tarIS.getNextEntry();
+                               if(entry == null) break;
+                               if(entry.isDirectory()) continue;
+                               String name = entry.getName();
+                               if(names.contains(name)) {
+                                       Logger.error(this, "Duplicate key 
"+name+" in archive "+key);
+                                       continue;
+                               }
+                               long size = entry.getSize();
+                               if(size > maxArchivedFileSize) {
+                                       addErrorElement(ctx, key, name, "File 
too big: "+maxArchivedFileSize+" greater than current archived file size limit 
"+maxArchivedFileSize);
+                               } else {
+                                       // Read the element
+                                       long realLen = 0;
+                                       Bucket output = 
tempBucketFactory.makeBucket(size);
+                                       OutputStream out = 
output.getOutputStream();
+
+                                       int readBytes;
+                                       while((readBytes = tarIS.read(buf)) > 
0) {
+                                               out.write(buf, 0, readBytes);
+                                               readBytes += realLen;
+                                               if(readBytes > 
maxArchivedFileSize) {
+                                                       addErrorElement(ctx, 
key, name, "File too big: "+maxArchivedFileSize+" greater than current archived 
file size limit "+maxArchivedFileSize);
+                                                       out.close();
+                                                       output.free();
+                                                       continue outerTAR;
+                                               }
+                                       }
+
+                                       out.close();
+                                       if(name.equals(".metadata"))
+                                               gotMetadata = true;
+                                       addStoreElement(ctx, key, name, output, 
gotElement, element, callback);
+                                       names.add(name);
+                                       trimStoredData();
+                               }
+                       }
+
+                       // If no metadata, generate some
+                       if(!gotMetadata) {
+                               generateMetadata(ctx, key, names, gotElement, 
element, callback);
+                               trimStoredData();
+                       }
+                       if(throwAtExit) throw new 
ArchiveRestartException("Archive changed on re-fetch");
+                       
+                       if((!gotElement.value) && element != null)
+                               callback.notInArchive();
+                       
+               } catch (IOException e) {
+                       throw new ArchiveFailureException("Error reading 
archive: "+e.getMessage(), e);
+               } finally {
+                       if(bz2is != null) {
+                               try {
+                                       bz2is.close();
+                               } catch (IOException e) {
+                                       Logger.error(this, "Failed to close 
stream: "+e, e);
+                               }
+                       }
+                       Closer.close(tarIS);
+               }
+       }
+       
+       private void handleZIPArchive(ArchiveStoreContext ctx, FreenetURI key, 
Bucket data, String element, ArchiveExtractCallback callback, MutableBoolean 
gotElement, boolean throwAtExit) throws ArchiveFailureException, 
ArchiveRestartException {
+               if(logMINOR) Logger.minor(this, "Handling a ZIP Archive");
                ZipInputStream zis = null;
                try {
                        zis = new ZipInputStream(data.getInputStream());
@@ -212,7 +348,7 @@
                        HashSet names = new HashSet();
                        boolean gotMetadata = false;

-outer:         while(true) {
+outerZIP:              while(true) {
                                entry = zis.getNextEntry();
                                if(entry == null) break;
                                if(entry.isDirectory()) continue;
@@ -238,7 +374,7 @@
                                                        addErrorElement(ctx, 
key, name, "File too big: "+maxArchivedFileSize+" greater than current archived 
file size limit "+maxArchivedFileSize);
                                                        out.close();
                                                        output.free();
-                                                       continue outer;
+                                                       continue outerZIP;
                                                }
                                        }

@@ -452,21 +588,4 @@
                }
                }
        }
-
-       /**
-        * Is the given MIME type an archive type that we can deal with?
-        */
-       public static boolean isUsableArchiveType(String type) {
-               return type.equals("application/zip") || 
type.equals("application/x-zip");
-               // Update when add new archive types
-       }
-
-       /** If the given MIME type is an archive type that we can deal with,
-        * get its archive type number (see the ARCHIVE_ constants in Metadata).
-        */
-       public static short getArchiveType(String type) {
-               if(type.equals("application/zip") || 
type.equals("application/x-zip"))
-                       return Metadata.ARCHIVE_ZIP;
-               else throw new IllegalArgumentException(); 
-       }
 }

Modified: trunk/freenet/src/freenet/client/ArchiveStoreContext.java
===================================================================
--- trunk/freenet/src/freenet/client/ArchiveStoreContext.java   2008-10-01 
21:01:09 UTC (rev 22906)
+++ trunk/freenet/src/freenet/client/ArchiveStoreContext.java   2008-10-01 
21:59:33 UTC (rev 22907)
@@ -24,7 +24,7 @@

        private ArchiveManager manager;
        private FreenetURI key;
-       private short archiveType;
+       private final short archiveType;
        private boolean forceRefetchArchive;
        /** Archive size */
        private long lastSize = -1;

Modified: trunk/freenet/src/freenet/client/Metadata.java
===================================================================
--- trunk/freenet/src/freenet/client/Metadata.java      2008-10-01 21:01:09 UTC 
(rev 22906)
+++ trunk/freenet/src/freenet/client/Metadata.java      2008-10-01 21:59:33 UTC 
(rev 22907)
@@ -19,6 +19,7 @@
 import freenet.keys.BaseClientKey;
 import freenet.keys.ClientCHK;
 import freenet.keys.FreenetURI;
+import freenet.client.ArchiveManager.ARCHIVE_TYPE;
 import freenet.support.Fields;
 import freenet.support.Logger;
 import freenet.support.api.Bucket;
@@ -45,8 +46,8 @@
        public static final byte SIMPLE_REDIRECT = 0;
        static final byte MULTI_LEVEL_METADATA = 1;
        static final byte SIMPLE_MANIFEST = 2;
-       public static final byte ZIP_MANIFEST = 3;
-       public static final byte ZIP_INTERNAL_REDIRECT = 4;
+       public static final byte ARCHIVE_MANIFEST = 3;
+       public static final byte ARCHIVE_INTERNAL_REDIRECT = 4;

        // 2 bytes of flags
        /** Is a splitfile */
@@ -70,15 +71,15 @@
 //     static final short FLAGS_SPLIT_USE_LENGTHS = 64; FIXME not supported, 
reassign to something else if we need a new flag
        static final short FLAGS_COMPRESSED = 128;

-       /** Container archive type */
+       /** Container archive type 
+        * @see ARCHIVE_TYPE
+        */
        short archiveType;
-       static final short ARCHIVE_ZIP = 0;
-       static final short ARCHIVE_TAR = 1; // FIXME for future use

-       /** Compressed splitfile codec */
+       /** Compressed splitfile codec 
+        * @see COMPRESSOR_TYPE
+        */
        short compressionCodec = -1;
-       public static final short COMPRESS_GZIP = 
COMPRESSOR_TYPE.GZIP.metadataID;
-       public static final short COMPRESS_BZIP2 = 
COMPRESSOR_TYPE.BZIP2.metadataID;

        /** The length of the splitfile */
        long dataLength;
@@ -183,7 +184,7 @@

                boolean compressed = false;
                if((documentType == SIMPLE_REDIRECT) || (documentType == 
MULTI_LEVEL_METADATA)
-                               || (documentType == ZIP_MANIFEST) || 
(documentType == ZIP_INTERNAL_REDIRECT)) {
+                               || (documentType == ARCHIVE_MANIFEST) || 
(documentType == ARCHIVE_INTERNAL_REDIRECT)) {
                        short flags = dis.readShort();
                        splitfile = (flags & FLAGS_SPLITFILE) == 
FLAGS_SPLITFILE;
                        dbr = (flags & FLAGS_DBR) == FLAGS_DBR;
@@ -194,10 +195,10 @@
                        compressed = (flags & FLAGS_COMPRESSED) == 
FLAGS_COMPRESSED;
                }

-               if(documentType == ZIP_MANIFEST) {
-                       if(logMINOR) Logger.minor(this, "Zip manifest");
+               if(documentType == ARCHIVE_MANIFEST) {
+                       if(logMINOR) Logger.minor(this, "Archive manifest");
                        archiveType = dis.readShort();
-                       if(archiveType != ARCHIVE_ZIP)
+                       if(!ARCHIVE_TYPE.isValidMetadataID(archiveType))
                                throw new MetadataParseException("Unrecognized 
archive type "+archiveType);
                }

@@ -268,7 +269,7 @@

                clientMetadata = new ClientMetadata(mimeType);

-               if((!splitfile) && ((documentType == SIMPLE_REDIRECT) || 
(documentType == ZIP_MANIFEST))) {
+               if((!splitfile) && ((documentType == SIMPLE_REDIRECT) || 
(documentType == ARCHIVE_MANIFEST))) {
                        simpleRedirectKey = readKey(dis);
                } else if(splitfile) {
                        splitfileAlgorithm = dis.readShort();
@@ -345,13 +346,13 @@
                        if(logMINOR) Logger.minor(this, "End of manifest"); // 
Make it easy to search for it!
                }

-               if(documentType == ZIP_INTERNAL_REDIRECT) {
+               if(documentType == ARCHIVE_INTERNAL_REDIRECT) {
                        int len = dis.readShort();
                        if(logMINOR) Logger.minor(this, "Reading zip internal 
redirect length "+len);
                        byte[] buf = new byte[len];
                        dis.readFully(buf);
                        nameInArchive = new String(buf, "UTF-8");
-                       if(logMINOR) Logger.minor(this, "Zip internal redirect: 
"+nameInArchive+" ("+len+ ')');
+                       if(logMINOR) Logger.minor(this, "Archive internal 
redirect: "+nameInArchive+" ("+len+ ')');
                }
        }

@@ -470,7 +471,7 @@
                        Metadata target;
                        if(o instanceof String) {
                                // Zip internal redirect
-                               target = new Metadata(ZIP_INTERNAL_REDIRECT, 
prefix+key, new ClientMetadata(DefaultMIMETypes.guessMIMEType(key, false)));
+                               target = new 
Metadata(ARCHIVE_INTERNAL_REDIRECT, prefix+key, new 
ClientMetadata(DefaultMIMETypes.guessMIMEType(key, false)));
                        } else if(o instanceof HashMap) {
                                target = new Metadata((HashMap)o, 
prefix+key+"/");
                        } else throw new IllegalArgumentException("Not String 
nor HashMap: "+o);
@@ -486,7 +487,7 @@
         * the archive to read from.
         */
        public Metadata(byte docType, String arg, ClientMetadata cm) {
-               if(docType == ZIP_INTERNAL_REDIRECT) {
+               if(docType == ARCHIVE_INTERNAL_REDIRECT) {
                        documentType = docType;
                        // Determine MIME type
                        this.clientMetadata = cm;
@@ -504,8 +505,9 @@
         * @param cm The client metadata, if any.
         */
        public Metadata(byte docType, FreenetURI uri, ClientMetadata cm) {
-               if((docType == SIMPLE_REDIRECT) || (docType == ZIP_MANIFEST)) {
+               if((docType == SIMPLE_REDIRECT) || (docType == 
ARCHIVE_MANIFEST)) {
                        documentType = docType;
+                       archiveType = ARCHIVE_TYPE.getDefault().metadataID;
                        clientMetadata = cm;
                        if((cm != null) && !cm.isTrivial()) {
                                setMIMEType(cm.getMIMEType());
@@ -526,7 +528,7 @@
                        documentType = MULTI_LEVEL_METADATA;
                else {
                        if(insertAsArchiveManifest)
-                               documentType = ZIP_MANIFEST;
+                               documentType = ARCHIVE_MANIFEST;
                        else documentType = SIMPLE_REDIRECT;
                }
                splitfile = true;
@@ -668,7 +670,7 @@
        public boolean isSingleFileRedirect() {
                return (((!splitfile) &&
                                (documentType == SIMPLE_REDIRECT)) || 
(documentType == MULTI_LEVEL_METADATA) ||
-                               (documentType == ZIP_MANIFEST));
+                               (documentType == ARCHIVE_MANIFEST));
        }

        /**
@@ -682,7 +684,7 @@
         * Is this a ZIP manifest?
         */
        public boolean isArchiveManifest() {
-               return documentType == ZIP_MANIFEST;
+               return documentType == ARCHIVE_MANIFEST;
        }

        /**
@@ -690,7 +692,7 @@
         * @return
         */
        public boolean isArchiveInternalRedirect() {
-               return documentType == ZIP_INTERNAL_REDIRECT;
+               return documentType == ARCHIVE_INTERNAL_REDIRECT;
        }

        /**
@@ -743,7 +745,7 @@
                dos.writeShort(0); // version
                dos.writeByte(documentType);
                if((documentType == SIMPLE_REDIRECT) || (documentType == 
MULTI_LEVEL_METADATA)
-                               || (documentType == ZIP_MANIFEST) || 
(documentType == ZIP_INTERNAL_REDIRECT)) {
+                               || (documentType == ARCHIVE_MANIFEST) || 
(documentType == ARCHIVE_INTERNAL_REDIRECT)) {
                        short flags = 0;
                        if(splitfile) flags |= FLAGS_SPLITFILE;
                        if(dbr) flags |= FLAGS_DBR;
@@ -755,7 +757,7 @@
                        dos.writeShort(flags);
                }

-               if(documentType == ZIP_MANIFEST) {
+               if(documentType == ARCHIVE_MANIFEST) {
                        dos.writeShort(archiveType);
                }

@@ -789,7 +791,7 @@
                if(extraMetadata)
                        throw new UnsupportedOperationException("No extra 
metadata support yet");

-               if((!splitfile) && ((documentType == SIMPLE_REDIRECT) || 
(documentType == ZIP_MANIFEST))) {
+               if((!splitfile) && ((documentType == SIMPLE_REDIRECT) || 
(documentType == ARCHIVE_MANIFEST))) {
                        writeKey(dos, simpleRedirectKey);
                } else if(splitfile) {
                        dos.writeShort(splitfileAlgorithm);
@@ -850,7 +852,7 @@
                        }
                }

-               if(documentType == ZIP_INTERNAL_REDIRECT) {
+               if(documentType == ARCHIVE_INTERNAL_REDIRECT) {
                        byte[] data = nameInArchive.getBytes("UTF-8");
                        if(data.length > Short.MAX_VALUE) throw new 
IllegalArgumentException("Zip internal redirect name too long");
                        dos.writeShort(data.length);
@@ -911,9 +913,9 @@
        }

        public void setArchiveManifest() {
-               archiveType = 
ArchiveManager.getArchiveType(clientMetadata.getMIMEType());
+               archiveType = 
ARCHIVE_TYPE.getArchiveType(clientMetadata.getMIMEType()).metadataID;
                clientMetadata.clear();
-               documentType = ZIP_MANIFEST;
+               documentType = ARCHIVE_MANIFEST;
        }

        public String getMIMEType() {

Modified: trunk/freenet/src/freenet/client/async/SimpleManifestPutter.java
===================================================================
--- trunk/freenet/src/freenet/client/async/SimpleManifestPutter.java    
2008-10-01 21:01:09 UTC (rev 22906)
+++ trunk/freenet/src/freenet/client/async/SimpleManifestPutter.java    
2008-10-01 21:59:33 UTC (rev 22907)
@@ -1,5 +1,6 @@
 package freenet.client.async;

+import freenet.client.ArchiveManager.ARCHIVE_TYPE;
 import java.io.BufferedOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -9,7 +10,6 @@
 import java.util.LinkedList;
 import java.util.Vector;
 import java.util.zip.ZipEntry;
-import java.util.zip.ZipException;
 import java.util.zip.ZipOutputStream;

 import freenet.client.ClientMetadata;
@@ -25,6 +25,9 @@
 import freenet.support.Logger;
 import freenet.support.api.Bucket;
 import freenet.support.io.BucketTools;
+import org.apache.tools.bzip2.CBZip2OutputStream;
+import org.apache.tools.tar.TarEntry;
+import org.apache.tools.tar.TarOutputStream;

 public class SimpleManifestPutter extends BaseClientPutter implements 
PutCompletionCallback {
        // Only implements PutCompletionCallback for the final metadata insert
@@ -51,12 +54,12 @@
                        origSFI = null;
                }

-               protected PutHandler(final SimpleManifestPutter smp, String 
name, String targetInZip, ClientMetadata cm, Bucket data) {
+               protected PutHandler(final SimpleManifestPutter smp, String 
name, String targetInArchive, ClientMetadata cm, Bucket data) {
                        super(smp.getPriorityClass(), smp.chkScheduler, 
smp.sskScheduler, smp.client);
                        this.cm = cm;
                        this.data = data;
-                       this.targetInZip = targetInZip;
-                       Metadata m = new 
Metadata(Metadata.ZIP_INTERNAL_REDIRECT, targetInZip, cm);
+                       this.targetInArchive = targetInArchive;
+                       Metadata m = new 
Metadata(Metadata.ARCHIVE_INTERNAL_REDIRECT, targetInArchive, cm);
                        metadata = m;
                        origSFI = null;
                }
@@ -64,7 +67,7 @@
                private SingleFileInserter origSFI;
                private ClientMetadata cm;
                private Metadata metadata;
-               private String targetInZip;
+               private String targetInArchive;
                private final Bucket data;

                public void start() throws InsertException {
@@ -222,7 +225,7 @@
        private final static String[] defaultDefaultNames =
                new String[] { "index.html", "index.htm", "default.html", 
"default.htm" };
        private int bytesOnZip;
-       private LinkedList elementsToPutInZip;
+       private LinkedList<PutHandler> elementsToPutInArchive;
        private boolean fetchable;
        private final boolean earlyEncode;

@@ -244,7 +247,7 @@
                waitingForBlockSets = new HashSet();
                metadataPuttersByMetadata = new HashMap();
                metadataPuttersUnfetchable = new HashMap();
-               elementsToPutInZip = new LinkedList();
+               elementsToPutInArchive = new LinkedList();
                makePutHandlers(manifestElements, putHandlersByName);
                checkZips();
        }
@@ -324,7 +327,7 @@
                                                bytesOnZip += sz;
                                                // Put it in the zip.
                                                ph = new PutHandler(this, name, 
ZipPrefix+element.fullName, cm, data);
-                                               elementsToPutInZip.addLast(ph);
+                                               
elementsToPutInArchive.addLast(ph);
                                                numberOfFiles++;
                                                totalSize += data.size();
                                        } else {
@@ -415,52 +418,26 @@
                InsertBlock block;
                boolean isMetadata = true;
                boolean insertAsArchiveManifest = false;
-               if(!(elementsToPutInZip.isEmpty())) {
-                       // There is a zip to insert.
+               if(!(elementsToPutInArchive.isEmpty())) {
+                       // There is an archive to insert.
                        // We want to include the metadata.
                        // We have the metadata, fortunately enough, because 
everything has been resolve()d.
-                       // So all we need to do is create the actual ZIP.
-                       try {
+                       // So all we need to do is create the actual archive.
+                       try {                           
+                               Bucket outputBucket = 
ctx.bf.makeBucket(baseMetadata.dataLength());
+                               // TODO: try both ? - maybe not worth it
+                               String mimeType = (ARCHIVE_TYPE.getDefault() == 
ARCHIVE_TYPE.TAR ?
+                                       createTarBucket(bucket, outputBucket) :
+                                       createZipBucket(bucket, outputBucket));

-                               // FIXME support formats other than .zip.
-                               // Only the *decoding* is generic at present.
+                               // Now we have to insert the Archive we have 
generated.

-                               Bucket zipBucket = 
ctx.bf.makeBucket(baseMetadata.dataLength());
-                               OutputStream os = new 
BufferedOutputStream(zipBucket.getOutputStream());
-                               ZipOutputStream zos = new ZipOutputStream(os);
-                               ZipEntry ze;
-                               
-                               for(Iterator 
i=elementsToPutInZip.iterator();i.hasNext();) {
-                                       PutHandler ph = (PutHandler) i.next();
-                                       ze = new ZipEntry(ph.targetInZip);
-                                       ze.setTime(0);
-                                       zos.putNextEntry(ze);
-                                       BucketTools.copyTo(ph.data, zos, 
ph.data.size());
-                               }
-                               
-                               // Add .metadata - after the rest.
-                               ze = new ZipEntry(".metadata");
-                               ze.setTime(0); // -1 = now, 0 = 1970.
-                               zos.putNextEntry(ze);
-                               BucketTools.copyTo(bucket, zos, bucket.size());
-                               
-                               zos.closeEntry();
-                               // Both finish() and close() are necessary.
-                               zos.finish();
-                               zos.flush();
-                               zos.close();
-                               
-                               // Now we have to insert the ZIP.
-                               
                                // Can we just insert it, and not bother with a 
redirect to it?
                                // Thereby exploiting implicit manifest 
support, which will pick up on .metadata??
                                // We ought to be able to !!
-                               block = new InsertBlock(zipBucket, new 
ClientMetadata("application/zip"), targetURI);
+                               block = new InsertBlock(outputBucket, new 
ClientMetadata(mimeType), targetURI);
                                isMetadata = false;
                                insertAsArchiveManifest = true;
-                       } catch (ZipException e) {
-                               fail(new 
InsertException(InsertException.INTERNAL_ERROR, e, null));
-                               return;
                        } catch (IOException e) {
                                fail(new 
InsertException(InsertException.BUCKET_ERROR, e, null));
                                return;
@@ -479,6 +456,72 @@
                }
        }

+       private String createTarBucket(Bucket inputBucket, Bucket outputBucket) 
throws IOException {
+               if(logMINOR) Logger.minor(this, "Create a TAR Bucket");
+               
+               OutputStream os = new 
BufferedOutputStream(outputBucket.getOutputStream());
+               CBZip2OutputStream bz2OS = new CBZip2OutputStream(os);
+               TarOutputStream tarOS = new TarOutputStream(bz2OS);
+               TarEntry ze;
+
+               for(PutHandler ph : elementsToPutInArchive) {
+                       ze = new TarEntry(ph.targetInArchive);
+                       ze.setModTime(0);
+                       long size = ph.data.size();
+                       ze.setSize(size);
+                       tarOS.putNextEntry(ze);
+                       BucketTools.copyTo(ph.data, tarOS, size);
+                       tarOS.closeEntry();
+               }
+
+               // Add .metadata - after the rest.
+               ze = new TarEntry(".metadata");
+               ze.setModTime(0); // -1 = now, 0 = 1970.
+               long size = inputBucket.size();
+               ze.setSize(size);
+               tarOS.putNextEntry(ze);
+               BucketTools.copyTo(inputBucket, tarOS, size);
+
+               tarOS.closeEntry();
+               // Both finish() and close() are necessary.
+               tarOS.finish();
+               tarOS.flush();
+               tarOS.close();
+               
+               return ARCHIVE_TYPE.TAR.mimeTypes[0];
+       }
+       
+       private String createZipBucket(Bucket inputBucket, Bucket outputBucket) 
throws IOException {
+               if(logMINOR) Logger.minor(this, "Create a ZIP Bucket");
+               
+               OutputStream os = new 
BufferedOutputStream(outputBucket.getOutputStream());
+               ZipOutputStream zos = new ZipOutputStream(os);
+               ZipEntry ze;
+
+               for(Iterator i = elementsToPutInArchive.iterator(); 
i.hasNext();) {
+                       PutHandler ph = (PutHandler) i.next();
+                       ze = new ZipEntry(ph.targetInArchive);
+                       ze.setTime(0);
+                       zos.putNextEntry(ze);
+                       BucketTools.copyTo(ph.data, zos, ph.data.size());
+                       zos.closeEntry();
+               }
+
+               // Add .metadata - after the rest.
+               ze = new ZipEntry(".metadata");
+               ze.setTime(0); // -1 = now, 0 = 1970.
+               zos.putNextEntry(ze);
+               BucketTools.copyTo(inputBucket, zos, inputBucket.size());
+
+               zos.closeEntry();
+               // Both finish() and close() are necessary.
+               zos.finish();
+               zos.flush();
+               zos.close();
+               
+               return ARCHIVE_TYPE.ZIP.mimeTypes[0];
+       }
+
        private boolean resolve(MetadataUnresolvedException e) throws 
InsertException, IOException {
                Metadata[] metas = e.mustResolve;
                boolean mustWait = false;

Modified: trunk/freenet/src/freenet/client/async/SingleFileFetcher.java
===================================================================
--- trunk/freenet/src/freenet/client/async/SingleFileFetcher.java       
2008-10-01 21:01:09 UTC (rev 22906)
+++ trunk/freenet/src/freenet/client/async/SingleFileFetcher.java       
2008-10-01 21:59:33 UTC (rev 22907)
@@ -162,7 +162,7 @@
                                metadata = Metadata.construct(data);
                                wrapHandleMetadata(false);
                        } catch (MetadataParseException e) {
-                               onFailure(new FetchException(e), sched);
+                               onFailure(new 
FetchException(FetchException.INVALID_METADATA, e), sched);
                                return;
                        } catch (IOException e) {
                                // Bucket error?
@@ -255,11 +255,11 @@
                                        metadata = metadata.getDocument(name);
                                        thisKey = thisKey.pushMetaString(name);
                                        if(metadata == null)
-                                               throw new 
FetchException(FetchException.NOT_IN_ARCHIVE);
+                                               throw new 
FetchException(FetchException.NOT_IN_ARCHIVE, "can't find "+name);
                                }
                                continue; // loop
                        } else if(metadata.isArchiveManifest()) {
-                               if(logMINOR) Logger.minor(this, "Is archive 
manifest");
+                               if(logMINOR) Logger.minor(this, "Is archive 
manifest (type="+metadata.getArchiveType()+')');
                                if(metaStrings.isEmpty() && 
ctx.returnZIPManifests) {
                                        // Just return the archive, whole.
                                        metadata.setSimpleRedirect();
@@ -396,7 +396,7 @@
                                if(mime != null) rcb.onExpectedMIME(mime);

                                String mimeType = 
clientMetadata.getMIMETypeNoParams();
-                               if(mimeType != null && 
ArchiveManager.isUsableArchiveType(mimeType) && metaStrings.size() > 0) {
+                               if(mimeType != null && 
ArchiveManager.ARCHIVE_TYPE.isUsableArchiveType(mimeType) && metaStrings.size() 
> 0) {
                                        // Looks like an implicit archive, 
handle as such
                                        metadata.setArchiveManifest();
                                        // Pick up MIME type from inside archive
@@ -461,7 +461,7 @@
                                if(mime != null) rcb.onExpectedMIME(mime);

                                String mimeType = 
clientMetadata.getMIMETypeNoParams();
-                               if(mimeType != null && 
ArchiveManager.isUsableArchiveType(mimeType) && metaStrings.size() > 0) {
+                               if(mimeType != null && 
ArchiveManager.ARCHIVE_TYPE.isUsableArchiveType(mimeType) && metaStrings.size() 
> 0) {
                                        // Looks like an implicit archive, 
handle as such
                                        metadata.setArchiveManifest();
                                        // Pick up MIME type from inside archive
@@ -573,7 +573,7 @@
                try {
                        handleMetadata();
                } catch (MetadataParseException e) {
-                       onFailure(new FetchException(e), sched);
+                       onFailure(new 
FetchException(FetchException.INVALID_METADATA, e), sched);
                } catch (FetchException e) {
                        if(notFinalizedSize)
                                e.setNotFinalizedSize();

Modified: trunk/freenet/src/freenet/client/async/SingleFileInserter.java
===================================================================
--- trunk/freenet/src/freenet/client/async/SingleFileInserter.java      
2008-10-01 21:01:09 UTC (rev 22906)
+++ trunk/freenet/src/freenet/client/async/SingleFileInserter.java      
2008-10-01 21:59:33 UTC (rev 22907)
@@ -294,7 +294,7 @@
        }

        private Metadata makeMetadata(FreenetURI uri) {
-               Metadata meta = new Metadata(insertAsArchiveManifest ? 
Metadata.ZIP_MANIFEST : Metadata.SIMPLE_REDIRECT, uri, block.clientMetadata);
+               Metadata meta = new Metadata(insertAsArchiveManifest ? 
Metadata.ARCHIVE_MANIFEST : Metadata.SIMPLE_REDIRECT, uri, 
block.clientMetadata);
                if(targetFilename != null) {
                        HashMap hm = new HashMap();
                        hm.put(targetFilename, meta);


Property changes on: trunk/freenet/src/org
___________________________________________________________________
Name: svn:externals
   - apache/tools/bzip2 
http://svn.apache.org/repos/asf/ant/core/tags/ANT_171/src/main/org/apache/tools/bzip2/

   + apache/tools/bzip2 
http://svn.apache.org/repos/asf/ant/core/tags/ANT_171/src/main/org/apache/tools/bzip2/
apache/tools/tar 
http://svn.apache.org/repos/asf/ant/core/tags/ANT_171/src/main/org/apache/tools/tar/



Property changes on: trunk/freenet/test/org
___________________________________________________________________
Name: svn:externals
   + apache/tools/tar 
http://svn.apache.org/repos/asf/ant/core/tags/ANT_171/src/tests/junit/org/apache/tools/tar/



Reply via email to