/// <summary>Default constructor is private.</summary> private AccountInfo() { this.BucketName = S3ObjectInfoProvider.GetBucketName("~"); if (string.IsNullOrEmpty(this.BucketName)) { throw new InvalidOperationException($"Amazon S3 bucket name could not be found. You must specify it in Settings by {SettingsKeyNames.AmazonS3BucketName} setting key."); } this.mS3Client = new AmazonS3ClientFactory().Create(this.BucketName); }
/// <summary>Sets last write time and creation time to S3 object.</summary> private void SetLastWriteTimeAndCreationTimeToS3Object() { string dateTimeString = S3ObjectInfoProvider.GetDateTimeString(DateTime.Now); if (this.obj.GetMetadata(S3ObjectInfoProvider.CREATION_TIME) == null) { this.obj.SetMetadata(S3ObjectInfoProvider.CREATION_TIME, dateTimeString, false); } this.obj.SetMetadata(S3ObjectInfoProvider.LAST_WRITE_TIME, dateTimeString); }
/// <summary> /// Opens a file, appends the specified string to the file, and then closes the file. If the file does not exist, this method creates a file, writes the specified string to the file, then closes the file. /// </summary> /// <param name="path">Path</param> /// <param name="contents">Content to write.</param> public override void AppendAllText(string path, string contents) { string directoryName = CMS.IO.Path.GetDirectoryName(path); if (!CMS.IO.Directory.Exists(directoryName)) { throw GetDirectoryNotFoundException(directoryName); } IS3ObjectInfo info = S3ObjectFactory.GetInfo(path); File.Provider.AppendTextToObject(info, contents); info.SetMetadata(S3ObjectInfoProvider.LAST_WRITE_TIME, S3ObjectInfoProvider.GetDateTimeString(DateTime.Now)); }
/// <summary> /// Returns the date and time the specified file or directory was last written to. /// </summary> /// <param name="path">Path to file.</param> public override DateTime GetLastWriteTime(string path) { if (!this.Exists(path)) { throw GetFileNotFoundException(path); } IS3ObjectInfo info = S3ObjectFactory.GetInfo(path); if (Provider.ObjectExists(info)) { return(S3ObjectInfoProvider.GetStringDateTime(info.GetMetadata(S3ObjectInfoProvider.LAST_WRITE_TIME))); } return(System.IO.File.GetLastAccessTime(path)); }
/// <summary> /// Creates a new file, writes the specified byte array to the file, and then closes the file. If the target file already exists, it is overwritten. /// </summary> /// <param name="path">Path to file.</param> /// <param name="bytes">Bytes to write.</param> public override void WriteAllBytes(string path, byte[] bytes) { string directoryName = CMS.IO.Path.GetDirectoryName(path); if (!CMS.IO.Directory.Exists(directoryName)) { throw GetDirectoryNotFoundException(directoryName); } var memoryStream = new System.IO.MemoryStream(bytes); IS3ObjectInfo info = S3ObjectFactory.GetInfo(path); Provider.PutDataFromStreamToObject(info, memoryStream); info.SetMetadata(S3ObjectInfoProvider.LAST_WRITE_TIME, S3ObjectInfoProvider.GetDateTimeString(DateTime.Now)); }
/// <summary> /// Gets end point and public access from web.config and sets properties. /// </summary> private static void GetEndPointAndAccess() { mEndPoint = ValidationHelper.GetString(SettingsHelper.AppSettings["CMSAmazonEndPoint"], null); if (mEndPoint == null) { mEndPoint = $"http://{S3ObjectInfoProvider.GetBucketName("~")}.s3.amazonaws.com"; mPublicAccess = new bool?(ValidationHelper.GetBoolean(SettingsHelper.AppSettings["CMSAmazonPublicAccess"], false)); } else { mEndPoint = URLHelper.AddHTTPToUrl(mEndPoint); mPublicAccess = new bool?(ValidationHelper.GetBoolean(SettingsHelper.AppSettings["CMSAmazonPublicAccess"], true)); } }
/// <summary> /// Sets the date and time that the specified file was last written to. /// </summary> /// <param name="path">Path to file.</param> /// <param name="lastWriteTime">Last write time.</param> public override void SetLastWriteTime(string path, DateTime lastWriteTime) { if (!this.Exists(path)) { throw GetFileNotFoundException(path); } IS3ObjectInfo info = S3ObjectFactory.GetInfo(path); if (Provider.ObjectExists(info)) { info.SetMetadata(S3ObjectInfoProvider.LAST_WRITE_TIME, S3ObjectInfoProvider.GetDateTimeString(lastWriteTime)); } else { throw new InvalidOperationException($"Cannot last write time to file '{path}' because is located only in application file system. \r\n This exception typically occurs when file system is mapped to Amazon S3 storage after the file or directory\r\n '{path}' was created in the local file system. To fix this issue move given file to Amazon S3 storage."); } }
/// <summary> /// Sets the specified FileAttributes of the file on the specified path. /// </summary> /// <param name="path">Path to file.</param> /// <param name="fileAttributes">File attributes.</param> public override void SetAttributes(string path, CMS.IO.FileAttributes fileAttributes) { if (!this.Exists(path)) { throw GetFileNotFoundException(path); } IS3ObjectInfo info = S3ObjectFactory.GetInfo(path); if (File.Provider.ObjectExists(info)) { info.SetMetadata(S3ObjectInfoProvider.ATTRIBUTES, ValidationHelper.GetString(ValidationHelper.GetInteger(fileAttributes, 0), string.Empty), false); info.SetMetadata(S3ObjectInfoProvider.LAST_WRITE_TIME, S3ObjectInfoProvider.GetDateTimeString(DateTime.Now)); } else { throw new InvalidOperationException($"Cannot set attributes to file '{path}' because it exists only in application file system. \r\n This exception typically occurs when file system is mapped to Amazon S3 storage after the file or directory\r\n '{path}' was created in the local file system. To fix this issue move given file to Amazon S3 storage."); } }
/// <summary>Sets values from System.IO.FileInfo to this file info</summary> private void InitCMSValues() { if (this.mSystemInfo != null) { this.mExtension = this.mSystemInfo.Extension; this.mFullName = this.mSystemInfo.FullName; this.mName = this.mSystemInfo.Name; this.mExists = this.mSystemInfo.Exists; this.LastWriteTime = this.mSystemInfo.LastWriteTime; this.CreationTime = this.mSystemInfo.CreationTime; this.IsReadOnly = this.mSystemInfo.IsReadOnly; this.Attributes = (CMS.IO.FileAttributes) this.mSystemInfo.Attributes; if (this.mExists) { this.mLength = this.mSystemInfo.Length; } if (this.mDirectory == null) { this.mDirectory = new DirectoryInfo(this.mSystemInfo.Directory.FullName); } this.mDirectory.CreationTime = this.mSystemInfo.Directory.CreationTime; this.mDirectory.Exists = this.mSystemInfo.Directory.Exists; this.mDirectory.FullName = this.mSystemInfo.Directory.FullName; this.mDirectory.LastWriteTime = this.mSystemInfo.Directory.LastWriteTime; this.mDirectory.Name = this.mSystemInfo.Directory.Name; } else { if (this.mExists) { this.mLastWriteTime = S3ObjectInfoProvider.GetStringDateTime(this.obj.GetMetadata(S3ObjectInfoProvider.LAST_WRITE_TIME)); this.mCreationTime = S3ObjectInfoProvider.GetStringDateTime(this.obj.GetMetadata(S3ObjectInfoProvider.CREATION_TIME)); this.mAttributes = (CMS.IO.FileAttributes)ValidationHelper.GetInteger((object)this.obj.GetMetadata(S3ObjectInfoProvider.CREATION_TIME), ValidationHelper.GetInteger((object)CMS.IO.FileAttributes.Normal, 0, (CultureInfo)null), (CultureInfo)null); this.mLength = this.obj.Length; } else { this.LastWriteTime = DateTimeHelper.ZERO_TIME; this.CreationTime = DateTimeHelper.ZERO_TIME; this.mAttributes = CMS.IO.FileAttributes.Normal; } this.mDirectory = new DirectoryInfo(CMS.IO.Path.GetDirectoryName(this.FullName)); } }
/// <summary> /// Copies an existing file to a new file. Overwriting a file of the same name is allowed. /// </summary> /// <param name="sourceFileName">Path to source file.</param> /// <param name="destFileName">Path to destination file.</param> /// <param name="overwrite">If destination file should be overwritten.</param> public override void Copy(string sourceFileName, string destFileName, bool overwrite) { if (!this.Exists(sourceFileName)) { throw GetFileNotFoundException(sourceFileName); } bool destExists = CMS.IO.File.Exists(destFileName); if (destExists && !overwrite) { return; } if (!StorageHelper.IsSameStorageProvider(sourceFileName, destFileName)) { StorageHelper.CopyFileAcrossProviders(sourceFileName, destFileName); } else { IS3ObjectInfo sourceInfo = S3ObjectFactory.GetInfo(sourceFileName); IS3ObjectInfo destInfo = S3ObjectFactory.GetInfo(destFileName); if (destExists) { Provider.DeleteObject(destInfo); } if (Provider.ObjectExists(sourceInfo)) { Provider.CopyObjects(sourceInfo, destInfo); } else { Provider.PutFileToObject(destInfo, sourceFileName); } IS3ObjectInfo destDirectoryInfo = S3ObjectFactory.GetInfo(CMS.IO.Path.GetDirectoryName(destFileName)); destDirectoryInfo.Key = $"{destDirectoryInfo.Key}/"; if (!Provider.ObjectExists(destDirectoryInfo)) { Provider.CreateEmptyObject(destDirectoryInfo); } var now = DateTime.Now; destDirectoryInfo.SetMetadata(S3ObjectInfoProvider.LAST_WRITE_TIME, S3ObjectInfoProvider.GetDateTimeString(now)); destInfo.SetMetadata(S3ObjectInfoProvider.LAST_WRITE_TIME, S3ObjectInfoProvider.GetDateTimeString(now), false); destInfo.SetMetadata(S3ObjectInfoProvider.CREATION_TIME, S3ObjectInfoProvider.GetDateTimeString(now)); } }
/// <summary> /// Uploads one large file to Amazon S3 storage in smaller parts. /// </summary> /// <remarks>Stream still needs to be disposed.</remarks> /// <param name="uploadSessionId">Unique identifier for one multipart upload. Can be obtained by <see cref="M:CMS.AmazonStorage.FileStream.InitMultiPartUpload" /> method.</param> /// <param name="partIdentifiers">List of identifiers from Amazon S3 received after uploading each part by <see cref="M:CMS.AmazonStorage.FileStream.UploadStreamContentAsMultiPart(System.String,System.Int32)" /> method.</param> /// <returns>ETag of the uploaded file.</returns> public string CompleteMultiPartUploadProcess(string uploadSessionId, IEnumerable <string> partIdentifiers) { this.mMultiPartUploadMode = true; List <UploadPartResponse> uploadPartResponseList = partIdentifiers.Select((id, index) => new UploadPartResponse { PartNumber = index + 1, ETag = id }).ToList(); if (this.obj.IsLocked) { throw new Exception($"Couldn't upload part of the object {this.obj.Key} because it is used by another process."); } this.obj.Lock(); this.obj.ETag = this.MultiPartUploader.CompleteMultiPartUploadProcess(this.obj.Key, this.obj.BucketName, uploadSessionId, uploadPartResponseList).ETag; this.obj.UnLock(); this.SetLastWriteTimeAndCreationTimeToS3Object(); S3ObjectInfoProvider.RemoveRequestCache(this.obj.Key); return(this.obj.ETag); }
/// <summary> /// Uploads stream's content to Amazon S3 storage as one part of the file in multipart upload process /// identified by <paramref name="uploadSessionId" />. /// </summary> /// <remarks> /// Always returns one ETag in collection. If stream's length is more than 5GB then exception is thrown. /// </remarks> /// <param name="uploadSessionId">Unique identifier for one multipart upload. Can be obtained by <see cref="M:CMS.AmazonStorage.FileStream.InitMultiPartUpload" />.</param> /// <param name="nextPartNumber">Number that defines position of the data obtained by the stream in the whole multipart upload process.</param> /// <returns>One unique identifier of the uploaded part in collection.</returns> public IEnumerable <string> UploadStreamContentAsMultiPart(string uploadSessionId, int nextPartNumber) { if (this.Length > this.MaximalPartSize) { throw new Exception($"Maximal size of part for upload to Amazon S3 storage is {this.MaximalPartSize} current stream has length {this.Length}."); } this.mMultiPartUploadMode = true; if (this.obj.IsLocked) { throw new Exception($"Couldn't upload part of the object {this.obj.Key} because it is used by another process."); } this.obj.Lock(); this.obj.Length += this.Length; List <string> stringList = new List <string>(); this.MultiPartUploader.UploadPartFromStream(uploadSessionId, this.obj.Key, this.obj.BucketName, nextPartNumber, this); this.obj.UnLock(); S3ObjectInfoProvider.RemoveRequestCache(this.obj.Key); return(stringList); }
/// <summary> /// Deletes the specified file. An exception is not thrown if the specified file does not exist. /// </summary> /// <param name="path">Path to file</param> public override void Delete(string path) { if (!this.Exists(path)) { throw GetFileNotFoundException(path); } IS3ObjectInfo info1 = S3ObjectFactory.GetInfo(path); if (Provider.ObjectExists(info1)) { Provider.DeleteObject(info1); IS3ObjectInfo info2 = S3ObjectFactory.GetInfo(CMS.IO.Path.GetDirectoryName(path)); info2.Key = $"{info2.Key}/"; if (!Provider.ObjectExists(info2)) { Provider.CreateEmptyObject(info2); } info2.SetMetadata(S3ObjectInfoProvider.LAST_WRITE_TIME, S3ObjectInfoProvider.GetDateTimeString(DateTime.Now)); } else { throw new InvalidOperationException($"File '{path}' cannot be deleted because it exists only in application file system. \r\n This exception typically occurs when file system is mapped to Amazon S3 storage after the file or directory\r\n '{path}' was created in the local file system. To fix this issue remove specified file or directory."); } }
/// <summary> /// Aborts multipart upload to Amazon S3 storage and removes all resources already uploaded. /// </summary> /// <param name="uploadSessionId"> /// Unique identifier for multipart upload process to external storage. /// Is obtained by <see cref="M:CMS.AmazonStorage.FileStream.InitMultiPartUpload" />. /// </param> public void AbortMultiPartUpload(string uploadSessionId) { S3ObjectInfoProvider.RemoveRequestCache(this.obj.Key); this.MultiPartUploader.AbortMultiPartUpload(this.obj.Key, this.obj.BucketName, uploadSessionId); }