private static BlobStorageContext GetBlobStorageContextPrivate(SqlDataReader reader, int fileId, int versionId, int propertyTypeId)
        {
            // this is a helper method to aid both the sync and
            // async version of the GetBlobContext operation

            var length       = reader.GetSafeInt64(0);
            var providerName = reader.GetSafeString(1);
            var providerData = reader.GetSafeString(2);

            var            useFileStream = false;
            FileStreamData fsData        = null;

            if (BlobStorage.FileStreamEnabled)
            {
                fsData = new FileStreamData
                {
                    Path = reader.GetSafeString(3),
                    TransactionContext = reader.GetSqlBytes(4).Buffer
                };
                useFileStream = fsData.Path != null;
            }

            var provider = BlobStorageBase.GetProvider(providerName);

            return(new BlobStorageContext(provider, providerData)
            {
                VersionId = versionId,
                PropertyTypeId = propertyTypeId,
                FileId = fileId,
                Length = length,
                UseFileStream = useFileStream,
                BlobProviderData = provider == BlobStorageBase.BuiltInProvider
                    ? new BuiltinBlobProviderData {
                    FileStreamData = fsData
                }
                    : provider.ParseData(providerData)
            });
        }
示例#2
0
 protected internal override BinaryCacheEntity LoadBinaryCacheEntity(int nodeVersionId, int propertyTypeId, out FileStreamData fileStreamData)
 {
     WriteLog(MethodInfo.GetCurrentMethod(), nodeVersionId, propertyTypeId);
     return(base.LoadBinaryCacheEntity(nodeVersionId, propertyTypeId, out fileStreamData));
 }
示例#3
0
        internal static void AddStream(BlobStorageContext context, Stream stream)
        {
            FileStreamData fileStreamData = null;
            var            providerData   = context.BlobProviderData as BuiltinBlobProviderData;

            if (providerData != null)
            {
                fileStreamData = providerData.FileStreamData;
            }

            SqlProcedure cmd = null;

            try
            {
                // if possible, write the stream using the special Filestream technology
                if (BlobStorageBase.UseFileStream(stream.Length))
                {
                    WriteSqlFileStream(stream, context.FileId, fileStreamData);
                    return;
                }

                // We have to work with an integer since SQL does not support
                // binary values bigger than [Int32.MaxValue].
                var streamSize = Convert.ToInt32(stream.Length);

                cmd = new SqlProcedure {
                    CommandText = "proc_BinaryProperty_WriteStream"
                };
                cmd.Parameters.Add("@Id", SqlDbType.Int).Value = context.FileId;

                var offsetParameter = cmd.Parameters.Add("@Offset", SqlDbType.Int);
                var valueParameter  = cmd.Parameters.Add("@Value", SqlDbType.VarBinary, streamSize);

                if (BlobStorage.FileStreamEnabled)
                {
                    var useFileStreamParameter = cmd.Parameters.Add("@UseFileStream", SqlDbType.TinyInt);
                    useFileStreamParameter.Value = false;
                }

                var    offset = 0;
                byte[] buffer = null;
                stream.Seek(0, SeekOrigin.Begin);

                // The 'while' loop is misleading here, because we write the whole
                // stream at once. Bigger files should go to the Filestream
                // column anyway.
                while (offset < streamSize)
                {
                    // Buffer size may be less at the end os the stream than the limit
                    var bufferSize = streamSize - offset;

                    if (buffer == null || buffer.Length != bufferSize)
                    {
                        buffer = new byte[bufferSize];
                    }

                    // Read bytes from the source
                    stream.Read(buffer, 0, bufferSize);

                    offsetParameter.Value = offset;
                    valueParameter.Value  = buffer;

                    // Write full stream
                    cmd.ExecuteNonQuery();

                    offset += bufferSize;
                }
            }
            finally
            {
                cmd?.Dispose();
            }
        }
示例#4
0
        private static void WriteBinaryStream(Stream stream, int binaryPropertyId, FileStreamData fileStreamData = null)
        {
            SqlProcedure cmd = null;

            try
            {
                var longStreamSize = stream.Length;
                var useFileStream  = RepositoryConfiguration.FileStreamEnabled &&
                                     longStreamSize > RepositoryConfiguration.MinimumSizeForFileStreamInBytes;

                //If possible, write the stream using the special Filestream technology
                if (useFileStream)
                {
                    WriteSqlFileStream(stream, binaryPropertyId, fileStreamData);
                    return;
                }

                //We have to work with an integer since SQL does not support
                //binary values bigger than [Int32.MaxValue].
                var streamSize = Convert.ToInt32(stream.Length);

                cmd = new SqlProcedure {
                    CommandText = "proc_BinaryProperty_WriteStream"
                };
                cmd.Parameters.Add("@Id", SqlDbType.Int).Value = binaryPropertyId;

                var offsetParameter = cmd.Parameters.Add("@Offset", SqlDbType.Int);
                var valueParameter  = cmd.Parameters.Add("@Value", SqlDbType.VarBinary, streamSize);

                if (RepositoryConfiguration.FileStreamEnabled)
                {
                    var useFileStreamParameter = cmd.Parameters.Add("@UseFileStream", SqlDbType.TinyInt);
                    useFileStreamParameter.Value = useFileStream;
                }

                int    offset = 0;
                byte[] buffer = null;
                stream.Seek(0, SeekOrigin.Begin);

                //The 'while' loop is misleading here, because we write the whole
                //stream at once. Bigger files should go to the Filestream
                //column anyway.
                while (offset < streamSize)
                {
                    // Buffer size may be less at the end os the stream than the limit
                    int bufferSize = streamSize - offset;

                    if (buffer == null || buffer.Length != bufferSize)
                    {
                        buffer = new byte[bufferSize];
                    }

                    // Read bytes from the source
                    stream.Read(buffer, 0, bufferSize);

                    offsetParameter.Value = offset;
                    valueParameter.Value  = buffer;

                    // Write full stream
                    cmd.ExecuteNonQuery();

                    offset += bufferSize;
                }
            }
            finally
            {
                if (cmd != null)
                {
                    cmd.Dispose();
                }
            }
        }
