-using System;
+#region
+/* -----------------------------------------------------------------------
+ * <copyright file="BlockUpdater.cs" company="GRNet">
+ *
+ * Copyright 2011-2012 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.
+ * </copyright>
+ * -----------------------------------------------------------------------
+ */
+#endregion
+using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
public string FilePath { get; private set; }
public string RelativePath { get; private set; }
- public string FragmentsPath { get; private set; }
+ public string CachePath { get; private set; }
public TreeHash ServerHash { get; private set; }
public string TempPath { get; private set; }
+ public bool HasBlocks
+ {
+ get { return _blocks.Count>0; }
+ }
+
+ readonly ConcurrentDictionary<int, string> _blocks = new ConcurrentDictionary<int, string>();
+ readonly ConcurrentDictionary<string, string> _orphanBlocks = new ConcurrentDictionary<string, string>();
+
+ [ContractInvariantMethod]
+ private void Invariants()
+ {
+ Contract.Invariant(Path.IsPathRooted(CachePath));
+ Contract.Invariant(Path.IsPathRooted(FilePath));
+ Contract.Invariant(Path.IsPathRooted(TempPath));
+ Contract.Invariant(!Path.IsPathRooted(RelativePath));
+ Contract.Invariant(_blocks!=null);
+ Contract.Invariant(_orphanBlocks!=null);
+ Contract.Invariant(ServerHash!=null);
+ }
- public BlockUpdater(string fragmentsPath, string filePath, string relativePath,TreeHash serverHash)
+ public BlockUpdater(string cachePath, string filePath, string relativePath,TreeHash serverHash)
{
- if (String.IsNullOrWhiteSpace(fragmentsPath))
- throw new ArgumentNullException("fragmentsPath");
- if (!Path.IsPathRooted(fragmentsPath))
- throw new ArgumentException("The fragmentsPath must be rooted", "fragmentsPath");
+ if (String.IsNullOrWhiteSpace(cachePath))
+ throw new ArgumentNullException("cachePath");
+ if (!Path.IsPathRooted(cachePath))
+ throw new ArgumentException("The cachePath must be rooted", "cachePath");
if (string.IsNullOrWhiteSpace(filePath))
throw new ArgumentNullException("filePath");
throw new ArgumentNullException("serverHash");
Contract.EndContractBlock();
- FragmentsPath=fragmentsPath;
+ CachePath=cachePath;
FilePath = filePath;
RelativePath=relativePath;
ServerHash = serverHash;
//The file will be stored in a temporary location while downloading with an extension .download
- TempPath = Path.Combine(FragmentsPath, RelativePath + ".download");
-
- var directoryPath = Path.GetDirectoryName(TempPath);
+ TempPath = Path.Combine(CachePath, RelativePath + ".download");
+
+ //Need to calculate the directory path because RelativePath may include folders
+ var directoryPath = Path.GetDirectoryName(TempPath);
+ //directoryPath CAN be null if TempPath is a root path
+ if (String.IsNullOrWhiteSpace(directoryPath))
+ throw new ArgumentException("TempPath");
+ //CachePath was absolute so directoryPath is absolute too
+ Contract.Assume(Path.IsPathRooted(directoryPath));
+
if (!Directory.Exists(directoryPath))
Directory.CreateDirectory(directoryPath);
throw new ArgumentNullException("directoryPath");
if (!Path.IsPathRooted(directoryPath))
throw new ArgumentException("The directoryPath must be rooted", "directoryPath");
+ if (ServerHash==null)
+ throw new InvalidOperationException("ServerHash wasn't initialized");
Contract.EndContractBlock();
var fileNamename = Path.GetFileName(FilePath);
//The server truncates nulls before calculating hashes, have to do the same
//Find the last non-null byte, starting from the end
var lastByteIndex = Array.FindLastIndex(buffer, buffer.Length-1, aByte => aByte != 0);
- var binHash = hasher.ComputeHash(buffer,0,lastByteIndex);
- var hash = binHash.ToHashString();
- _orphanBlocks[hash] = orphan;
+ //lastByteIndex may be -1 if the file was empty. We don't want to use that block file
+ if (lastByteIndex >= 0)
+ {
+ var binHash = hasher.ComputeHash(buffer, 0, lastByteIndex);
+ var hash = binHash.ToHashString();
+ _orphanBlocks[hash] = orphan;
+ }
}
}
}
File.Copy(FilePath, TempPath, true);
//Set the size of the file to the size specified in the treehash
- //This will also create an empty file if the file doesn't exist
+ //This will also create an empty file if the file doesn't exist
+
+
SetFileSize(TempPath, ServerHash.Bytes);
//Update the temporary file with the data from the blocks
if (File.Exists(FilePath))
File.Replace(TempPath, FilePath, null, true);
else
+ {
+ var targetDirectory = Path.GetDirectoryName(FilePath);
+ if (!Directory.Exists(targetDirectory))
+ Directory.CreateDirectory(targetDirectory);
File.Move(TempPath, FilePath);
+ }
}
private void ClearBlocks()
return (tempLastWrite < localLastWrite);
}*/
- ConcurrentDictionary<int,string> _blocks=new ConcurrentDictionary<int, string>();
- ConcurrentDictionary<string, string> _orphanBlocks = new ConcurrentDictionary<string, string>();
public bool UseOrphan(int blockIndex, string blockHash)
{
return FileAsync.WriteAllBytes(blockPath, buffer);
}
- /*private Task WriteAsync(string filePath, byte[] buffer, int offset, int count)
- {
- var stream = FileAsync.OpenWrite(filePath);
- try
- {
- stream.Seek(offset, SeekOrigin.Begin);
- var write = stream.WriteAsync(buffer, 0, count);
- return write.ContinueWith(s => stream.Close());
- }
- catch (Exception ex)
- {
- stream.Close();
- return Task.Factory.FromException(ex);
- }
- }*/
+
}
}