Bug 358470 [Import/Export] Export project does not export empty folders
diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/ArchiveFileExportOperation.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/ArchiveFileExportOperation.java
index 1c3736e..9504059 100644
--- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/ArchiveFileExportOperation.java
+++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/ArchiveFileExportOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -162,6 +162,20 @@
             throws InterruptedException {
         exportResource(exportResource, 1);
     }
+    
+    /**
+     * Creates and returns the string that should be used as the name of the entry in the archive.
+     * @param exportResource the resource to export
+     * @param leadupDepth the number of resource levels to be included in the path including the resourse itself.
+     */
+    private String createDestinationName(int leadupDepth, IResource exportResource) {
+        IPath fullPath = exportResource.getFullPath();
+        if (createLeadupStructure) {
+        	return fullPath.makeRelative().toString();
+        }
+		return fullPath.removeFirstSegments(
+                fullPath.segmentCount() - leadupDepth).toString();
+    }
 
     /**
      *  Export the passed resource to the destination .zip
@@ -177,14 +191,7 @@
 		}
 
         if (exportResource.getType() == IResource.FILE) {
-            String destinationName;
-            IPath fullPath = exportResource.getFullPath();
-            if (createLeadupStructure) {
-				destinationName = fullPath.makeRelative().toString();
-			} else {
-				destinationName = fullPath.removeFirstSegments(
-                        fullPath.segmentCount() - leadupDepth).toString();
-			}
+        	String destinationName = createDestinationName(leadupDepth, exportResource);
             monitor.subTask(destinationName);
 
             try {
@@ -206,6 +213,15 @@
                 // this should never happen because an #isAccessible check is done before #members is invoked
                 addError(NLS.bind(DataTransferMessages.DataTransfer_errorExporting, exportResource.getFullPath()), e);
             }
+            
+            if (children.length == 0) { // create an entry for empty containers, see bug 278402
+            	String destinationName = createDestinationName(leadupDepth, exportResource);
+                try {
+            		exporter.write((IContainer) exportResource, destinationName + IPath.SEPARATOR);
+                } catch (IOException e) {
+                    addError(NLS.bind(DataTransferMessages.DataTransfer_errorExporting, exportResource.getFullPath().makeRelative(), e.getMessage()), e);
+                }
+            }
 
             for (int i = 0; i < children.length; i++) {
 				exportResource(children[i], leadupDepth + 1);
diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/IFileExporter.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/IFileExporter.java
index 14ec986..f7a6472 100644
--- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/IFileExporter.java
+++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/IFileExporter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2006 IBM Corporation and others.
+ * Copyright (c) 2004, 2011 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -12,6 +12,7 @@
 
 import java.io.IOException;
 
+import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.runtime.CoreException;
 
@@ -32,6 +33,16 @@
 	public void finished() throws IOException;
 	
 	/**
+	 * Write the entry for the folder's name into the current archive.
+	 * 
+	 * @param container the container to write
+	 * @param destinationPath the path that will be used in the archive
+	 * @throws IOException if an IO error occurs while writing the folder entry
+	 */
+    public void write(IContainer container, String destinationPath)
+    	throws IOException;
+	
+	/**
 	 * Write the passed resource to the current archive
 	 * 
 	 * @param resource
diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/TarFileExporter.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/TarFileExporter.java
index 055a0e8..e063635 100644
--- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/TarFileExporter.java
+++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/TarFileExporter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -19,6 +19,7 @@
 import java.util.zip.GZIPOutputStream;
 
 import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.ResourceAttributes;
@@ -95,6 +96,23 @@
     	outputStream.closeEntry();    	
     }
 
+    public void write(IContainer container, String destinationPath)
+            throws IOException {
+        TarEntry newEntry = new TarEntry(destinationPath);
+        if(container.getLocalTimeStamp() != IResource.NULL_STAMP) {
+        	newEntry.setTime(container.getLocalTimeStamp() / 1000);
+        }
+        ResourceAttributes attributes = container.getResourceAttributes();
+        if (attributes != null && attributes.isExecutable()) {
+        	newEntry.setMode(newEntry.getMode() | 0111);
+        }
+        if (attributes != null && attributes.isReadOnly()) {
+        	newEntry.setMode(newEntry.getMode() & ~0222);
+        }
+        newEntry.setFileType(TarEntry.DIRECTORY);
+        outputStream.putNextEntry(newEntry);
+    }
+    
     /**
      *  Write the passed resource to the current archive.
      *
diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/ZipFileExporter.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/ZipFileExporter.java
index 7133d7b..7612cd6 100644
--- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/ZipFileExporter.java
+++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/ZipFileExporter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -17,6 +17,7 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 
+import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.runtime.CoreException;
 
@@ -99,6 +100,12 @@
         outputStream.closeEntry();
     }
 
+    public void write(IContainer container, String destinationPath)
+            throws IOException {
+        ZipEntry newEntry = new ZipEntry(destinationPath);
+        outputStream.putNextEntry(newEntry);
+    }
+
     /**
      *  Write the passed resource to the current archive.
      *