示例#5
0
        public void UpdateBinaryProperty(int binaryDataId, BinaryDataValue value)
        {
            if (!RepositoryConfiguration.FileStreamEnabled)
            {
                // MS-SQL does not support stream size over [Int32.MaxValue],
                // but check only if Filestream is not enabled
                if (value.Stream != null && value.Stream.Length > Int32.MaxValue)
                {
                    throw new NotSupportedException();
                }
            }

            var            isRepositoryStream = value.Stream is RepositoryStream || value.Stream is SenseNetSqlFileStream;
            FileStreamData fileStreamData     = null;

            SqlProcedure cmd = null;

            try
            {
                cmd = new SqlProcedure {
                    CommandText = "proc_BinaryProperty_Update"
                };
                cmd.Parameters.Add("@BinaryPropertyId", SqlDbType.Int).Value      = binaryDataId;
                cmd.Parameters.Add("@ContentType", SqlDbType.NVarChar, 450).Value = value.ContentType;
                cmd.Parameters.Add("@FileNameWithoutExtension", SqlDbType.NVarChar, 450).Value = value.FileName.FileNameWithoutExtension == null ? (object)DBNull.Value : (object)value.FileName.FileNameWithoutExtension;
                cmd.Parameters.Add("@Extension", SqlDbType.NVarChar, 50).Value = ValidateExtension(value.FileName.Extension);
                cmd.Parameters.Add("@Size", SqlDbType.BigInt).Value            = value.Size;

                // Do not update the stream field in the database if it is not loaded (other change happened)
                cmd.Parameters.Add("@IsStreamModified", SqlDbType.TinyInt).Value = isRepositoryStream ? 0 : 1;
                cmd.Parameters.Add("@Checksum", SqlDbType.VarChar, 200).Value    = (value.Checksum != null) ? (object)value.Checksum : DBNull.Value;

                if (RepositoryConfiguration.FileStreamEnabled)
                {
                    string path;
                    byte[] transactionContext;

                    //Update row and retrieve file path and
                    //transaction context for the Filestream column
                    using (var reader = cmd.ExecuteReader())
                    {
                        reader.Read();

                        path = reader.GetString(0);
                        transactionContext = reader.GetSqlBytes(1).Buffer;
                    }

                    if (!string.IsNullOrEmpty(path))
                    {
                        fileStreamData = new FileStreamData {
                            Path = path, TransactionContext = transactionContext
                        }
                    }
                    ;
                }
                else
                {
                    cmd.ExecuteNonQuery();
                }
            }
            finally
            {
                if (cmd != null)
                {
                    cmd.Dispose();
                }
            }

            if (!isRepositoryStream && value.Stream != null && value.Stream.Length > 0)
            {
                // Stream exists and is loaded -> write it
                WriteBinaryStream(value.Stream, binaryDataId, fileStreamData);
            }
        }
示例#6
0
        public async Task <ActionResult <IEnumerable <UFileReturnDto> > > UploadFiles([FromForm] UFilesReceiveDto filesReceiveDto)
        {
            if (filesReceiveDto.Files == null || filesReceiveDto.Files.Count == 0)
            {
                return(BadRequest("No files found"));
            }

            if (filesReceiveDto.Files.Count > _uploadSettings.Value.MaxFiles)
            {
                return(BadRequest($"Too many files. Max files is {_uploadSettings.Value.MaxFiles.ToString()}"));
            }

            // Serialize the info tab
            var infoList = filesReceiveDto.Infos == null ? null :
                           JsonSerializer.Deserialize <List <MultiFileInfoDto> >(filesReceiveDto.Infos, new JsonSerializerOptions()
            {
                PropertyNameCaseInsensitive = true
            });

            if (infoList != null && infoList.Count != 0 && infoList.Count != filesReceiveDto.Files.Count)
            {
                return(BadRequest("Either leave infos empty or add the same amount of info entries as files!"));
            }

            // before we do any computation or allocation
            foreach (var file in filesReceiveDto.Files)
            {
                if (file.Length > _uploadSettings.Value.MaxSize)
                {
                    return(BadRequest(
                               $"File too big. Maximum file size allowed is {_uploadSettings.Value.MaxSize.ToString()} bytes"));
                }
                string extension = Path.GetExtension(file.FileName);
                if (_uploadSettings.Value.BlockedExtensions.Any(
                        e => e.Equals(extension, StringComparison.OrdinalIgnoreCase)))
                {
                    return(BadRequest($"File extension {extension} is not allowed"));
                }
            }

            Album album = null;

            // check if specified album exists
            if (filesReceiveDto.AlbumId.HasValue)
            {
                album = await _albumRepo.GetAlbumById(filesReceiveDto.AlbumId.Value);

                if (album == null)
                {
                    return(BadRequest("Album doesn't exist."));
                }
            }

            int userId = int.Parse(User.FindFirst(ClaimTypes.NameIdentifier).Value);

            // Check if user exceeded upload limit
            if (_limitSettings.Value.MaxFiles != 0 && await _fileRepo.GetFileCount(userId) >= _limitSettings.Value.MaxFiles)
            {
                return(BadRequest($"You have reached the maximum file limit of {_limitSettings.Value.MaxFiles.ToString()}"));
            }

            var userFromRepo = await _userRepo.GetUserById(userId);

            List <FileStreamData> fileStreams = new List <FileStreamData>(filesReceiveDto.Files.Count);
            List <UFile>          dbFiles     = new List <UFile>(filesReceiveDto.Files.Count);

            try
            {
                int index = 0;
                foreach (var file in filesReceiveDto.Files)
                {
                    string extension = Path.GetExtension(file.FileName);

                    string fileId   = Guid.NewGuid().ToString();
                    string path     = _utilsService.GenerateFilePath(fileId, extension);
                    var    fileData = new FileStreamData()
                    {
                        Path       = path,
                        CopyTask   = null,
                        FileStream = new FileStream(path, FileMode.Create)
                    };
                    // begin entire file download and saving
                    fileData.CopyTask = file.CopyToAsync(fileData.FileStream);
                    fileStreams.Add(fileData);
                    // create files for database
                    bool   isPublic = true;
                    string filename = Path.GetFileNameWithoutExtension(file.FileName);
                    string name     = filename;
                    if (infoList != null && infoList.Count != 0)
                    {
                        isPublic = infoList[index].IsPublic;
                        name     = infoList[index].Name ?? filename;
                    }

                    if (string.IsNullOrWhiteSpace(name))
                    {
                        name = fileId;
                    }

                    var uFile = new UFile(fileId, isPublic, extension, file.ContentType,
                                          userFromRepo.Id, name);
                    if (album != null)
                    {
                        uFile.AlbumId = album.Id;
                    }
                    dbFiles.Add(uFile);

                    index++;
                }

                // now await the files one after another
                foreach (var file in fileStreams)
                {
                    await file.CopyTask;
                }

                // now we know all files successfully downloaded and saved
                // add to the DB
                foreach (var dbFile in dbFiles)
                {
                    _fileRepo.Add(dbFile);
                }

                if (!await _fileRepo.SaveAll())
                {
                    await UndoChanges();

                    return(BadRequest("Failed saving the files"));
                }

                var filesToReturn = _mapper.Map <IEnumerable <UFileReturnDto> >(dbFiles);
                return(Ok(filesToReturn));
            }
            catch (Exception e)
            {
                await UndoChanges();

                _logger.Log(LogLevel.Error, e, "Failed to save Files!");
                return(BadRequest("Something failed sorry :("));
            }
            finally
            {
                foreach (var data in fileStreams)
                {
                    await data.FileStream.DisposeAsync();

                    data.CopyTask.Dispose();
                }
            }

            async Task UndoChanges()
            {
                for (int i = 0; i < fileStreams.Count; i++)
                {
                    var file   = fileStreams[i];
                    var dbFile = dbFiles[i];

                    // wait in case its not finished yet
                    await file.CopyTask;
                    await file.FileStream.DisposeAsync();

                    file.CopyTask.Dispose();
                    // remove photo if it exists
                    if (System.IO.File.Exists(file.Path))
                    {
                        System.IO.File.Delete(file.Path);
                    }
                    // remove Db entries
                    var fileFromDb = await _fileRepo.GetFile(dbFile.PublicId);

                    if (fileFromDb != null)
                    {
                        _fileRepo.Delete(fileFromDb);
                    }
                }

                await _fileRepo.SaveAll();
            }
        }
