-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-
-namespace Pithos.Interfaces
-{
- public class ObjectInfo
- {
- public string Name { get; set; }
- public string Hash { get; set; }
- public long Bytes { get; set; }
- public string Content_Type { get; set; }
- public DateTime Last_Modified { get; set; }
-
- private Dictionary<string, string> _tags=new Dictionary<string, string>();
- public Dictionary<string, string> Tags
- {
- get { return _tags; }
- set { _tags = value; }
- }
-
- private Dictionary<string, string> _extensions=new Dictionary<string, string>();
- public Dictionary<string, string> Extensions
- {
- get { return _extensions; }
- set
- {
- _extensions = value;
- ExtractKnownExtensions();
- }
- }
-
- private long? _version;
- public long? Version
- {
- get { return _version; }
- set { _version = value; }
- }
-
- //Alias for version, for Json deserialization purposes
- public long? X_Object_Version
- {
- get { return _version; }
- set { _version = value; }
- }
-
- /* //Alias vor VersionTimestamp, for Json deserialization purposes
- public DateTime? X_Object_Version_Timestamp
- {
- get { return _versionTimestamp; }
- set { _versionTimestamp = value; }
- }*/
-
- private DateTime? _versionTimestamp;
- public DateTime? VersionTimestamp
- {
- get { return _versionTimestamp; }
- set { _versionTimestamp = value; }
- }
-
- public string ModifiedBy
- {
- get{ return _modifiedBy; }
- set{ _modifiedBy = value; }
- }
-
- //Alias for ModifiedBy, for Json deserialization purposes
- public string X_Object_Modified_By
- {
- get{ return _modifiedBy; }
- set{ _modifiedBy = value; }
- }
-
- public Stream Stream { get; set; }
-
-
- private void ExtractKnownExtensions()
- {
- Version=GetLong(KnownExtensions.X_Object_Version);
- VersionTimestamp = GetTimestamp(KnownExtensions.X_Object_Version_Timestamp);
- ModifiedBy = GetString(KnownExtensions.X_Object_Modified_By);
- }
-
- private string GetString(string name)
- {
- var value=String.Empty;
- _extensions.TryGetValue(name, out value);
- return value ;
- }
-
- private long? GetLong(string name)
- {
- string version;
- long value;
- return _extensions.TryGetValue(name, out version) && long.TryParse(version, out value)
- ? (long?) value
- : null;
- }
-
- private DateTime? GetTimestamp(string name)
- {
- string version;
- DateTime value;
- if (_extensions.TryGetValue(name, out version) &&
- DateTime.TryParse(version,CultureInfo.InvariantCulture,DateTimeStyles.AdjustToUniversal, out value))
- {
- return value;
- }
- return null;
- }
-
-
- public static ObjectInfo Empty = new ObjectInfo
- {
- Name = String.Empty,
- Hash = String.Empty,
- Bytes = 0,
- Content_Type = String.Empty,
- Last_Modified = DateTime.MinValue
- };
-
- private string _modifiedBy;
- }
+#region\r
+/* -----------------------------------------------------------------------\r
+ * <copyright file="ObjectInfo.cs" company="GRNet">\r
+ * \r
+ * Copyright 2011-2012 GRNET S.A. All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * 2. Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS\r
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR\r
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\r
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\r
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+ * POSSIBILITY OF SUCH DAMAGE.\r
+ *\r
+ * The views and conclusions contained in the software and\r
+ * documentation are those of the authors and should not be\r
+ * interpreted as representing official policies, either expressed\r
+ * or implied, of GRNET S.A.\r
+ * </copyright>\r
+ * -----------------------------------------------------------------------\r
+ */\r
+#endregion\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Diagnostics;\r
+using System.Diagnostics.Contracts;\r
+using System.Dynamic;\r
+using System.Globalization;\r
+using System.IO;\r
+using System.Linq;\r
+using System.Text;\r
+using Newtonsoft.Json;\r
+\r
+namespace Pithos.Interfaces\r
+{\r
+ [DebuggerDisplay("Name {Name}")]\r
+ public class ObjectInfo//:DynamicObject \r
+ {\r
+ public const string CONTENT_TYPE_DIRECTORY = @"application/directory";\r
+ public const string CONTENT_TYPE_FOLDER = @"application/folder";\r
+ private readonly List<string> _knownContainers= new List<string>{"trash"};\r
+\r
+ [JsonConverter(typeof(RelativeUriConverter))]\r
+ public Uri Name\r
+ {\r
+ get { return _name; }\r
+ set\r
+ {\r
+ if (value != null && value.IsAbsoluteUri)\r
+ throw new ArgumentException("Must be relative Uri", "Name");\r
+ _name = value;\r
+ }\r
+ }\r
+\r
+ [JsonProperty("hash")]\r
+ public string ETag { get; set; }\r
+\r
+ //public string Hash { get; set; }\r
+\r
+/*\r
+ public string X_Object_Hash { get { return Hash; } set { Hash = value; } }\r
+*/\r
+\r
+ public string X_Object_Hash { get; set; }\r
+\r
+ [JsonProperty("x_object_uuid")]\r
+ public string UUID { get; set; }\r
+\r
+ public long Bytes { get; set; }\r
+ public string Content_Type { get; set; }\r
+ public DateTime Last_Modified { get; set; }\r
+\r
+ private Dictionary<string, string> _tags=new Dictionary<string, string>();\r
+ public Dictionary<string, string> Tags\r
+ {\r
+ get { return _tags; }\r
+ set { _tags = value; }\r
+ }\r
+\r
+ private Dictionary<string, string> _extensions=new Dictionary<string, string>();\r
+ public Dictionary<string, string> Extensions\r
+ {\r
+ get { return _extensions; }\r
+ set\r
+ {\r
+ _extensions = value;\r
+ ExtractKnownExtensions();\r
+ }\r
+ }\r
+ \r
+ \r
+ private Dictionary<string, string> _permissions=new Dictionary<string, string>();\r
+ [JsonProperty("x_object_sharing")]\r
+ [JsonConverter(typeof(PermissionConverter))]\r
+ public Dictionary<string, string> Permissions\r
+ {\r
+ get { return _permissions; }\r
+ set\r
+ {\r
+ _permissions = value; \r
+ }\r
+ }\r
+\r
+ /// <summary>\r
+ /// Version number\r
+ /// </summary>\r
+ [JsonProperty("x_object_version")]\r
+ public long? Version { get; set; }\r
+\r
+\r
+ /// <summary>\r
+ /// Shared object permissions can be Read or Write\r
+ /// </summary>\r
+ [JsonProperty("x_object_allowed_to")]\r
+ public string AllowedTo { get; set; }\r
+\r
+\r
+ /// <summary>\r
+ /// Version timestamp\r
+ /// </summary>\r
+ [JsonProperty("X_Object_Version_Timestamp"), JsonConverter(typeof(PithosDateTimeConverter))]\r
+ public DateTime? VersionTimestamp { get; set; }\r
+\r
+ [JsonProperty("X_Object_Modified_By")]\r
+ public string ModifiedBy { get; set; }\r
+\r
+\r
+ public Stream Stream { get; set; }\r
+\r
+\r
+ public Uri StorageUri { get; set; }\r
+\r
+ public string Account { get; set; }\r
+\r
+ [JsonConverter(typeof(RelativeUriConverter))]\r
+ public Uri Container\r
+ {\r
+ get { return _container; }\r
+ set\r
+ {\r
+ if (value != null && value.IsAbsoluteUri)\r
+ throw new ArgumentException("Must be relative Uri", "Container");\r
+ _container = value;\r
+ }\r
+ }\r
+\r
+ public Uri Uri\r
+ {\r
+ get\r
+ {\r
+ var relativeUrl=String.Format("{0}/{1}/{2}",Account, Container,Name);\r
+ return StorageUri==null \r
+ ? new Uri(relativeUrl,UriKind.Relative) \r
+ : StorageUri.Combine(relativeUrl);\r
+ }\r
+ }\r
+\r
+ public string ContendDisposition { get; set; }\r
+\r
+ public string ContentEncoding { get; set; }\r
+\r
+ public string Manifest { get; set; }\r
+ \r
+ public bool IsPublic\r
+ {\r
+ get { return !String.IsNullOrWhiteSpace(PublicUrl); }\r
+ set\r
+ {\r
+ if (!value)\r
+ PublicUrl = null;\r
+ else if (String.IsNullOrWhiteSpace(PublicUrl))\r
+ PublicUrl="true"; \r
+ }\r
+ }\r
+\r
+ [JsonProperty("X_Object_Public")]\r
+ public string PublicUrl { get; set; }\r
+\r
+ public string PreviousHash { get; set; }\r
+\r
+ public ObjectInfo()\r
+ {}\r
+\r
+ public ObjectInfo(string accountPath,string accountName,FileSystemInfo fileInfo)\r
+ {\r
+ if (String.IsNullOrWhiteSpace(accountPath))\r
+ throw new ArgumentNullException("accountPath");\r
+ if (string.IsNullOrWhiteSpace(accountName))\r
+ throw new ArgumentNullException("accountName");\r
+ if (fileInfo == null)\r
+ throw new ArgumentNullException("fileInfo");\r
+ Contract.EndContractBlock();\r
+\r
+ var relativeUrl = fileInfo.WithProperCapitalization().AsRelativeUrlTo(accountPath);\r
+ //The first part of the URL is the container\r
+ var parts = relativeUrl.ToString().Split(new[]{'/'}, 2);\r
+ var container = parts[0];\r
+ //The second is the file's url relative to the container\r
+ var fileUrl = parts[1];\r
+\r
+ Account = accountName;\r
+ Container = new Uri(container,UriKind.Relative);\r
+ Name = new Uri(fileUrl,UriKind.Relative); \r
+ }\r
+\r
+\r
+ private void ExtractKnownExtensions()\r
+ {\r
+ Version=GetLong(KnownExtensions.X_Object_Version);\r
+ VersionTimestamp = GetTimestamp(KnownExtensions.X_Object_Version_Timestamp);\r
+ ModifiedBy = GetString(KnownExtensions.X_Object_Modified_By);\r
+ }\r
+\r
+ private string GetString(string name)\r
+ { \r
+ string value;\r
+ _extensions.TryGetValue(name, out value);\r
+ return value ; \r
+ }\r
+ \r
+ private long? GetLong(string name)\r
+ {\r
+ string version;\r
+ long value;\r
+ return _extensions.TryGetValue(name, out version) && long.TryParse(version, out value)\r
+ ? (long?) value\r
+ : null;\r
+ }\r
+\r
+ private DateTime? GetTimestamp(string name)\r
+ {\r
+ string version;\r
+ DateTime value;\r
+ if (_extensions.TryGetValue(name, out version) && \r
+ DateTime.TryParse(version,CultureInfo.InvariantCulture,DateTimeStyles.AdjustToUniversal, out value))\r
+ {\r
+ return value;\r
+ }\r
+ return null;\r
+ }\r
+\r
+\r
+ public static ObjectInfo Empty = new ObjectInfo\r
+ {\r
+ Name = _emptyUri,\r
+ Container = _emptyUri,\r
+ ETag= String.Empty,\r
+ X_Object_Hash= String.Empty,\r
+ Bytes = 0,\r
+ Content_Type = String.Empty,\r
+ Last_Modified = DateTime.MinValue,\r
+ Exists=false\r
+ };\r
+\r
+ private bool _exists=true;\r
+ private Uri _container;\r
+ private Uri _name;\r
+ private static Uri _emptyUri = new Uri(String.Empty, UriKind.Relative);\r
+\r
+ public bool Exists\r
+ {\r
+ get {\r
+ return _exists;\r
+ }\r
+ set {\r
+ _exists = value;\r
+ }\r
+ }\r
+\r
+\r
+ public string RelativeUrlToFilePath(string currentAccount)\r
+ {\r
+ if (Name==null)\r
+ throw new InvalidOperationException("Name can't be null");\r
+ if (String.IsNullOrWhiteSpace(currentAccount))\r
+ throw new ArgumentNullException("currentAccount");\r
+ Contract.EndContractBlock();\r
+\r
+ if (this == Empty)\r
+ return String.Empty;\r
+\r
+ var unescaped = Uri.UnescapeDataString(Name.ToString());\r
+ var path = unescaped.Replace("/", "\\");\r
+ var pathParts=new Stack<string>();\r
+ pathParts.Push(path);\r
+\r
+ var container = Container.NullSafe(c=>c.ToString());\r
+ if (!String.IsNullOrWhiteSpace(container) && !_knownContainers.Contains(container))\r
+ pathParts.Push(Uri.UnescapeDataString(container));\r
+ if (!currentAccount.Equals(Account, StringComparison.InvariantCultureIgnoreCase))\r
+ {\r
+ if (Account != null)\r
+ {\r
+ pathParts.Push(Account);\r
+ pathParts.Push(FolderConstants.OthersFolder);\r
+ }\r
+ }\r
+ var finalPath=Path.Combine(pathParts.ToArray());\r
+ return finalPath;\r
+ }\r
+\r
+/*\r
+ public override bool TrySetMember(SetMemberBinder binder, object value)\r
+ {\r
+ if (binder.Name.StartsWith("x_object_meta"))\r
+ {\r
+ Tags[binder.Name] = value.ToString();\r
+ }\r
+ return false;\r
+ }\r
+*/\r
+\r
+ public string GetPermissionString()\r
+ {\r
+ if (Permissions==null)\r
+ throw new InvalidOperationException();\r
+ Contract.EndContractBlock();\r
+\r
+ if (Permissions.Count == 0)\r
+ return "~";\r
+ var permissionBuilder = new StringBuilder();\r
+ var groupings = Permissions.GroupBy(pair => pair.Value.Trim(), pair => pair.Key.Trim());\r
+ foreach (var grouping in groupings)\r
+ {\r
+ permissionBuilder.AppendFormat("{0}={1};", grouping.Key, String.Join(",", grouping));\r
+ }\r
+ var permissions = Uri.EscapeDataString(permissionBuilder.ToString().Trim(';'));\r
+ return permissions;\r
+ }\r
+\r
+ public void SetPermissions(string permissions)\r
+ {\r
+ if (String.IsNullOrWhiteSpace(permissions))\r
+ return;\r
+ \r
+ Permissions = PermissionConverter.ParsePermissions(permissions);\r
+ }\r
+\r
+ //The previous values that correspond to a NoModification object\r
+ //have the same account, container and possibly the same folder\r
+ public bool CorrespondsTo(ObjectInfo other)\r
+ {\r
+ return other.Account == this.Account\r
+ && other.Container == this.Container\r
+ && (this.Name == null || other.Name.ToString().StartsWith(this.Name.ToString()));\r
+ }\r
+\r
+ public bool IsWritable(string account)\r
+ {\r
+ //If the Allowed To header has no value, try to determine the Share permissions\r
+ if (AllowedTo == null)\r
+ {\r
+ //If this file has no permissions defined, we can probably write it\r
+ //This case should occur only when the info comes from a listing of the user's own files\r
+ if (Permissions == null || Permissions.Count == 0)\r
+ return true;\r
+ string perms;\r
+\r
+ //Do we have an explicit write share to this account?\r
+ return Permissions.TryGetValue(account, out perms) \r
+ && perms.Equals("write",StringComparison.InvariantCultureIgnoreCase);\r
+ \r
+ }\r
+ //Otherwise return the permissions specified by AllowedTo\r
+ return AllowedTo.Equals("write",StringComparison.InvariantCultureIgnoreCase) ;\r
+ }\r
+\r
+ public ObjectInfo Previous { get; private set; }\r
+\r
+ public bool IsDirectory\r
+ {\r
+ get\r
+ {\r
+ if (Content_Type == null)\r
+ return false;\r
+ if (Content_Type.StartsWith(CONTENT_TYPE_DIRECTORY,StringComparison.InvariantCultureIgnoreCase))\r
+ return true;\r
+ if (Content_Type.StartsWith(CONTENT_TYPE_FOLDER,StringComparison.InvariantCultureIgnoreCase))\r
+ return true;\r
+ return false;\r
+ }\r
+ }\r
+\r
+ public Uri AccountKey\r
+ {\r
+ get { return StorageUri.Combine("../" + Account); }\r
+ }\r
+\r
+ public ObjectInfo SetPrevious(ObjectInfo previous)\r
+ { \r
+ Previous = previous;\r
+ PreviousHash = previous.X_Object_Hash;\r
+ return this;\r
+ }\r
+\r
+ public bool? IsShared\r
+ {\r
+ get\r
+ {\r
+ if (Uri == null || StorageUri == null)\r
+ return null;\r
+ var isShared = !Uri.ToString().StartsWith(StorageUri.ToString());\r
+ return isShared;\r
+ }\r
+ }\r
+ }\r