// constructors
        public GridFSForwardOnlyDownloadStream(
            GridFSBucket <TFileId> bucket,
            IReadBinding binding,
            GridFSFileInfo <TFileId> fileInfo,
            bool checkMD5)
            : base(bucket, binding, fileInfo)
        {
            _checkMD5 = checkMD5;
            if (_checkMD5)
            {
                _md5 = IncrementalMD5.Create();
            }

            _lastChunkNumber = (int)((fileInfo.Length - 1) / fileInfo.ChunkSizeBytes);
            _lastChunkSize   = (int)(fileInfo.Length % fileInfo.ChunkSizeBytes);

            if (_lastChunkSize == 0)
            {
                _lastChunkSize = fileInfo.ChunkSizeBytes;
            }

            var idSerializer        = bucket.Options.SerializerRegistry.GetSerializer <TFileId>();
            var idSerializationInfo = new BsonSerializationInfo("_id", idSerializer, typeof(TFileId));

            _idAsBsonValue = idSerializationInfo.SerializeValue(fileInfo.Id);
        }
        // constructors
        public GridFSForwardOnlyUploadStream(
            GridFSBucket <TFileId> bucket,
            IWriteBinding binding,
            TFileId id,
            string filename,
            BsonDocument metadata,
            IEnumerable <string> aliases,
            string contentType,
            int chunkSizeBytes,
            int batchSize)
        {
            _bucket         = bucket;
            _binding        = binding;
            _id             = id;
            _filename       = filename;
            _metadata       = metadata;                                  // can be null
            _aliases        = aliases == null ? null : aliases.ToList(); // can be null
            _contentType    = contentType;                               // can be null
            _chunkSizeBytes = chunkSizeBytes;
            _batchSize      = batchSize;

            _batch = new List <byte[]>();
            _md5   = IncrementalMD5.Create();

            var idSerializer        = bucket.Options.SerializerRegistry.GetSerializer <TFileId>();
            var idSerializationInfo = new BsonSerializationInfo("_id", idSerializer, typeof(TFileId));

            _idAsBsonValue = idSerializationInfo.SerializeValue(id);
        }
Example #3
0
        /// <summary>
        /// Downloads a GridFS file.
        /// </summary>
        /// <param name="stream">The destination stream.</param>
        /// <param name="fileInfo">The GridFS file.</param>
        public void Download(Stream stream, MongoGridFSFileInfo fileInfo)
        {
            using (_server.RequestStart(_settings.ReadPreference))
            {
                var connectionId = _server.RequestConnectionId;

                if (_settings.VerifyMD5 && fileInfo.MD5 == null)
                {
                    throw new MongoGridFSException(connectionId, "VerifyMD5 is true and file being downloaded has no MD5 hash.");
                }

                var database         = GetDatabase();
                var chunksCollection = GetChunksCollection(database);

                string md5Client = null;
                using (var md5Algorithm = _settings.VerifyMD5 ? IncrementalMD5.Create() : null)
                {
                    var numberOfChunks = (fileInfo.Length + fileInfo.ChunkSize - 1) / fileInfo.ChunkSize;
                    for (var n = 0L; n < numberOfChunks; n++)
                    {
                        var query = Query.And(Query.EQ("files_id", fileInfo.Id), Query.EQ("n", n));
                        var chunk = chunksCollection.FindOne(query);
                        if (chunk == null)
                        {
                            string errorMessage = string.Format("Chunk {0} missing for GridFS file '{1}'.", n, fileInfo.Name);
                            throw new MongoGridFSException(connectionId, errorMessage);
                        }
                        var data = chunk["data"].AsBsonBinaryData;
                        if (data.Bytes.Length != fileInfo.ChunkSize)
                        {
                            // the last chunk only has as many bytes as needed to complete the file
                            if (n < numberOfChunks - 1 || data.Bytes.Length != fileInfo.Length % fileInfo.ChunkSize)
                            {
                                string errorMessage = string.Format("Chunk {0} for GridFS file '{1}' is the wrong size.", n, fileInfo.Name);
                                throw new MongoGridFSException(connectionId, errorMessage);
                            }
                        }
                        stream.Write(data.Bytes, 0, data.Bytes.Length);
                        if (_settings.VerifyMD5)
                        {
                            md5Algorithm.AppendData(data.Bytes, 0, data.Bytes.Length);
                        }
                    }

                    if (_settings.VerifyMD5)
                    {
                        md5Client = BsonUtils.ToHexString(md5Algorithm.GetHashAndReset());
                    }
                }

                if (_settings.VerifyMD5 && !md5Client.Equals(fileInfo.MD5, StringComparison.OrdinalIgnoreCase))
                {
                    throw new MongoGridFSException(connectionId, "Download client and server MD5 hashes are not equal.");
                }
            }
        }
