Beispiel #1
0
        public static ChunkedFileHeader ReadFromMemoryMappedFile(MemoryMappedFile mmf, long maxChunks)
        {
            var header = new ChunkedFileHeader();

            using (var headerAccessor = mmf.CreateViewStream(0, GetHeaderLengthInBytes(maxChunks)))
            {
                var buffer = new byte[sizeof(int)];
                headerAccessor.Read(buffer, 0, buffer.Length);
                header.Version = BitConverter.ToInt32(buffer, 0);

                buffer = new byte[sizeof(long)];
                headerAccessor.Read(buffer, 0, buffer.Length);
                header.MaxChunks = BitConverter.ToInt64(buffer, 0);
                if (header.MaxChunks == 0)
                {
                    header.MaxChunks = maxChunks;
                }

                var chunksReceivedBytes = header.MaxChunks * sizeof(bool);
                buffer = new byte[chunksReceivedBytes];
                headerAccessor.Read(buffer, 0, buffer.Length);

                header.ChunksReceived = new bool[chunksReceivedBytes / sizeof(bool)];
                Buffer.BlockCopy(buffer, 0, header.ChunksReceived, 0, header.ChunksReceived.Length);
            }
            return(header);
        }
Beispiel #2
0
        private void WriteChunkedFile(FileSystemInfo directory, TransportFileDelivery delivery, FileTransferProperties props, bool overwrite)
        {
            var fileName = delivery.TransportFile.Name;
            var filePath = GenerateUniqueFileName(Path.Combine(directory.FullName, fileName), overwrite);

            var uniqueTransferId = props.TransferId ?? 0;
            var tmpName          = Path.ChangeExtension(filePath, $".{uniqueTransferId}.temp");

            _log.LogDebug($"Processing chunk no. {props.ChunkNumber} - is last {props.LastChunk}");

            if (filePath == null)
            {
                return;                  // only to make static code analysis happy.
            }
            try
            {
                long maxChunks;
                if (props.LastChunk)
                {
                    maxChunks = props.ChunkNumber + 1;
                }
                else
                {
                    maxChunks  = props.FileSize / props.ChunkSize;
                    maxChunks += props.FileSize % props.ChunkSize != 0 ? 1 : 0;
                }
                var headerSizeInBytes = ChunkedFileHeader.GetHeaderLengthInBytes(maxChunks);

                // Wait here to write to file
                var log = _log; // needed to make static code analysis happy (avoid using variable in and outside synchronization blocks warning)
                lock (string.Intern(tmpName))
                {
                    var tmpFileSize = headerSizeInBytes + props.FileSize;
                    CheckTempFileConsistency(tmpName, uniqueTransferId, tmpFileSize);

                    using (var fs = new FileStream(tmpName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read))
                    {
                        using (var mmf = MemoryMappedFile.CreateFromFile(fs, null, tmpFileSize, MemoryMappedFileAccess.ReadWrite, HandleInheritability.Inheritable, false))
                        {
                            var fileHeader = ChunkedFileHeader.ReadFromMemoryMappedFile(mmf, maxChunks);
                            using (var accessor = mmf.CreateViewStream(headerSizeInBytes + props.ChunkOffset, 0))
                            {
                                delivery.TransportFile.WriteTo(accessor);
                            }

                            fileHeader.ChunksReceived[props.ChunkNumber] = true;
                            fileHeader.WriteToMemoryMappedFile(mmf);

                            var isFileComplete = fileHeader.ChunksReceived.All(b => b);
                            if (!isFileComplete)
                            {
                                return;
                            }

                            try
                            {
                                if (overwrite)
                                {
                                    DeleteExistingFile(delivery, directory);
                                }

                                SaveCompletedFileContent(mmf, filePath, headerSizeInBytes, props.FileSize);
                                log.LogInformation($"File written to {filePath}");
                            }
                            catch (IOException e)
                            {
                                log.LogError($"Could not move file from {tmpName} to {filePath} because of {e.Message}");
                                throw;
                            }
                        }
                    }

                    File.Delete(tmpName);
                }

                FileReceived?.Invoke(filePath);
            }
            catch (IOException e)
            {
                _log.LogError($"Could not handle file {tmpName} -> {filePath}: '{e.Message}'");
            }
        }