internal static ZipEntry AddOrUpdateDirectoryImpl(this ZipFile zipFile, string directoryName, string rootDirectoryPathInArchive, AddOrUpdateAction action, bool recurse, int level)
        {
            string fullPath = GetFullPath(directoryName);

            if (zipFile.StatusMessageTextWriter != null)
                zipFile.StatusMessageTextWriter.WriteLine("{0} {1}...",
                                                  (action == AddOrUpdateAction.AddOnly) ? "adding" : "Adding or updating",
                                                  directoryName);

            if (level == 0)
            {
                zipFile.SetAddOperationCanceled(false);
                zipFile.OnAddStarted();
            }

            // workitem 13371
            if (zipFile.IsAddOperationCanceled())
                return null;

            string dirForEntries = rootDirectoryPathInArchive;
            ZipEntry baseDir = null;

            if (level > 0)
            {
                int f = directoryName.Length;
                for (int i = level; i > 0; i--)
                    f = directoryName.LastIndexOfAny("/\\".ToCharArray(), f - 1, f - 1);

                dirForEntries = directoryName.Substring(f + 1);
                dirForEntries = Path.Combine(rootDirectoryPathInArchive, dirForEntries);
            }

            // if not top level, or if the root is non-empty, then explicitly add the directory
            if (level > 0 || rootDirectoryPathInArchive != "")
            {
                // add the directory only if it does not exist.
                // It's not an error if it already exists.
                dirForEntries = ZipEntryInternal.NameInArchive(dirForEntries) + '/';
                if (!zipFile.EntryFileNames.Contains(dirForEntries))
                {
                    baseDir = zipFile.AddDirectoryByName(dirForEntries);
                }
            }

            if (!zipFile.IsAddOperationCanceled())
            {
                IFile fileCheck = FileSystem.Current.GetFileFromPathAsync(fullPath).ExecuteSync();
                if (fileCheck != null)
                {
                    throw new IOException(string.Format("That path ({0}) is a file, not a directory!", directoryName));
                }
                IFolder folder = FileSystem.Current.GetFolderFromPathAsync(fullPath).ExecuteSync();
                if (folder == null)
                {
                    throw new FileNotFoundException(string.Format("That folder ({0}) does not exist!", directoryName));
                }
                IList<IFile> files = folder.GetFilesAsync().ExecuteSync();

                if (recurse)
                {
                    // add the files:
                    foreach (IFile file in files)
                    {
                        if (zipFile.IsAddOperationCanceled()) break;
                        if (action == AddOrUpdateAction.AddOnly)
                            zipFile.AddFile(file.Path, dirForEntries);
                        else
                            zipFile.UpdateFile(file.Path, dirForEntries);
                    }

                    if (!zipFile.IsAddOperationCanceled())
                    {
                        // add the subdirectories:
                        IList<IFolder> dirs = folder.GetFoldersAsync().ExecuteSync();
                        foreach (IFolder dir in dirs)
                        {
                                zipFile.AddOrUpdateDirectoryImpl(dir.Path, rootDirectoryPathInArchive, action, recurse, level + 1);
                        }

                    }
                }
            }

            if (level == 0)
                zipFile.OnAddCompleted();

            return baseDir;
        }
 /// <summary>
 ///   Add or update a directory in the zip archive at the specified root
 ///   directory in the archive.
 /// </summary>
 ///
 /// <remarks>
 ///   If the specified directory does not exist in the archive, then this method
 ///   is equivalent to calling <c>AddDirectory()</c>.  If the specified
 ///   directory already exists in the archive, then this method updates any
 ///   existing entries, and adds any new entries. Any entries that are in the
 ///   zip archive but not in the specified directory, are left alone.  In other
 ///   words, the contents of the zip file will be a union of the previous
 ///   contents and the new files.
 /// </remarks>
 ///
 /// <seealso cref="Ionic.Zip.ZipFile.UpdateFile(string,string)"/>
 /// <seealso cref="Ionic.Zip.ZipFile.AddDirectory(string,string)"/>
 /// <seealso cref="Ionic.Zip.ZipFile.UpdateItem(string,string)"/>
 ///
 /// <param name="directoryName">
 ///   The path to the directory to be added to the zip archive, or updated
 ///   in the zip archive.
 /// </param>
 ///
 /// <param name="directoryPathInArchive">
 ///   Specifies a directory path to use to override any path in the
 ///   <c>directoryName</c>.  This path may, or may not, correspond to a real
 ///   directory in the current filesystem.  If the files within the zip are
 ///   later extracted, this is the path used for the extracted file.  Passing
 ///   <c>null</c> (<c>Nothing</c> in VB) will use the path on the
 ///   <c>directoryName</c>, if any.  Passing the empty string ("") will insert
 ///   the item at the root path within the archive.
 /// </param>
 ///
 /// <returns>
 ///   The <c>ZipEntry</c> corresponding to the Directory that was added or updated.
 /// </returns>
 public static ZipEntry UpdateDirectory(this ZipFile zipFile, string directoryName, String directoryPathInArchive)
 {
     return zipFile.AddOrUpdateDirectoryImpl(directoryName, directoryPathInArchive, AddOrUpdateAction.AddOrUpdate);
 }
        internal static ZipEntry AddOrUpdateDirectoryImpl(this ZipFile zipFile, string directoryName, string rootDirectoryPathInArchive, AddOrUpdateAction action)
        {
            if (rootDirectoryPathInArchive == null)
            {
                rootDirectoryPathInArchive = "";
            }

            return zipFile.AddOrUpdateDirectoryImpl(directoryName, rootDirectoryPathInArchive, action, true, 0);
        }