2 /* -----------------------------------------------------------------------
3 * <copyright file="FileState.cs" company="GRNet">
5 * Copyright 2011-2012 GRNET S.A. All rights reserved.
7 * Redistribution and use in source and binary forms, with or
8 * without modification, are permitted provided that the following
11 * 1. Redistributions of source code must retain the above
12 * copyright notice, this list of conditions and the following
15 * 2. Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer in the documentation and/or other materials
18 * provided with the distribution.
21 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
34 * The views and conclusions contained in the software and
35 * documentation are those of the authors and should not be
36 * interpreted as representing official policies, either expressed
37 * or implied, of GRNET S.A.
39 * -----------------------------------------------------------------------
42 using System.Diagnostics.Contracts;
44 using System.Threading.Tasks;
45 using Castle.ActiveRecord;
46 using Castle.ActiveRecord.Framework;
47 using Pithos.Core.Agents;
48 using Pithos.Interfaces;
55 using System.Collections.Generic;
59 /// TODO: Update summary.
62 public class FileState : ActiveRecordLinqBase<FileState>
64 private static readonly ILog Log = LogManager.GetLogger("FileState");
66 private IList<FileTag> _tags = new List<FileTag>();
68 [PrimaryKey(PrimaryKeyType.Guid)]
69 public Guid Id { get; set; }
72 [Property(Unique = true, UniqueKey = "IX_FileState_FilePath")]
73 public string FilePath { get; set; }
76 public FileOverlayStatus OverlayStatus { get; set; }
79 public FileStatus FileStatus { get; set; }
82 public string Checksum { get; set; }
86 public long? Version { get; set; }
89 public DateTime? VersionTimeStamp { get; set; }
93 public bool IsShared { get; set; }
96 public string SharedBy { get; set; }
99 public bool ShareWrite { get; set; }
102 public bool IsFolder{ get; set; }
104 [HasMany(Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Lazy = true, Inverse = true)]
105 public IList<FileTag> Tags
107 get { return _tags; }
108 set { _tags = value; }
112 public DateTime Modified { get; set; }
115 public FileSystemInfo GetFileSystemInfo()
117 if (String.IsNullOrWhiteSpace(FilePath))
118 throw new InvalidOperationException();
119 Contract.EndContractBlock();
121 return Directory.Exists(FilePath) ?
122 (FileSystemInfo)new DirectoryInfo(FilePath)
123 : new FileInfo(FilePath);
126 public string GetRelativeUrl(AccountInfo accountInfo)
128 if (accountInfo==null)
129 throw new ArgumentNullException("accountInfo");
130 Contract.EndContractBlock();
132 var fsi=GetFileSystemInfo();
133 return fsi.AsRelativeUrlTo(accountInfo.AccountPath);
135 /*public static FileState FindByFilePath(string absolutePath)
137 if (string.IsNullOrWhiteSpace(absolutePath))
138 throw new ArgumentNullException("absolutePath");
139 Contract.EndContractBlock();
145 return Queryable.FirstOrDefault(s => s.FilePath == absolutePath);
149 Log.Error(ex.ToString());
156 /* public static void DeleteByFilePath(string absolutePath)
158 if (string.IsNullOrWhiteSpace(absolutePath))
159 throw new ArgumentNullException("absolutePath");
160 Contract.EndContractBlock();
162 ExecuteWithRetry((session, instance) =>
164 const string hqlDelete = "delete FileState where FilePath = :path";
165 var deletedEntities = session.CreateQuery(hqlDelete)
166 .SetString("path", absolutePath)
168 return deletedEntities;
173 public static void StoreFileStatus(string absolutePath, FileStatus newStatus)
175 if (string.IsNullOrWhiteSpace(absolutePath))
176 throw new ArgumentNullException("absolutePath");
177 Contract.EndContractBlock();
179 ExecuteWithRetry((session, instance) =>
181 const string hqlUpdate = "update FileState set FileStatus= :status where FilePath = :path ";
182 var updatedEntities = session.CreateQuery(hqlUpdate)
183 .SetString("path", absolutePath)
184 .SetEnum("status", newStatus)
186 if (updatedEntities == 0)
188 var newState = new FileState
190 FilePath = absolutePath,
192 FileStatus = newStatus,
193 IsFolder=Directory.Exists(absolutePath)
195 newState.CreateAndFlush();
202 public static void StoreOverlayStatus(string absolutePath, FileOverlayStatus newStatus)
204 if (string.IsNullOrWhiteSpace(absolutePath))
205 throw new ArgumentNullException("absolutePath");
206 Contract.EndContractBlock();
208 ExecuteWithRetry((session, instance) =>
210 const string hqlUpdate =
211 "update FileState set OverlayStatus= :status where FilePath = :path ";
212 var updatedEntities = session.CreateQuery(hqlUpdate)
213 .SetString("path", absolutePath)
214 .SetEnum("status", newStatus)
216 if (updatedEntities == 0)
218 var newState = new FileState
220 FilePath = absolutePath,
222 OverlayStatus = newStatus,
223 IsFolder=Directory.Exists(absolutePath)
225 newState.CreateAndFlush();
233 public static void UpdateStatus(string absolutePath, FileStatus fileStatus, FileOverlayStatus overlayStatus)
235 if (string.IsNullOrWhiteSpace(absolutePath))
236 throw new ArgumentNullException("absolutePath");
237 Contract.EndContractBlock();
239 ExecuteWithRetry((session, instance) =>
241 const string hqlUpdate =
242 "update FileState set OverlayStatus= :overlayStatus, FileStatus= :fileStatus where FilePath = :path ";
243 var updatedEntities = session.CreateQuery(hqlUpdate)
244 .SetString("path", absolutePath)
245 .SetEnum("fileStatus", fileStatus)
246 .SetEnum("overlayStatus", overlayStatus)
248 return updatedEntities;
255 public static void UpdateStatus(string absolutePath, FileStatus fileStatus)
257 if (string.IsNullOrWhiteSpace(absolutePath))
258 throw new ArgumentNullException("absolutePath");
259 Contract.EndContractBlock();
261 ExecuteWithRetry((session, instance) =>
263 const string hqlUpdate =
264 "update FileState set FileStatus= :fileStatus where FilePath = :path ";
265 var updatedEntities = session.CreateQuery(hqlUpdate)
266 .SetString("path", absolutePath)
267 .SetEnum("fileStatus", fileStatus)
269 return updatedEntities;
275 public static void RenameState(string oldPath, string newPath)
277 if (string.IsNullOrWhiteSpace(oldPath))
278 throw new ArgumentNullException("oldPath");
279 Contract.EndContractBlock();
281 ExecuteWithRetry((session, instance) =>
283 const string hqlUpdate =
284 "update FileState set FilePath= :newPath where FilePath = :oldPath ";
285 var updatedEntities = session.CreateQuery(hqlUpdate)
286 .SetString("oldPath", oldPath)
287 .SetString("newPath", newPath)
289 return updatedEntities;
294 /* public static void UpdateStatus(Guid id, FileStatus fileStatus)
297 ExecuteWithRetry((session, instance) =>
299 const string hqlUpdate =
300 "update FileState set FileStatus= :fileStatus where Id = :id ";
301 var updatedEntities = session.CreateQuery(hqlUpdate)
303 .SetEnum("fileStatus", fileStatus)
305 return updatedEntities;
309 public static void UpdateChecksum(string absolutePath, string checksum)
311 if (string.IsNullOrWhiteSpace(absolutePath))
312 throw new ArgumentNullException("absolutePath");
313 Contract.EndContractBlock();
315 ExecuteWithRetry((session, instance) =>
317 const string hqlUpdate = "update FileState set Checksum= :checksum where FilePath = :path ";
318 var updatedEntities = session.CreateQuery(hqlUpdate)
319 .SetString("path", absolutePath)
320 .SetString("checksum", checksum)
322 return updatedEntities;
327 public static void ChangeRootPath(string oldPath, string newPath)
329 if (String.IsNullOrWhiteSpace(oldPath))
330 throw new ArgumentNullException("oldPath");
331 if (!Path.IsPathRooted(oldPath))
332 throw new ArgumentException("oldPath must be an absolute path", "oldPath");
333 if (string.IsNullOrWhiteSpace(newPath))
334 throw new ArgumentNullException("newPath");
335 if (!Path.IsPathRooted(newPath))
336 throw new ArgumentException("newPath must be an absolute path", "newPath");
337 Contract.EndContractBlock();
339 //Ensure the paths end with the same character
340 if (!oldPath.EndsWith("\\"))
341 oldPath = oldPath + "\\";
342 if (!newPath.EndsWith("\\"))
343 newPath = newPath + "\\";
345 ExecuteWithRetry((session, instance) =>
347 const string hqlUpdate =
348 "update FileState set FilePath = replace(FilePath,:oldPath,:newPath) where FilePath like :oldPath || '%' ";
349 var renames = session.CreateQuery(hqlUpdate)
350 .SetString("oldPath", oldPath)
351 .SetString("newPath", newPath)
357 public static Task<FileState> CreateForAsync(string filePath, int blockSize, string algorithm)
360 throw new ArgumentOutOfRangeException("blockSize");
361 if (String.IsNullOrWhiteSpace(algorithm))
362 throw new ArgumentNullException("algorithm");
363 Contract.EndContractBlock();
366 var fileState = new FileState
369 OverlayStatus = FileOverlayStatus.Unversioned,
370 FileStatus = FileStatus.Created,
375 return fileState.UpdateHashesAsync(blockSize, algorithm);
378 public async Task<FileState> UpdateHashesAsync(int blockSize, string algorithm)
381 throw new ArgumentOutOfRangeException("blockSize");
382 if (String.IsNullOrWhiteSpace(algorithm))
383 throw new ArgumentNullException("algorithm");
384 Contract.EndContractBlock();
386 //Skip updating the hash for folders
387 if (Directory.Exists(FilePath))
390 var hash = await TaskEx.Run(() =>
392 var info = new FileInfo(FilePath);
393 return info.CalculateHash(blockSize, algorithm);
401 private static void ExecuteWithRetry(NHibernateDelegate call, object state)
407 using (new SessionScope())
409 Execute(call, state);
413 catch (ActiveRecordException )
422 [ActiveRecord("Tags")]
423 public class FileTag : ActiveRecordLinqBase<FileTag>
426 public int Id { get; set; }
429 public string Name { get; set; }
432 public string Value { get; set; }
434 [BelongsTo("FileStateId")]
435 public FileState FileState { get; set; }