// ----------------------------------------------------------------------- // // Copyright 2011 GRNET S.A. All rights reserved. // // Redistribution and use in source and binary forms, with or // without modification, are permitted provided that the following // conditions are met: // // 1. Redistributions of source code must retain the above // copyright notice, this list of conditions and the following // disclaimer. // // 2. Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials // provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS // OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // // The views and conclusions contained in the software and // documentation are those of the authors and should not be // interpreted as representing official policies, either expressed // or implied, of GRNET S.A. // // ----------------------------------------------------------------------- using System.Diagnostics.Contracts; using System.IO; using System.Threading.Tasks; using Castle.ActiveRecord; using Castle.ActiveRecord.Framework; using Pithos.Core.Agents; using Pithos.Interfaces; using log4net; namespace Pithos.Core { using System; using System.Collections.Generic; using System.Linq; /// /// TODO: Update summary. /// [ActiveRecord] public class FileState:ActiveRecordLinqBase { private static readonly ILog Log = LogManager.GetLogger("FileState"); private string _filePath; private IList _tags=new List(); [PrimaryKey(PrimaryKeyType.Guid)] public Guid Id { get; set; } [Property(Unique=true,UniqueKey="IX_FileState_FilePath")] public string FilePath { get { return _filePath; } set { _filePath = value.ToLower(); } } [Property] public FileOverlayStatus OverlayStatus { get; set; } [Property] public FileStatus FileStatus { get; set; } [Property] public string Checksum { get; set; } [Property] public long? Version { get; set; } [Property] public DateTime? VersionTimeStamp { get; set; } [Property] public bool IsShared { get; set; } [Property] public string SharedBy { get; set; } [Property] public bool ShareWrite { get; set; } [HasMany(Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Lazy = true,Inverse=true)] public IList Tags { get { return _tags; } set { _tags=value;} } public static FileState FindByFilePath(string absolutePath) { if (string.IsNullOrWhiteSpace(absolutePath)) throw new ArgumentNullException("absolutePath"); Contract.EndContractBlock(); try { return Queryable.FirstOrDefault(s => s.FilePath == absolutePath.ToLower()); } catch (Exception ex) { Log.Error(ex.ToString()); throw; } } public static void DeleteByFilePath(string absolutePath) { if(string.IsNullOrWhiteSpace(absolutePath)) throw new ArgumentNullException("absolutePath"); Contract.EndContractBlock(); Execute((session, instance) => { const string hqlDelete = "delete FileState where FilePath = :path"; var deletedEntities = session.CreateQuery(hqlDelete) .SetString("path", absolutePath.ToLower()) .ExecuteUpdate(); return deletedEntities; },null); } public static void StoreFileStatus(string absolutePath, FileStatus newStatus) { if (string.IsNullOrWhiteSpace(absolutePath)) throw new ArgumentNullException("absolutePath"); Contract.EndContractBlock(); Execute((session, instance) => { const string hqlUpdate = "update FileState set FileStatus= :status where FilePath = :path "; var updatedEntities = session.CreateQuery(hqlUpdate) .SetString("path", absolutePath.ToLower()) .SetEnum("status", newStatus) .ExecuteUpdate(); if (updatedEntities == 0) { var newState = new FileState { FilePath = absolutePath.ToLower(), Id = Guid.NewGuid(), FileStatus = newStatus }; newState.CreateAndFlush(); } return null; }, null); } public static void StoreOverlayStatus(string absolutePath, FileOverlayStatus newStatus) { if (string.IsNullOrWhiteSpace(absolutePath)) throw new ArgumentNullException("absolutePath"); Contract.EndContractBlock(); Execute((session, instance) => { const string hqlUpdate = "update FileState set OverlayStatus= :status where FilePath = :path "; var updatedEntities = session.CreateQuery(hqlUpdate) .SetString("path", absolutePath.ToLower()) .SetEnum("status", newStatus) .ExecuteUpdate(); if (updatedEntities == 0) { var newState = new FileState { FilePath = absolutePath, Id = Guid.NewGuid(), OverlayStatus = newStatus }; newState.CreateAndFlush(); } return null; }, null); } public static void UpdateStatus(string absolutePath, FileStatus fileStatus, FileOverlayStatus overlayStatus) { if (string.IsNullOrWhiteSpace(absolutePath)) throw new ArgumentNullException("absolutePath"); Contract.EndContractBlock(); Execute((session, instance) => { const string hqlUpdate = "update FileState set OverlayStatus= :overlayStatus, FileStatus= :fileStatus where FilePath = :path "; var updatedEntities = session.CreateQuery(hqlUpdate) .SetString("path", absolutePath.ToLower()) .SetEnum("fileStatus", fileStatus) .SetEnum("overlayStatus", overlayStatus) .ExecuteUpdate(); return updatedEntities; }, null); } public static void UpdateStatus(string absolutePath, FileStatus fileStatus) { if (string.IsNullOrWhiteSpace(absolutePath)) throw new ArgumentNullException("absolutePath"); Contract.EndContractBlock(); Execute((session, instance) => { const string hqlUpdate = "update FileState set FileStatus= :fileStatus where FilePath = :path "; var updatedEntities = session.CreateQuery(hqlUpdate) .SetString("path", absolutePath.ToLower()) .SetEnum("fileStatus", fileStatus) .ExecuteUpdate(); return updatedEntities; }, null); } public static void RenameState(string oldPath, string newPath) { if (string.IsNullOrWhiteSpace(oldPath)) throw new ArgumentNullException("oldPath"); Contract.EndContractBlock(); Execute((session, instance) => { const string hqlUpdate = "update FileState set FilePath= :newPath where FilePath = :oldPath "; var updatedEntities = session.CreateQuery(hqlUpdate) .SetString("oldPath", oldPath.ToLower()) .SetString("newPath", newPath.ToLower()) .ExecuteUpdate(); return updatedEntities; }, null); } public static void UpdateStatus(Guid id, FileStatus fileStatus) { Contract.EndContractBlock(); Execute((session, instance) => { const string hqlUpdate = "update FileState set FileStatus= :fileStatus where Id = :id "; var updatedEntities = session.CreateQuery(hqlUpdate) .SetGuid("id", id) .SetEnum("fileStatus", fileStatus) .ExecuteUpdate(); return updatedEntities; }, null); } public static void UpdateChecksum(string absolutePath, string checksum) { if (string.IsNullOrWhiteSpace(absolutePath)) throw new ArgumentNullException("absolutePath"); Contract.EndContractBlock(); Execute((session, instance) => { const string hqlUpdate = "update FileState set Checksum= :checksum where FilePath = :path "; var updatedEntities = session.CreateQuery(hqlUpdate) .SetString("path", absolutePath.ToLower()) .SetString("checksum", checksum) .ExecuteUpdate(); return updatedEntities; }, null); } public static void ChangeRootPath(string oldPath,string newPath) { if (String.IsNullOrWhiteSpace(oldPath)) throw new ArgumentNullException("oldPath"); if (!Path.IsPathRooted(oldPath)) throw new ArgumentException("oldPath must be an absolute path", "oldPath"); if (string.IsNullOrWhiteSpace(newPath)) throw new ArgumentNullException("newPath"); if (!Path.IsPathRooted(newPath)) throw new ArgumentException("newPath must be an absolute path", "newPath"); Contract.EndContractBlock(); //Ensure the paths end with the same character if (!oldPath.EndsWith("\\")) oldPath = oldPath + "\\"; if (!newPath.EndsWith("\\")) newPath = newPath + "\\"; using (new TransactionScope()) { Execute((session, instance) => { const string hqlUpdate = "update FileState set FilePath = replace(FilePath,:oldPath,:newPath) where FilePath like :oldPath || '%' "; var renames=session.CreateQuery(hqlUpdate) .SetString("oldPath", oldPath.ToLower()) .SetString("newPath", newPath.ToLower()) .ExecuteUpdate(); return renames; }, null); } } public static Task CreateForAsync(string filePath,int blockSize,string algorithm) { if (blockSize <= 0) throw new ArgumentOutOfRangeException("blockSize"); if (String.IsNullOrWhiteSpace(algorithm)) throw new ArgumentNullException("algorithm"); Contract.EndContractBlock(); var fileState = new FileState { FilePath = filePath.ToLower(), OverlayStatus = FileOverlayStatus.Unversioned, FileStatus = FileStatus.Created, Id=Guid.NewGuid() }; return fileState.UpdateHashesAsync(blockSize,algorithm); } public async Task UpdateHashesAsync(int blockSize,string algorithm) { if (blockSize<=0) throw new ArgumentOutOfRangeException("blockSize"); if (String.IsNullOrWhiteSpace(algorithm)) throw new ArgumentNullException("algorithm"); Contract.EndContractBlock(); //Skip updating the hash for folders if (Directory.Exists(FilePath)) return this; var hash = await TaskEx.Run(() => { var info = new FileInfo(FilePath); return info.CalculateHash(blockSize, algorithm); }); Checksum = hash; return this; } } [ActiveRecord("Tags")] public class FileTag : ActiveRecordLinqBase { [PrimaryKey] public int Id { get; set; } [Property] public string Name { get; set; } [Property] public string Value { get; set; } [BelongsTo("FileStateId")] public FileState FileState { get; set; } } }