Example #4
0
        /// <summary>
        /// Uploads a GridFS file.
        /// </summary>
        /// <param name="stream">The source stream.</param>
        /// <param name="remoteFileName">The remote file name.</param>
        /// <param name="createOptions">The create options.</param>
        /// <returns>The file info of the new GridFS file.</returns>
        public MongoGridFSFileInfo Upload(
            Stream stream,
            string remoteFileName,
            MongoGridFSCreateOptions createOptions)
        {
            if (_settings.ReadPreference != ReadPreference.Primary)
            {
                var gridFS = WithReadPreferencePrimary();
                return(gridFS.Upload(stream, remoteFileName, createOptions));
            }
            using (_server.RequestStart(ReadPreference.Primary))
            {
                var connectionId = _server.RequestConnectionId;
                EnsureIndexes();

                var database         = GetDatabase(ReadPreference.Primary);
                var chunksCollection = GetChunksCollection(database);
                var filesCollection  = GetFilesCollection(database);

                var files_id  = createOptions.Id ?? ObjectId.GenerateNewId();
                var chunkSize = (createOptions.ChunkSize == 0) ? _settings.ChunkSize : createOptions.ChunkSize;
                var buffer    = new byte[chunkSize];

                var    length    = 0L;
                string md5Client = null;
                using (var md5Algorithm = _settings.VerifyMD5 ? IncrementalMD5.Create() : null)
                {
                    for (var n = 0L; true; n++)
                    {
                        // might have to call Stream.Read several times to get a whole chunk
                        var bytesNeeded = chunkSize;
                        var bytesRead   = 0;
                        while (bytesNeeded > 0)
                        {
                            var partialRead = stream.Read(buffer, bytesRead, bytesNeeded);
                            if (partialRead == 0)
                            {
                                break; // EOF may or may not have a partial chunk
                            }
                            bytesNeeded -= partialRead;
                            bytesRead   += partialRead;
                        }
                        if (bytesRead == 0)
                        {
                            break; // EOF no partial chunk
                        }
                        length += bytesRead;

                        byte[] data = buffer;
                        if (bytesRead < chunkSize)
                        {
                            data = new byte[bytesRead];
                            Buffer.BlockCopy(buffer, 0, data, 0, bytesRead);
                        }

                        var chunk = new BsonDocument
                        {
                            { "_id", ObjectId.GenerateNewId() },
                            { "files_id", files_id },
                            { "n", n < int.MaxValue ? (BsonValue)(BsonInt32)(int)n : (BsonInt64)n },
                            { "data", new BsonBinaryData(data) }
                        };
                        chunksCollection.Insert(chunk, _settings.WriteConcern);

                        if (_settings.VerifyMD5)
                        {
                            md5Algorithm.AppendData(data, 0, data.Length);
                        }

                        if (bytesRead < chunkSize)
                        {
                            break; // EOF after partial chunk
                        }
                    }

                    if (_settings.VerifyMD5)
                    {
                        md5Client = BsonUtils.ToHexString(md5Algorithm.GetHashAndReset());
                    }
                }

                string md5Server = null;
                if (_settings.UpdateMD5 || _settings.VerifyMD5)
                {
                    var md5Command = new CommandDocument
                    {
                        { "filemd5", files_id },
                        { "root", _settings.Root }
                    };
                    var md5Result = database.RunCommand(md5Command);
                    md5Server = md5Result.Response["md5"].AsString;
                }

                if (_settings.VerifyMD5 && !md5Client.Equals(md5Server, StringComparison.OrdinalIgnoreCase))
                {
                    throw new MongoGridFSException(connectionId, "Upload client and server MD5 hashes are not equal.");
                }

                var          uploadDate = (createOptions.UploadDate == DateTime.MinValue) ? DateTime.UtcNow : createOptions.UploadDate;
                var          aliases    = (createOptions.Aliases != null) ? new BsonArray(createOptions.Aliases) : null;
                BsonDocument fileInfo   = new BsonDocument
                {
                    { "_id", files_id },
                    { "filename", remoteFileName, !string.IsNullOrEmpty(remoteFileName) }, // optional
                    { "length", length },
                    { "chunkSize", chunkSize },
                    { "uploadDate", uploadDate },
                    { "md5", (md5Server == null) ? (BsonValue)BsonNull.Value : new BsonString(md5Server) },
                    { "contentType", createOptions.ContentType, !string.IsNullOrEmpty(createOptions.ContentType) }, // optional
                    { "aliases", aliases, aliases != null },                                                        // optional
                    { "metadata", createOptions.Metadata, createOptions.Metadata != null } // optional
                };
                filesCollection.Insert(fileInfo, _settings.WriteConcern);

                return(FindOneById(files_id));
            }
        }