Skip to content

Commit

Permalink
v2.5.5083.0
Browse files Browse the repository at this point in the history
  • Loading branch information
ITHitBuild committed Apr 22, 2021
1 parent ca45391 commit 6d55a3f
Show file tree
Hide file tree
Showing 78 changed files with 3,231 additions and 1,725 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using System.IO;
using System.Text;

namespace ITHit.FileSystem.Samples.Common
namespace ITHit.FileSystem.Samples.Common.Windows
{
/// <summary>
/// Thrown when a file can not be locked. For example when a lock-token file is blocked
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using System.Text;
using System.Threading.Tasks;

namespace ITHit.FileSystem.Samples.Common
namespace ITHit.FileSystem.Samples.Common.Windows
{
/// <summary>
/// Custom data stored with a file or folder placeholder, such original file/folder path. Max 4KB.
Expand Down Expand Up @@ -114,11 +114,12 @@ public static bool IsMoved(this PlaceholderItem placeholder)
/// <summary>
/// Returns true if the item was created and must be synched to remote storage.
/// </summary>
/// <param name="virtualDrive">Vitrual drive.</param>
/// <returns>
/// True if the item was created in the user file system and does not exists
/// in the remote storage. False otherwise.
/// </returns>
public static bool IsNew(this PlaceholderItem placeholder)
public static bool IsNew(this PlaceholderItem placeholder, VirtualDriveBase virtualDrive)
{
// ETag absence signals that the item is new.
// However, ETag file may not exists during move operation,
Expand All @@ -128,7 +129,7 @@ public static bool IsNew(this PlaceholderItem placeholder)

string originalPath = placeholder.GetOriginalPath();

bool eTagFileExists = File.Exists(ETag.GetETagFilePath(placeholder.Path));
bool eTagFileExists = File.Exists(virtualDrive.GetETagManager(placeholder.Path).ETagFilePath);

return !eTagFileExists && string.IsNullOrEmpty(originalPath);
}
Expand Down
140 changes: 140 additions & 0 deletions ITHit.FileSystem.Samples.Common.Windows/ETagManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;

namespace ITHit.FileSystem.Samples.Common.Windows
{
/// <summary>
/// Provides method for reading and writing ETags.
/// </summary>
public class ETagManager
{
private readonly string userFileSystemPath;
private readonly string userFileSystemRootPath;
private readonly string serverDataFolderPath;
private readonly ILogger logger;
internal readonly string ETagFilePath;

private const string eTagExt = ".etag";

/// <summary>
/// Creates instance of this class.
/// </summary>
/// <param name="userFileSystemRootPath">User file system root path.</param>
/// <param name="serverDataFolderPath">Folder where ETags are stored.</param>
/// <param name="logger">Logger.</param>
internal ETagManager(string userFileSystemPath, string serverDataFolderPath, string userFileSystemRootPath, ILogger logger)
{
this.userFileSystemPath = userFileSystemPath;
this.userFileSystemRootPath = userFileSystemRootPath;
this.serverDataFolderPath = serverDataFolderPath;
this.logger = logger;
this.ETagFilePath = $"{GetEtagFilePath(userFileSystemPath)}{eTagExt}";
}

/// <summary>
/// Creates or updates ETag associated with the file.
/// </summary>
/// <param name="eTag">ETag.</param>
/// <returns></returns>
public async Task SetETagAsync(string eTag)
{
// Delete ETag file if null or empty string value is passed.
if (string.IsNullOrEmpty(eTag) && File.Exists(ETagFilePath))
{
DeleteETag();
}

Directory.CreateDirectory(Path.GetDirectoryName(ETagFilePath));
await File.WriteAllTextAsync(ETagFilePath, eTag);
}

/// <summary>
/// Gets ETag associated with a file.
/// </summary>
/// <returns>ETag.</returns>
public async Task<string> GetETagAsync()
{
if (!File.Exists(ETagFilePath))
{
return null;
}
return await File.ReadAllTextAsync(ETagFilePath);
}

/// <summary>
/// Moves ETag to a new location.
/// </summary>
/// <param name="userFileSystemNewPath">Path of the file in the user file system to move this Etag to.</param>
internal async Task MoveToAsync(string userFileSystemNewPath)
{
// Move ETag file.
string eTagTargetPath = GetEtagFilePath(userFileSystemNewPath);
string eTagFileTargetPath = $"{eTagTargetPath}{eTagExt}";

// Ensure the target directory exisit, in case we are moving into empty folder or which is offline.
new FileInfo(eTagFileTargetPath).Directory.Create();
File.Move(ETagFilePath, eTagFileTargetPath);

// If this is a folder, move all eTags in this folder.
string eTagSourceFolderPath = GetEtagFilePath(userFileSystemPath);
if (Directory.Exists(eTagSourceFolderPath))
{
Directory.Move(eTagSourceFolderPath, eTagTargetPath);
}
}

/// <summary>
/// Deletes ETag associated with a file.
/// </summary>
internal void DeleteETag()
{
File.Delete(ETagFilePath);

// If this is a folder, delete all eTags in this folder.
string eTagFolderPath = GetEtagFilePath(userFileSystemPath);
if (Directory.Exists(eTagFolderPath))
{
Directory.Delete(eTagFolderPath, true);
}
}

/// <summary>
/// Returns true if the remote storage ETag and user file system ETags are equal. False - otherwise.
/// </summary>
/// <param name="remoteStorageItem">Remote storage item info.</param>
/// <remarks>
/// ETag is updated on the server during every document update and is sent to client with a file.
/// During user file system to remote storage update it is sent back to the remote storage together with a modified content.
/// This ensures the changes in the remote storage are not overwritten if the document on the server is modified.
/// </remarks>
public async Task<bool> ETagEqualsAsync(FileSystemItemMetadata remoteStorageItem)
{
string remoteStorageETag = remoteStorageItem.ETag;
string userFileSystemETag = await GetETagAsync();

if (string.IsNullOrEmpty(remoteStorageETag) && string.IsNullOrEmpty(userFileSystemETag))
{
// We assume the remote storage is not using ETags or no ETag is ssociated with this file/folder.
return true;
}

return remoteStorageETag == userFileSystemETag;
}

/// <summary>
/// Gets ETag file path (without extension).
/// </summary>
/// <param name="userFileSystemPath">Path of the file in user file system to get ETag path for.</param>
private string GetEtagFilePath(string userFileSystemPath)
{
// Get path relative to the virtual root.
string relativePath = userFileSystemPath.TrimEnd(Path.DirectorySeparatorChar).Substring(
userFileSystemRootPath.TrimEnd(Path.DirectorySeparatorChar).Length);

return $"{serverDataFolderPath.TrimEnd(Path.DirectorySeparatorChar)}{relativePath}";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using Windows.Storage;
using FileAttributes = System.IO.FileAttributes;

namespace ITHit.FileSystem.Samples.Common
namespace ITHit.FileSystem.Samples.Common.Windows
{
/// <summary>
/// Provides file system operations. Helps determining file and folder existence and creating file and folder items.
Expand Down Expand Up @@ -47,6 +47,11 @@ public static bool Exists(string path)
return File.Exists(path) || Directory.Exists(path);
}

public static FileSystemItemTypeEnum GetItemType(string path)
{
return FsPath.IsFile(path) ? FileSystemItemTypeEnum.File : FileSystemItemTypeEnum.Folder;
}

/// <summary>
/// Returns true if the path point to a recycle bin folder.
/// </summary>
Expand Down Expand Up @@ -124,7 +129,7 @@ private static bool IsMsOfficeTemp(string path)
return (Path.GetFileName(path).StartsWith('~') && Path.GetExtension(path).Equals(".tmp", StringComparison.InvariantCultureIgnoreCase)) // Word temp files
|| (Path.GetFileName(path).StartsWith("ppt") && Path.GetExtension(path).Equals(".tmp", StringComparison.InvariantCultureIgnoreCase)) // PowerPoint temp files
|| (string.IsNullOrEmpty(Path.GetExtension(path)) && (Path.GetFileName(path).Length == 8) && File.Exists(path)) // Excel temp files
|| ((Path.GetFileNameWithoutExtension(path).Length == 8) && Path.GetExtension(path).Equals(".tmp", StringComparison.InvariantCultureIgnoreCase)); // Excel temp files
|| ( ((Path.GetFileNameWithoutExtension(path).Length == 8) || (Path.GetFileNameWithoutExtension(path).Length == 7)) && Path.GetExtension(path).Equals(".tmp", StringComparison.InvariantCultureIgnoreCase)); // Excel temp files
}

/// <summary>
Expand Down Expand Up @@ -246,6 +251,16 @@ public static string Size(string path)
return null;
}

return FormatBytes(length);
}

/// <summary>
/// Formats bytes to string.
/// </summary>
/// <param name="length">Bytes to format.</param>
/// <returns>Human readable bytes string.</returns>
public static string FormatBytes(long length)
{
string[] suf = { "b ", "KB", "MB", "GB", "TB", "PB", "EB" };
if (length == 0)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<Description>Contains functionality common for all Windows Virtual Drive samples.</Description>
<Authors>IT Hit LTD.</Authors>
<Product>IT Hit User File System</Product>
<Copyright>IT Hit LTD.</Copyright>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="log4net" Version="2.0.12" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0" />
<PackageReference Include="Microsoft.Windows.SDK.Contracts" Version="10.0.19041.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\ITHit.FileSystem\ITHit.FileSystem.Windows\ITHit.FileSystem.Windows.csproj" />
<ProjectReference Include="..\ITHit.FileSystem.Samples.Common\ITHit.FileSystem.Samples.Common.csproj" />
</ItemGroup>
</Project>
Loading

0 comments on commit 6d55a3f

Please sign in to comment.