protected override void WriteFile(HttpResponseBase response)
 {
     // By default, response is fully buffered in memory and sent once completed. On big zipped content, this would cause troubles.
     // If un-buffering response is required (<c>response.BufferOutput = false;</c>), beware, it may emit very small packets,
     // causing download time to dramatically raise. To avoid this, it would then required to use a BufferedStream with a
     // reasonnable buffer size (256kb for instance). http://stackoverflow.com/q/26010915/1178314
     // The BufferedStream should encapsulate response.OutputStream. PositionWrapperStream must then Dispose it (current
     // implementation will not), so long for this causing OutputStream to get closed (BufferedStream do not have any option for
     // telling it not to close its underlying stream, and it is sealed...).
     using (var outputStream = new PositionWrapperStream(response.OutputStream))
         using (var zip = new ZipArchive(outputStream, ZipArchiveMode.Create, true))
         {
             if (_files != null)
             {
                 var archiveDir = ZipFolder ??
                                  (_files.Length <= 1 ? string.Empty :
                                   string.IsNullOrEmpty(FileDownloadName) ? "files" : Path.ChangeExtension(FileDownloadName, null));
                 foreach (var file in _files)
                 {
                     if (file == null)
                     {
                         continue;
                     }
                     file.WriteEntry(zip, archiveDir);
                 }
             }
         }
 }
예제 #2
0
        public Task InitializeAsync(FileSystemSmugglerOptions options, FileSystemSmugglerNotifications notifications, CancellationToken cancellationToken)
        {
            // We use PositionWrapperStream due to:
            // http://connect.microsoft.com/VisualStudio/feedbackdetail/view/816411/ziparchive-shouldnt-read-the-position-of-non-seekable-streams
            positionStream = new PositionWrapperStream(stream, leaveOpen: true);
            archive        = new ZipArchive(positionStream, ZipArchiveMode.Create, leaveOpen: true);

            return(new CompletedTask());
        }
예제 #3
0
        public static long WriteDirectoryToStream(Stream stream, string pathToDirectory)
        {
            using (PositionWrapperStream wrappedStream = new PositionWrapperStream(stream))
                using (ZipArchive zip = new ZipArchive(wrappedStream, ZipArchiveMode.Create))
                {
                    // track how much we've sent (ignoring zip overhead)
                    long bytesSent = 0;

                    // use URIs to calculate relative paths, as discussed in
                    // https://stackoverflow.com/questions/9042861/how-to-make-an-absolute-path-relative-to-a-particular-folder
                    Uri relativeRoot = new Uri(pathToDirectory.Last() == '\\' ? pathToDirectory : pathToDirectory + '\\', UriKind.Absolute);

                    // get all entries in the path
                    var entries = (new DirectoryInfo(pathToDirectory)).EnumerateFileSystemInfos("*", SearchOption.AllDirectories);

                    // add entries to the zip file
                    foreach (var entry in entries)
                    {
                        string entryName = relativeRoot.MakeRelativeUri(new Uri(entry.FullName, UriKind.Absolute)).ToString();

                        // if we're handling a directory, add a blank entry
                        if (entry.Attributes.HasFlag(FileAttributes.Directory))
                        {
                            // calculate the relative path as described here:
                            zip.CreateEntry(entryName + "/");
                        }

                        // we're handling a file
                        else
                        {
                            zip.CreateEntryFromFile(entry.FullName, entryName, CompressionLevel.NoCompression);
                            bytesSent += (new FileInfo(entry.FullName)).Length;
                        }
                    }

                    // return the number of bytes sent
                    return(bytesSent);
                }
        }
예제 #4
0
        public virtual async Task <ExportFilesResult> ExportData(SmugglerExportOptions <FilesConnectionStringOptions> exportOptions)
        {
            Operations.Configure(Options);
            Operations.Initialize(Options);

            var result = new ExportFilesResult
            {
                FilePath            = exportOptions.ToFile,
                LastFileEtag        = Options.StartFilesEtag,
                LastDeletedFileEtag = Options.StartFilesDeletionEtag,
            };

            if (result.FilePath != null)
            {
                result.FilePath = Path.GetFullPath(result.FilePath);
            }

            if (Options.Incremental)
            {
                if (Directory.Exists(result.FilePath) == false)
                {
                    if (File.Exists(result.FilePath))
                    {
                        result.FilePath = Path.GetDirectoryName(result.FilePath) ?? result.FilePath;
                    }
                    else
                    {
                        Directory.CreateDirectory(result.FilePath);
                    }
                }

                if (Options.StartFilesEtag == Etag.Empty)
                {
                    ReadLastEtagsFromFile(result);
                }

                result.FilePath = Path.Combine(result.FilePath, SystemTime.UtcNow.ToString("yyyy-MM-dd-HH-mm-0", CultureInfo.InvariantCulture) + ".ravenfs-incremental-dump");
                if (File.Exists(result.FilePath))
                {
                    var counter = 1;
                    while (true)
                    {
                        result.FilePath = Path.Combine(Path.GetDirectoryName(result.FilePath), SystemTime.UtcNow.ToString("yyyy-MM-dd-HH-mm", CultureInfo.InvariantCulture) + "-" + counter + ".ravenfs-incremental-dump");

                        if (File.Exists(result.FilePath) == false)
                        {
                            break;
                        }

                        counter++;
                    }
                }
            }

            SmugglerExportException lastException = null;

            bool ownedStream = exportOptions.ToStream == null;
            var  stream      = exportOptions.ToStream ?? File.Create(result.FilePath);

            try
            {
                await DetectServerSupportedFeatures(exportOptions.From);
            }
            catch (WebException e)
            {
                throw new SmugglerExportException("Failed to query server for supported features. Reason : " + e.Message)
                      {
                          LastEtag = Etag.Empty,
                          File     = result.FilePath
                      };
            }

            try
            {
                // used to synchronize max returned values for put/delete operations
                var maxEtags = Operations.FetchCurrentMaxEtags();

                try
                {
                    // We use PositionWrapperStream due to:
                    // http://connect.microsoft.com/VisualStudio/feedbackdetail/view/816411/ziparchive-shouldnt-read-the-position-of-non-seekable-streams
                    using (var positionStream = new PositionWrapperStream(stream, leaveOpen: true))
                        using (var archive = new ZipArchive(positionStream, ZipArchiveMode.Create, leaveOpen: true))
                        {
                            await ExportFiles(archive, result.LastFileEtag, maxEtags.LastFileEtag);
                            await ExportConfigurations(archive);
                        }
                }
                catch (SmugglerExportException ex)
                {
                    result.LastFileEtag = ex.LastEtag;
                    ex.File             = result.FilePath;
                    lastException       = ex;
                }

                if (Options.Incremental)
                {
                    WriteLastEtagsToFile(result, Path.GetDirectoryName(result.FilePath));
                }

                if (lastException != null)
                {
                    throw lastException;
                }

                return(result);
            }
            finally
            {
                if (ownedStream && stream != null)
                {
                    stream.Dispose();
                }
            }
        }