示例#7
0
        internal static Stream GetBinaryStream2(int nodeId, int versionId, int propertyTypeId)
        {
            FileStreamData fileStreamData = null;

            if (TransactionScope.IsActive)
            {
                // Aktív tranzakció hekk
                var bce = DataProvider.Current.LoadBinaryCacheEntity(versionId, propertyTypeId, out fileStreamData);

                //If we received the necessary information for serving file stream, use that. If filestream data
                //is null, we MUST NOT use SqlFileStream here, because the data is in the database.
                if (bce.UseFileStream && fileStreamData != null)
                {
                    return(new ContentRepository.Storage.Data.SqlFileStream(bce.Length, bce.BinaryPropertyId, fileStreamData));
                }

                return(bce.RawData == null
                    ? new RepositoryStream(bce.Length, bce.BinaryPropertyId)
                    : new RepositoryStream(bce.BinaryPropertyId, bce.Length, bce.RawData));
            }

            // Try to load cached binary entity
            var cacheKey          = BinaryCacheEntity.GetCacheKey(versionId, propertyTypeId);
            var binaryCacheEntity = (BinaryCacheEntity)DistributedApplication.Cache.Get(cacheKey);

            if (binaryCacheEntity == null)
            {
                //Not in cache, load it from the database
                binaryCacheEntity = DataProvider.Current.LoadBinaryCacheEntity(versionId, propertyTypeId, out fileStreamData);

                //insert the binary cache entity into the
                //cache only if we know the node id
                if (binaryCacheEntity != null && nodeId != 0)
                {
                    if (!RepositoryConfiguration.WorkingMode.Populating)
                    {
                        DistributedApplication.Cache.Insert(cacheKey, binaryCacheEntity, new NodeIdDependency(nodeId));
                    }
                }
            }

            //Not found even in the database
            if (binaryCacheEntity == null)
            {
                return(null);
            }
            if (binaryCacheEntity.Length == -1)
            {
                return(null);
            }

            //We can use SqlFilestream to load the binary from the filesystem.
            //Transaction is handled inside the SqlFileStream.
            if (binaryCacheEntity.UseFileStream)
            {
                return(new ContentRepository.Storage.Data.SqlFileStream(binaryCacheEntity.Length, binaryCacheEntity.BinaryPropertyId));
            }

            var stream = binaryCacheEntity.RawData == null
               ? new RepositoryStream(binaryCacheEntity.Length, binaryCacheEntity.BinaryPropertyId)
               : new RepositoryStream(binaryCacheEntity.BinaryPropertyId, binaryCacheEntity.Length, binaryCacheEntity.RawData);

            return(stream);
        }
        /// <summary>
        /// Loads a cache item into memory that either contains the raw binary (if its size fits into the limit) or
        /// just the blob metadata pointing to the blob storage.
        /// </summary>
        /// <param name="versionId">Content version id.</param>
        /// <param name="propertyTypeId">Binary property type id.</param>
        public BinaryCacheEntity LoadBinaryCacheEntity(int versionId, int propertyTypeId)
        {
            var columnDefinitions = BlobStorage.FileStreamEnabled
                ? string.Format(LoadBinaryCacheentityColumnsFormatFilestreamScript, BlobStorage.BinaryCacheSize)
                : string.Format(LoadBinaryCacheentityColumnsFormatScript, BlobStorage.BinaryCacheSize);

            var commandText = string.Format(LoadBinaryCacheentityFormatScript, columnDefinitions);

            using (var cmd = new SqlProcedure {
                CommandText = commandText
            })
            {
                cmd.Parameters.Add("@VersionId", SqlDbType.Int).Value      = versionId;
                cmd.Parameters.Add("@PropertyTypeId", SqlDbType.Int).Value = propertyTypeId;
                cmd.CommandType = CommandType.Text;

                using (var reader = cmd.ExecuteReader(CommandBehavior.SingleRow | CommandBehavior.SingleResult))
                {
                    if (!reader.HasRows || !reader.Read())
                    {
                        return(null);
                    }

                    var length           = reader.GetInt64(0);
                    var binaryPropertyId = reader.GetInt32(1);
                    var fileId           = reader.GetInt32(2);

                    var providerName     = reader.GetSafeString(3);
                    var providerTextData = reader.GetSafeString(4);

                    byte[] rawData;
                    if (reader.IsDBNull(5))
                    {
                        rawData = null;
                    }
                    else
                    {
                        rawData = (byte[])reader.GetValue(5);
                    }

                    var useFileStream = false;

                    FileStreamData fileStreamData = null;
                    if (BlobStorage.FileStreamEnabled)
                    {
                        useFileStream = reader.GetInt32(6) == 1;

                        if (useFileStream)
                        {
                            // fill Filestream info if we really need it
                            fileStreamData = new FileStreamData
                            {
                                Path = reader.GetSafeString(7),
                                TransactionContext = reader.GetSqlBytes(8).Buffer
                            };
                        }
                    }

                    var provider = BlobStorageBase.GetProvider(providerName);
                    var context  = new BlobStorageContext(provider, providerTextData)
                    {
                        VersionId = versionId, PropertyTypeId = propertyTypeId, FileId = fileId, Length = length, UseFileStream = useFileStream
                    };
                    if (provider == BlobStorageBase.BuiltInProvider)
                    {
                        context.BlobProviderData = new BuiltinBlobProviderData {
                            FileStreamData = fileStreamData
                        }
                    }
                    ;

                    return(new BinaryCacheEntity
                    {
                        Length = length,
                        RawData = rawData,
                        BinaryPropertyId = binaryPropertyId,
                        FileId = fileId,
                        Context = context
                    });
                }
            }
        }
        /// <summary>
        /// Updates an existing binary property value in the database and the blob storage.
        /// </summary>
        /// <param name="blobProvider">Blob storage provider.</param>
        /// <param name="value">Binary data to update.</param>
        public void UpdateBinaryProperty(IBlobProvider blobProvider, BinaryDataValue value)
        {
            var streamLength = value.Stream?.Length ?? 0;

            if (blobProvider != BlobStorageBase.BuiltInProvider && streamLength > 0)
            {
                var ctx = new BlobStorageContext(blobProvider, value.BlobProviderData)
                {
                    VersionId      = 0,
                    PropertyTypeId = 0,
                    FileId         = value.FileId,
                    Length         = streamLength,
                    UseFileStream  = false
                };

                blobProvider.Allocate(ctx);
                using (var stream = blobProvider.GetStreamForWrite(ctx))
                    value.Stream?.CopyTo(stream);

                value.BlobProviderName = ctx.Provider.GetType().FullName;
                value.BlobProviderData = BlobStorageContext.SerializeBlobProviderData(ctx.BlobProviderData);
            }
            else
            {
                value.BlobProviderName = null;
                value.BlobProviderData = null;
            }

            if (blobProvider == BlobStorageBase.BuiltInProvider && !BlobStorage.FileStreamEnabled)
            {
                // MS-SQL does not support stream size over [Int32.MaxValue],
                // but check only if Filestream is not enabled
                if (streamLength > int.MaxValue)
                {
                    throw new NotSupportedException();
                }
            }

            var isRepositoryStream = value.Stream is RepositoryStream || value.Stream is SenseNetSqlFileStream;
            var hasStream          = isRepositoryStream || value.Stream is MemoryStream;

            if (!hasStream)
            {
                // do not do any database operation if the stream is not modified
                return;
            }

            FileStreamData fileStreamData = null;
            SqlProcedure   cmd            = null;

            try
            {
                string      sql;
                CommandType commandType;
                if (blobProvider == BlobStorageBase.BuiltInProvider)
                {
                    commandType = CommandType.StoredProcedure;
                    sql         = "proc_BinaryProperty_Update";
                }
                else
                {
                    commandType = CommandType.Text;
                    sql         = BlobStorage.FileStreamEnabled
                        ? UpdateBinarypropertyNewFilerowFilestreamScript
                        : UpdateBinarypropertyNewFilerowScript;
                }

                cmd = new SqlProcedure {
                    CommandText = sql, CommandType = commandType
                };
                cmd.Parameters.Add("@BinaryPropertyId", SqlDbType.Int).Value      = value.Id;
                cmd.Parameters.Add("@ContentType", SqlDbType.NVarChar, 450).Value = value.ContentType;
                cmd.Parameters.Add("@FileNameWithoutExtension", SqlDbType.NVarChar, 450).Value = value.FileName.FileNameWithoutExtension == null ? DBNull.Value : (object)value.FileName.FileNameWithoutExtension;
                cmd.Parameters.Add("@Extension", SqlDbType.NVarChar, 50).Value     = ValidateExtension(value.FileName.Extension);
                cmd.Parameters.Add("@Size", SqlDbType.BigInt).Value                = value.Size;
                cmd.Parameters.Add("@Checksum", SqlDbType.VarChar, 200).Value      = value.Checksum != null ? (object)value.Checksum : DBNull.Value;
                cmd.Parameters.Add("@BlobProvider", SqlDbType.NVarChar, 450).Value = value.BlobProviderName != null ? (object)value.BlobProviderName : DBNull.Value;
                cmd.Parameters.Add("@BlobProviderData", SqlDbType.NVarChar, int.MaxValue).Value = value.BlobProviderData != null ? (object)value.BlobProviderData : DBNull.Value;

                int fileId;
                if (BlobStorage.FileStreamEnabled)
                {
                    string path;
                    byte[] transactionContext;

                    // Update row and retrieve file path and
                    // transaction context for the Filestream column
                    using (var reader = cmd.ExecuteReader())
                    {
                        reader.Read();

                        fileId             = reader.GetInt32(0);
                        path               = reader.GetSafeString(1);
                        transactionContext = reader.IsDBNull(2) ? null : reader.GetSqlBytes(2).Buffer;
                    }

                    if (!string.IsNullOrEmpty(path))
                    {
                        fileStreamData = new FileStreamData {
                            Path = path, TransactionContext = transactionContext
                        }
                    }
                    ;
                }
                else
                {
                    fileId = (int)cmd.ExecuteScalar();
                }
                if (fileId > 0 && fileId != value.FileId)
                {
                    value.FileId = fileId;
                }
            }
            finally
            {
                cmd?.Dispose();
            }

            // ReSharper disable once InvertIf
            if (blobProvider == BlobStorageBase.BuiltInProvider && !isRepositoryStream && streamLength > 0)
            {
                // Stream exists and is loaded -> write it
                var ctx = new BlobStorageContext(blobProvider, value.BlobProviderData)
                {
                    VersionId        = 0,
                    PropertyTypeId   = 0,
                    FileId           = value.FileId,
                    Length           = streamLength,
                    UseFileStream    = fileStreamData != null,
                    BlobProviderData = new BuiltinBlobProviderData {
                        FileStreamData = fileStreamData
                    }
                };

                BuiltInBlobProvider.UpdateStream(ctx, value.Stream);
            }
        }
        /// <summary>
        /// Inserts a new binary property value into the metadata database and the blob storage,
        /// removing the previous one if the content is not new.
        /// </summary>
        /// <param name="blobProvider">Blob storage provider.</param>
        /// <param name="value">Binary data to insert.</param>
        /// <param name="versionId">Content version id.</param>
        /// <param name="propertyTypeId">Binary property type id.</param>
        /// <param name="isNewNode">Whether this value belongs to a new or an existing node.</param>
        public void InsertBinaryProperty(IBlobProvider blobProvider, BinaryDataValue value, int versionId, int propertyTypeId, bool isNewNode)
        {
            var streamLength  = value.Stream?.Length ?? 0;
            var useFileStream = BlobStorage.FileStreamEnabled &&
                                streamLength > Convert.ToInt64(BlobStorage.MinimumSizeForFileStreamInBytes);
            var ctx = new BlobStorageContext(blobProvider)
            {
                VersionId = versionId, PropertyTypeId = propertyTypeId, FileId = 0, Length = streamLength, UseFileStream = useFileStream
            };

            // In case of an external provider allocate the place for bytes and
            // write the stream beforehand and get the generated provider data.
            // Note that the external provider does not need an existing record
            // in the Files table to work, it just stores the bytes.
            if (blobProvider != BlobStorageBase.BuiltInProvider && streamLength > 0)
            {
                blobProvider.Allocate(ctx);

                using (var stream = blobProvider.GetStreamForWrite(ctx))
                    value.Stream?.CopyTo(stream);

                value.BlobProviderName = ctx.Provider.GetType().FullName;
                value.BlobProviderData = BlobStorageContext.SerializeBlobProviderData(ctx.BlobProviderData);
            }

            SqlProcedure   cmd            = null;
            FileStreamData fileStreamData = null;

            try
            {
                cmd = useFileStream
                    ? new SqlProcedure {
                    CommandText = isNewNode ? InsertBinaryPropertyFilestreamScript : DeleteAndInsertBinaryPropertyFilestream, CommandType = CommandType.Text
                }
                    : new SqlProcedure {
                    CommandText = isNewNode ? InsertBinaryPropertyScript : DeleteAndInsertBinaryProperty, CommandType = CommandType.Text
                };

                cmd.Parameters.Add("@VersionId", SqlDbType.Int).Value             = versionId != 0 ? (object)versionId : DBNull.Value;
                cmd.Parameters.Add("@PropertyTypeId", SqlDbType.Int).Value        = propertyTypeId != 0 ? (object)propertyTypeId : DBNull.Value;
                cmd.Parameters.Add("@ContentType", SqlDbType.NVarChar, 450).Value = value.ContentType;
                cmd.Parameters.Add("@FileNameWithoutExtension", SqlDbType.NVarChar, 450).Value = value.FileName.FileNameWithoutExtension == null ? DBNull.Value : (object)value.FileName.FileNameWithoutExtension;
                cmd.Parameters.Add("@Extension", SqlDbType.NVarChar, 50).Value     = ValidateExtension(value.FileName.Extension);
                cmd.Parameters.Add("@Size", SqlDbType.BigInt).Value                = Math.Max(0, value.Size);
                cmd.Parameters.Add("@BlobProvider", SqlDbType.NVarChar, 450).Value = value.BlobProviderName != null ? (object)value.BlobProviderName : DBNull.Value;
                cmd.Parameters.Add("@BlobProviderData", SqlDbType.NVarChar, int.MaxValue).Value = value.BlobProviderData != null ? (object)value.BlobProviderData : DBNull.Value;
                cmd.Parameters.Add("@Checksum", SqlDbType.VarChar, 200).Value = value.Checksum != null ? (object)value.Checksum : DBNull.Value;

                // insert binary and file rows and retrieve file path and transaction context for the Filestream column
                using (var reader = cmd.ExecuteReader())
                {
                    reader.Read();

                    value.Id        = Convert.ToInt32(reader[0]);
                    value.FileId    = Convert.ToInt32(reader[1]);
                    value.Timestamp = Utility.Convert.BytesToLong((byte[])reader.GetValue(2));
                    if (useFileStream)
                    {
                        fileStreamData = new FileStreamData
                        {
                            Path = reader.GetString(3),
                            TransactionContext = reader.GetSqlBytes(4).Buffer
                        };
                    }
                }
            }
            finally
            {
                cmd.Dispose();
            }

            // The BuiltIn blob provider saves the stream after the record
            // was saved into the Files table, because simple varbinary
            // and sql filestream columns must exist before we can write a
            // stream into the record.
            // ReSharper disable once InvertIf
            if (blobProvider == BlobStorageBase.BuiltInProvider && value.Stream != null && value.Stream.Length > 0)
            {
                ctx.FileId           = value.FileId;
                ctx.BlobProviderData = new BuiltinBlobProviderData {
                    FileStreamData = fileStreamData
                };

                BuiltInBlobProvider.AddStream(ctx, value.Stream);
            }
        }
示例#11
0
        public async Task <object> UploadFile(IFormFile file, FileTypeEnum fileType, string domainId, string folderId)
        {
            try
            {
                var    isImageFile = _pictureService.IsImageFile(file);
                byte[] fileBinary;
                using (var ms = new MemoryStream())
                {
                    await file.CopyToAsync(ms);

                    fileBinary = ms.ToArray();
                }

                var    originalName    = file.FileName;
                var    fileEx          = !string.IsNullOrEmpty(Path.GetExtension(file.FileName).ToLower()) ? Path.GetExtension(file.FileName).ToLower() : "." + _pictureService.GetImageFormat(fileBinary).ToString();
                var    uniqueId        = UniqueIDHelper.GenarateRandomString(12, false);
                var    uniqueCode      = Guid.NewGuid();
                var    fileName        = $"{uniqueCode.ToString().Replace("-", "")}{fileEx}";
                var    seoName         = _webHelper.GetSeName(file.FileName, true, false);
                var    isPortraitImage = false;
                var    pathRoot        = _aqFileProvider.GetAbsolutePath(@"contents\");
                var    fullPath        = string.Empty;
                var    pathSubRoot     = string.Empty;
                var    pathThumb12     = string.Empty;
                var    pathThumb14     = string.Empty;
                var    pathThumb16     = string.Empty;
                var    pathThumb18     = string.Empty;
                byte[] fileThumb12;
                byte[] fileThumb14;
                byte[] fileThumb16;
                byte[] fileThumb18;

                if (!_aqFileProvider.DirectoryExists(pathRoot))
                {
                    _aqFileProvider.CreateDirectory(pathRoot);
                }

                if (isImageFile)
                {
                    pathSubRoot = Path.Combine(pathRoot, $@"images\");
                }
                else
                {
                    pathSubRoot = Path.Combine(pathRoot, $@"docs\");
                }

                if (!_aqFileProvider.DirectoryExists(pathSubRoot))
                {
                    _aqFileProvider.CreateDirectory(pathSubRoot);
                }

                domainId = !string.IsNullOrEmpty(domainId.ToLower()) ? domainId.ToLower() : "others";
                var pathDomain = Path.Combine(pathSubRoot, $@"{domainId}\");
                if (!_aqFileProvider.DirectoryExists(pathDomain))
                {
                    _aqFileProvider.CreateDirectory(pathDomain);
                }

                folderId = !string.IsNullOrEmpty(folderId.ToLower()) ? folderId.ToLower() : "others";
                var saveFilePath = Path.Combine(pathDomain, $@"{folderId}\");
                if (!_aqFileProvider.DirectoryExists(saveFilePath))
                {
                    _aqFileProvider.CreateDirectory(saveFilePath);
                }

                fullPath = Path.Combine(saveFilePath, $"{fileName}");

                if (isImageFile)
                {
                    int quality = 100;
                    //in MB
                    double fileSize = Convert.ToDouble(fileBinary.Length.ToString()) / 1024 / 1024;
                    if (fileSize >= 4)
                    {
                        quality = 45;
                    }
                    else if (fileSize >= 2 && fileSize < 4)
                    {
                        quality = 65;
                    }
                    else if (fileSize > 0.5 && fileSize < 2)
                    {
                        quality = 85;
                    }

                    fileBinary = _pictureService.ValidatePicture(fileBinary, 2048, quality);

                    fileThumb12 = _pictureService.ResizePicture(fileBinary, (int)ThumbRatioEnum.half, quality);
                    fileThumb14 = _pictureService.ResizePicture(fileBinary, (int)ThumbRatioEnum.quarter, quality);
                    fileThumb16 = _pictureService.ResizePicture(fileBinary, (int)ThumbRatioEnum.oneSixth, quality);
                    fileThumb18 = _pictureService.ResizePicture(fileBinary, (int)ThumbRatioEnum.oneEighth, quality);

                    pathThumb12 = Path.Combine(saveFilePath, $"{uniqueCode.ToString().Replace("-", "")}_12{fileEx}");
                    pathThumb14 = Path.Combine(saveFilePath, $"{uniqueCode.ToString().Replace("-", "")}_14{fileEx}");
                    pathThumb16 = Path.Combine(saveFilePath, $"{uniqueCode.ToString().Replace("-", "")}_16{fileEx}");
                    pathThumb18 = Path.Combine(saveFilePath, $"{uniqueCode.ToString().Replace("-", "")}_18{fileEx}");

                    isPortraitImage = _pictureService.isPortraitImage(fileBinary);

                    if (!_aqFileProvider.FileExists(pathThumb12))
                    {
                        using (Stream f = File.OpenWrite(pathThumb12))
                        {
                            await f.WriteAsync(fileThumb12, 0, fileThumb12.Length);
                        };
                    }

                    if (!_aqFileProvider.FileExists(pathThumb14))
                    {
                        using (Stream f = File.OpenWrite(pathThumb14))
                        {
                            await f.WriteAsync(fileThumb14, 0, fileThumb14.Length);
                        };
                    }

                    if (!_aqFileProvider.FileExists(pathThumb16))
                    {
                        using (Stream f = File.OpenWrite(pathThumb16))
                        {
                            await f.WriteAsync(fileThumb16, 0, fileThumb16.Length);
                        };
                    }

                    if (!_aqFileProvider.FileExists(pathThumb18))
                    {
                        using (Stream f = File.OpenWrite(pathThumb18))
                        {
                            await f.WriteAsync(fileThumb18, 0, fileThumb18.Length);
                        };
                    }
                }

                var virtualPath       = fullPath.Replace($@"{_hostingEnvironment.WebRootPath}\", "").Replace(@"\", "/");
                var virtuaPathThumb12 = pathThumb12.Replace($@"{_hostingEnvironment.WebRootPath}\", "").Replace(@"\", "/");
                var virtuaPathThumb14 = pathThumb14.Replace($@"{_hostingEnvironment.WebRootPath}\", "").Replace(@"\", "/");
                var virtuaPathThumb16 = pathThumb16.Replace($@"{_hostingEnvironment.WebRootPath}\", "").Replace(@"\", "/");
                var virtuaPathThumb18 = pathThumb18.Replace($@"{_hostingEnvironment.WebRootPath}\", "").Replace(@"\", "/");

                if (!_aqFileProvider.DirectoryExists(fullPath))
                {
                    using (Stream f = File.OpenWrite(fullPath))
                    {
                        await f.WriteAsync(fileBinary, 0, fileBinary.Length);
                    };
                }

                var fileInfo = new FileStreamInfo()
                {
                    UniqueId        = uniqueId,
                    UniqueCode      = uniqueCode,
                    FileTypeFid     = Convert.ToInt32(fileType),
                    OriginalName    = originalName,
                    FileName        = fileName,
                    Seoname         = seoName,
                    FileExtentions  = fileEx,
                    FileSize        = fileBinary.Length,
                    Path            = virtualPath,
                    PathThumb12     = virtuaPathThumb12,
                    PathThumb14     = virtuaPathThumb14,
                    PathThumb16     = virtuaPathThumb16,
                    PathThumb18     = virtuaPathThumb18,
                    UploadedDateUtc = DateTime.UtcNow,
                    UploadedBy      = "",
                    Deleted         = false,
                    IsNew           = true,
                    IsPortraitImage = isPortraitImage
                };

                await InsertFileInfo(fileInfo);

                var fileData = new FileStreamData()
                {
                    FileId   = fileInfo.FileId,
                    FileData = fileBinary
                };

                await InsertFileData(fileData);

                return(new FileUploadResponse()
                {
                    FileName = fileInfo.FileName,
                    FileSize = fileInfo.FileSize,
                    FileId = fileInfo.FileId
                });
            }
            catch
            {
                throw;
            }
        }
示例#12
0
        public async Task <int> InsertFileData(FileStreamData fileData)
        {
            var res = await Task.Run(() => _dataContext.FileStreamData.Add(fileData));

            return(await _dataContext.SaveChangesAsync());
        }
        private static async Task DownloadSteam3AsyncDepotFileChunk(
            CancellationTokenSource cts, uint appId,
            GlobalDownloadCounter downloadCounter,
            DepotFilesData depotFilesData,
            ProtoManifest.FileData file,
            FileStreamData fileStreamData,
            ProtoManifest.ChunkData chunk)
        {
            cts.Token.ThrowIfCancellationRequested();

            var depot = depotFilesData.depotDownloadInfo;
            var depotDownloadCounter = depotFilesData.depotCounter;

            string chunkID = Util.EncodeHexString(chunk.ChunkID);

            DepotManifest.ChunkData data = new DepotManifest.ChunkData();
            data.ChunkID            = chunk.ChunkID;
            data.Checksum           = chunk.Checksum;
            data.Offset             = chunk.Offset;
            data.CompressedLength   = chunk.CompressedLength;
            data.UncompressedLength = chunk.UncompressedLength;

            CDNClient.DepotChunk chunkData = null;

            do
            {
                cts.Token.ThrowIfCancellationRequested();

                CDNClient.Server connection = null;

                try
                {
                    connection = cdnPool.GetConnection(cts.Token);
                    var cdnToken = await cdnPool.AuthenticateConnection(appId, depot.id, connection);

                    chunkData = await cdnPool.CDNClient.DownloadDepotChunkAsync(depot.id, data,
                                                                                connection, cdnToken, depot.depotKey).ConfigureAwait(false);

                    cdnPool.ReturnConnection(connection);
                }
                catch (TaskCanceledException)
                {
                    Console.WriteLine("Connection timeout downloading chunk {0}", chunkID);
                }
                catch (SteamKitWebRequestException e)
                {
                    cdnPool.ReturnBrokenConnection(connection);

                    if (e.StatusCode == HttpStatusCode.Unauthorized || e.StatusCode == HttpStatusCode.Forbidden)
                    {
                        Console.WriteLine("Encountered 401 for chunk {0}. Aborting.", chunkID);
                        break;
                    }
                    else
                    {
                        Console.WriteLine("Encountered error downloading chunk {0}: {1}", chunkID, e.StatusCode);
                    }
                }
                catch (OperationCanceledException)
                {
                    break;
                }
                catch (Exception e)
                {
                    cdnPool.ReturnBrokenConnection(connection);
                    Console.WriteLine("Encountered unexpected error downloading chunk {0}: {1}", chunkID, e.Message);
                }
            }while (chunkData == null);

            if (chunkData == null)
            {
                Console.WriteLine("Failed to find any server with chunk {0} for depot {1}. Aborting.", chunkID, depot.id);
                cts.Cancel();
            }

            // Throw the cancellation exception if requested so that this task is marked failed
            cts.Token.ThrowIfCancellationRequested();

            try
            {
                await fileStreamData.fileLock.WaitAsync().ConfigureAwait(false);

                fileStreamData.fileStream.Seek((long)chunkData.ChunkInfo.Offset, SeekOrigin.Begin);
                await fileStreamData.fileStream.WriteAsync(chunkData.Data, 0, chunkData.Data.Length);
            }
            finally
            {
                fileStreamData.fileLock.Release();
            }

            int remainingChunks = Interlocked.Decrement(ref fileStreamData.chunksToDownload);

            if (remainingChunks == 0)
            {
                fileStreamData.fileStream.Dispose();
                fileStreamData.fileLock.Dispose();
            }

            ulong sizeDownloaded = 0;

            lock (depotDownloadCounter)
            {
                sizeDownloaded = depotDownloadCounter.SizeDownloaded + (ulong)chunkData.Data.Length;
                depotDownloadCounter.SizeDownloaded          = sizeDownloaded;
                depotDownloadCounter.DepotBytesCompressed   += chunk.CompressedLength;
                depotDownloadCounter.DepotBytesUncompressed += chunk.UncompressedLength;
            }

            lock (downloadCounter)
            {
                downloadCounter.TotalBytesCompressed   += chunk.CompressedLength;
                downloadCounter.TotalBytesUncompressed += chunk.UncompressedLength;
            }

            if (remainingChunks == 0)
            {
                var fileFinalPath = Path.Combine(depot.installDir, file.FileName);
                Console.WriteLine("{0,6:#00.00}% {1}", ((float)sizeDownloaded / (float)depotDownloadCounter.CompleteDownloadSize) * 100.0f, fileFinalPath);
            }
        }
        private static void DownloadSteam3AsyncDepotFile(
            CancellationTokenSource cts,
            DepotFilesData depotFilesData,
            ProtoManifest.FileData file,
            ConcurrentQueue <Tuple <FileStreamData, ProtoManifest.FileData, ProtoManifest.ChunkData> > networkChunkQueue)
        {
            cts.Token.ThrowIfCancellationRequested();

            var depot                = depotFilesData.depotDownloadInfo;
            var stagingDir           = depotFilesData.stagingDir;
            var depotDownloadCounter = depotFilesData.depotCounter;
            var oldProtoManifest     = depotFilesData.previousManifest;

            string fileFinalPath   = Path.Combine(depot.installDir, file.FileName);
            string fileStagingPath = Path.Combine(stagingDir, file.FileName);

            // This may still exist if the previous run exited before cleanup
            if (File.Exists(fileStagingPath))
            {
                File.Delete(fileStagingPath);
            }

            FileStream fs = null;
            List <ProtoManifest.ChunkData> neededChunks;
            FileInfo fi = new FileInfo(fileFinalPath);

            if (!fi.Exists)
            {
                Console.WriteLine("Pre-allocating {0}", fileFinalPath);

                // create new file. need all chunks
                fs = File.Create(fileFinalPath);
                fs.SetLength((long)file.TotalSize);
                neededChunks = new List <ProtoManifest.ChunkData>(file.Chunks);
            }
            else
            {
                // open existing
                ProtoManifest.FileData oldManifestFile = null;
                if (oldProtoManifest != null)
                {
                    oldManifestFile = oldProtoManifest.Files.SingleOrDefault(f => f.FileName == file.FileName);
                }

                if (oldManifestFile != null)
                {
                    neededChunks = new List <ProtoManifest.ChunkData>();

                    if (Config.VerifyAll || !oldManifestFile.FileHash.SequenceEqual(file.FileHash))
                    {
                        // we have a version of this file, but it doesn't fully match what we want
                        if (Config.VerifyAll)
                        {
                            Console.WriteLine("Validating {0}", fileFinalPath);
                        }

                        var matchingChunks = new List <ChunkMatch>();

                        foreach (var chunk in file.Chunks)
                        {
                            var oldChunk = oldManifestFile.Chunks.FirstOrDefault(c => c.ChunkID.SequenceEqual(chunk.ChunkID));
                            if (oldChunk != null)
                            {
                                matchingChunks.Add(new ChunkMatch(oldChunk, chunk));
                            }
                            else
                            {
                                neededChunks.Add(chunk);
                            }
                        }

                        var orderedChunks = matchingChunks.OrderBy(x => x.OldChunk.Offset);

                        File.Move(fileFinalPath, fileStagingPath);

                        fs = File.Open(fileFinalPath, FileMode.Create);
                        fs.SetLength((long)file.TotalSize);

                        using (var fsOld = File.Open(fileStagingPath, FileMode.Open))
                        {
                            foreach (var match in orderedChunks)
                            {
                                fsOld.Seek((long)match.OldChunk.Offset, SeekOrigin.Begin);

                                byte[] tmp = new byte[match.OldChunk.UncompressedLength];
                                fsOld.Read(tmp, 0, tmp.Length);

                                byte[] adler = Util.AdlerHash(tmp);
                                if (!adler.SequenceEqual(match.OldChunk.Checksum))
                                {
                                    neededChunks.Add(match.NewChunk);
                                }
                                else
                                {
                                    fs.Seek((long)match.NewChunk.Offset, SeekOrigin.Begin);
                                    fs.Write(tmp, 0, tmp.Length);
                                }
                            }
                        }

                        File.Delete(fileStagingPath);
                    }
                }
                else
                {
                    // No old manifest or file not in old manifest. We must validate.

                    fs = File.Open(fileFinalPath, FileMode.Open);
                    if ((ulong)fi.Length != file.TotalSize)
                    {
                        fs.SetLength((long)file.TotalSize);
                    }

                    Console.WriteLine("Validating {0}", fileFinalPath);
                    neededChunks = Util.ValidateSteam3FileChecksums(fs, file.Chunks.OrderBy(x => x.Offset).ToArray());
                }

                if (neededChunks.Count() == 0)
                {
                    lock (depotDownloadCounter)
                    {
                        depotDownloadCounter.SizeDownloaded += (ulong)file.TotalSize;
                        Console.WriteLine("{0,6:#00.00}% {1}", ((float)depotDownloadCounter.SizeDownloaded / (float)depotDownloadCounter.CompleteDownloadSize) * 100.0f, fileFinalPath);
                    }

                    if (fs != null)
                    {
                        fs.Dispose();
                    }
                    return;
                }
                else
                {
                    var sizeOnDisk = (file.TotalSize - (ulong)neededChunks.Select(x => (long)x.UncompressedLength).Sum());
                    lock (depotDownloadCounter)
                    {
                        depotDownloadCounter.SizeDownloaded += sizeOnDisk;
                    }
                }
            }

            FileStreamData fileStreamData = new FileStreamData
            {
                fileStream       = fs,
                fileLock         = new SemaphoreSlim(1),
                chunksToDownload = neededChunks.Count
            };

            foreach (var chunk in neededChunks)
            {
                networkChunkQueue.Enqueue(Tuple.Create(fileStreamData, file, chunk));
            }
        }
示例#15
0
        public int CreateIndex(string P_key, string P_value)
        {
            // Key Should contain ASCII 32-122 only

            KeyBytes = ASCIIEncoding.UTF8.GetBytes(P_key);

            uint RecordPointer = uint.MaxValue, NewRecordPointer = uint.MaxValue, IndexPointer = uint.MaxValue, NewIndexOffset = 0;

            String LastKey = "";

            NewRecordPointer = (uint)LastPosition; /// Start of Next Key

            IndexOffset = 0;
            ByteIndex   = 0;

            do
            {
                IndexPosition = (uint)(IndexOffset + (KeyBytes[ByteIndex] - 32) * 8);
                count++;
                try // Read next Branch (ASCII 32-122)
                {
                    if (KeyBytes[ByteIndex] < 32 || KeyBytes[ByteIndex] > 122)
                    {
                        return(-52);                                                       // Validate Character Range
                    }
                    FileStreamIdx.Seek(IndexPosition, 0);
                    RecordPointer = BinaryReaderIdx.ReadUInt32();
                    IndexPointer  = BinaryReaderIdx.ReadUInt32();
                }
                catch (Exception e)
                {
                    StringLastError = e.Message;
                    return(-1);
                }

                if (IndexPointer == uint.MaxValue)
                {
                    try
                    {
                        FileStreamIdx.Seek(IndexPosition, 0);
                        BinaryWriterIdx.Write(NewRecordPointer);
                        BinaryWriterIdx.Write(IndexPosition);
                        FileStreamIdx.Flush();
                        return(1); // Inserted new Branch successfully
                    }
                    catch (Exception e)
                    {
                        StringLastError = e.Message;
                        return(-1);
                    }
                }
                else
                {
                    try
                    {
                        FileStreamData.Seek(RecordPointer, 0);
                        LastKey      = BinaryReaderData.ReadString();
                        LastKeyBytes = ASCIIEncoding.UTF8.GetBytes(LastKey);
                    }
                    catch (Exception e)
                    {
                        StringLastError = e.Message;
                        return(-10);
                    }

                    Difference = GetDif(ref LastKeyBytes, ref KeyBytes);
                    if (Difference == 0)
                    {
                        if (BinaryReaderData.PeekChar() == 0)
                        {
                            return(-3);
                        }
                        else
                        {
                            FileStreamData.Seek(RecordPointer, 0);
                            BinaryWriterData.Write(P_key);
                            BinaryWriterData.Write(false);
                            BinaryWriterData.Write(P_value);

                            BinaryWriterData.Flush();

                            return(-4); /// if the record flag is deleted, update record.
                        }
                    }
                    else
                    {
                        if (Difference > 0)
                        {
                            if (IndexPointer == IndexPosition)
                            {
                                try
                                {
                                    NewIndexOffset = (uint)FileStreamIdx.Length;
                                    FileStreamIdx.Seek(IndexPosition + 4, 0);
                                    BinaryWriterIdx.Write(NewIndexOffset);
                                    ADDIndexBlock();

                                    IndexPosition = (uint)(NewIndexOffset + (KeyBytes[ByteIndex + 1] - 32) * 8);

                                    FileStreamIdx.Seek(IndexPosition, 0);

                                    BinaryWriterIdx.Write(NewRecordPointer);
                                    BinaryWriterIdx.Write(IndexPosition);
                                    FileStreamIdx.Flush();

                                    return(1); // Inserted new key successfully
                                }
                                catch (Exception e)
                                {
                                    StringLastError = e.Message;
                                    return(-16);
                                }
                            }
                            else
                            {
                                IndexOffset = IndexPointer;
                            }
                        }
                        else
                        {
                            if (IndexPointer == IndexPosition)
                            {
                                try
                                {
                                    NewIndexOffset = (uint)FileStreamIdx.Length;
                                    FileStreamIdx.Seek(IndexPosition, 0);

                                    BinaryWriterIdx.Write(NewRecordPointer);
                                    BinaryWriterIdx.Write(NewIndexOffset);
                                    ADDIndexBlock();

                                    NewRecordPointer = RecordPointer;

                                    KeyBytes = ASCIIEncoding.UTF8.GetBytes(LastKey);
                                    P_key    = LastKey;

                                    IndexOffset = NewIndexOffset;

                                    IndexPosition = (uint)(NewIndexOffset + (KeyBytes[ByteIndex + 1] - 32) * 8);

                                    FileStreamIdx.Seek(IndexPosition, 0);

                                    BinaryWriterIdx.Write(NewRecordPointer);
                                    BinaryWriterIdx.Write(IndexPosition);
                                    FileStreamIdx.Flush();

                                    return(1); // Inserted new key successfully
                                }
                                catch (Exception e)
                                {
                                    StringLastError = e.Message;
                                    return(-17);
                                }
                            }
                            else
                            {
                                try
                                {
                                    FileStreamIdx.Seek(IndexPosition, 0);
                                    BinaryWriterIdx.Write(NewRecordPointer);

                                    NewRecordPointer = RecordPointer;
                                    KeyBytes         = ASCIIEncoding.UTF8.GetBytes(LastKey);
                                    P_key            = LastKey;

                                    FileStreamIdx.Flush();

                                    IndexOffset = IndexPointer;
                                }
                                catch (Exception e)
                                {
                                    StringLastError = e.Message;
                                    return(-18);
                                }
                            }
                        }
                    }
                }

                ByteIndex++;
            } while (ByteIndex < KeyBytes.Length);

            return(-20);
        }