Skip to content

Commit

Permalink
Merge branch 'stable'
Browse files Browse the repository at this point in the history
* stable:
  (maint) formatting
  (GH-313) Snapshot detection of locked files
  (maint) formatting

Conflicts:
	src/chocolatey/infrastructure/filesystem/DotNetFileSystem.cs
  • Loading branch information
ferventcoder committed Jun 8, 2015
2 parents 062b97d + 09765f6 commit 7b96acc
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="infrastructure.app\services\FilesServiceSpecs.cs" />
<Compile Include="infrastructure\commands\CommandExecutorSpecs.cs" />
<Compile Include="infrastructure\cryptography\CrytpoHashProviderSpecs.cs" />
<Compile Include="infrastructure\filesystem\DotNetFileSystemSpecs.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
namespace chocolatey.tests.integration.infrastructure.app.services
{
using System;
using System.IO;
using System.Linq;
using Moq;
using Should;
using chocolatey.infrastructure.app;
using chocolatey.infrastructure.app.configuration;
using chocolatey.infrastructure.app.domain;
using chocolatey.infrastructure.app.services;
using chocolatey.infrastructure.commands;
using chocolatey.infrastructure.cryptography;
using chocolatey.infrastructure.filesystem;
using chocolatey.infrastructure.results;
using chocolatey.infrastructure.services;

public class FilesServiceSpecs
{
public abstract class FilesServiceSpecsBase : TinySpec
{
protected FilesService Service;
protected IFileSystem FileSystem = new DotNetFileSystem();

public override void Context()
{
Service = new FilesService(new XmlService(FileSystem), FileSystem, new CrytpoHashProvider(FileSystem, CryptoHashProviderType.Md5));
}
}

public class when_FilesService_encounters_locked_files : FilesServiceSpecsBase
{
private PackageFiles _result;
private readonly ChocolateyConfiguration _config = new ChocolateyConfiguration();
private PackageResult _packageResult;
private string _contextPath;
private string _theLockedFile;
private FileStream _fileStream;

public override void Context()
{
base.Context();
_contextPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "infrastructure", "filesystem");
_theLockedFile = Path.Combine(_contextPath, "Slipsum.txt");
_packageResult = new PackageResult("bob", "1.2.3", FileSystem.get_directory_name(_theLockedFile));
MockLogger.LogMessagesToConsole = true;

_fileStream = new FileStream(_theLockedFile, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
}

public override void AfterObservations()
{
base.AfterObservations();
_fileStream.Close();
}

public override void Because()
{
_result = Service.capture_package_files(_packageResult, _config);
}

[Fact]
public void should_not_error()
{
//nothing to see here
}

[Fact]
public void should_log_a_warning()
{
MockLogger.Verify(l => l.Warn(It.IsAny<string>()), Times.AtLeastOnce);
}

[Fact]
public void should_log_a_warning_about_locked_files()
{
bool lockedFiles = false;
foreach (var message in MockLogger.MessagesFor(LogLevel.Warn).or_empty_list_if_null())
{
if (message.Contains("The process cannot access the file")) lockedFiles = true;
}

lockedFiles.ShouldBeTrue();
}

[Fact]
public void should_return_a_special_code_for_locked_files()
{
_result.Files.FirstOrDefault(x => x.Path == _theLockedFile).Checksum.ShouldEqual(ApplicationParameters.HashProviderFileLocked);
}
}
}
}
1 change: 1 addition & 0 deletions src/chocolatey/infrastructure.app/ApplicationParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public static class Environment
public static readonly string[] ConfigFileExtensions = new string[] {".autoconf",".config",".conf",".cfg",".jsc",".json",".jsonp",".ini",".xml",".yaml"};

public static string HashProviderFileTooBig = "UnableToDetectChanges_FileTooBig";
public static string HashProviderFileLocked = "UnableToDetectChanges_FileLocked";

public static class Tools
{
Expand Down
1 change: 0 additions & 1 deletion src/chocolatey/infrastructure.app/services/FilesService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ public PackageFiles capture_package_files(string directory, ChocolateyConfigurat
return packageFiles;
}


public PackageFile get_package_file(string file)
{
var hash = _hashProvider.hash_file(file);
Expand Down
9 changes: 8 additions & 1 deletion src/chocolatey/infrastructure.app/services/NugetService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -969,11 +969,18 @@ public void remove_installation_files(IPackage removedPackage, ChocolateyPackage
foreach (var file in _fileSystem.get_files(installDir, "*.*", SearchOption.AllDirectories).or_empty_list_if_null())
{
var fileSnapshot = pkgInfo.FilesSnapshot.Files.FirstOrDefault(f => f.Path.is_equal_to(file));
if (fileSnapshot != null && fileSnapshot.Checksum == _filesService.get_package_file(file).Checksum)
if (fileSnapshot == null) continue;

if (fileSnapshot.Checksum == _filesService.get_package_file(file).Checksum)
{
FaultTolerance.try_catch_with_logging_exception(
() => _fileSystem.delete_file(file),
"Error deleting file");
}

if (fileSnapshot.Checksum == ApplicationParameters.HashProviderFileLocked)
{
this.Log().Warn(()=> "Snapshot for '{0}' was attempted when file was locked.{1} Please inspect and manually remove file{1} at '{2}'".format_with(_fileSystem.get_file_name(file), Environment.NewLine, _fileSystem.get_directory_name(file)));
}
}
}
Expand Down
27 changes: 24 additions & 3 deletions src/chocolatey/infrastructure/cryptography/CrytpoHashProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,23 @@
namespace chocolatey.infrastructure.cryptography
{
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using adapters;
using app;
using filesystem;
using platforms;
using Environment = System.Environment;
using HashAlgorithm = adapters.HashAlgorithm;


public sealed class CrytpoHashProvider : IHashProvider
{
private readonly IFileSystem _fileSystem;
private readonly IHashAlgorithm _hashAlgorithm;
private const int ERROR_LOCK_VIOLATION = 33;
private const int ERROR_SHARING_VIOLATION = 32;

public CrytpoHashProvider(IFileSystem fileSystem, CryptoHashProviderType providerType)
{
Expand Down Expand Up @@ -69,11 +73,28 @@ public string hash_file(string filePath)
}
catch (IOException ex)
{
this.Log().Warn(() => "Error computing hash for '{0}'{1} Captured error:{1} {2}".format_with(filePath, Environment.NewLine, ex.Message));
this.Log().Warn(() => "Error computing hash for '{0}'{1} Hash will be special code for locked file or file too big instead.{1} Captured error:{1} {2}".format_with(filePath, Environment.NewLine, ex.Message));

if (file_is_locked(ex))
{
return ApplicationParameters.HashProviderFileLocked;
}

//IO.IO_FileTooLong2GB (over Int32.MaxValue)
return ApplicationParameters.HashProviderFileTooBig;
return "UnableToDetectChanges_FileTooBig";
}
}

private static bool file_is_locked(Exception exception)
{
var errorCode = 0;

var hresult = Marshal.GetHRForException(exception);

errorCode = hresult & ((1 << 16) - 1);

return errorCode == ERROR_SHARING_VIOLATION || errorCode == ERROR_LOCK_VIOLATION;
}

}
}
16 changes: 14 additions & 2 deletions src/chocolatey/infrastructure/filesystem/DotNetFileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -256,11 +256,23 @@ public void copy_file(string sourceFilePath, string destinationFilePath, bool ov

public bool copy_file_unsafe(string sourceFilePath, string destinationFilePath, bool overwriteExisting)
{
if (Platform.get_platform() != PlatformType.Windows)
{
copy_file(sourceFilePath, destinationFilePath, overwriteExisting);
return true;
}

this.Log().Debug(() => "Attempting to copy from \"{0}\" to \"{1}\".".format_with(sourceFilePath, destinationFilePath));
create_directory_if_not_exists(get_directory_name(destinationFilePath), ignoreError: true);

//Private Declare Function apiCopyFile Lib "kernel32" Alias "CopyFileA" _
int success = CopyFileW(sourceFilePath, destinationFilePath, overwriteExisting ? 0 : 1);
return success == 0;
//if (success == 0)
//{
// var error = Marshal.GetLastWin32Error();

//}
return success != 0;
}

// ReSharper disable InconsistentNaming
Expand All @@ -275,7 +287,7 @@ _In_ BOOL bFailIfExists
);
*/

[DllImport("kernel32")]
[DllImport("kernel32", SetLastError = true)]
private static extern int CopyFileW(string lpExistingFileName, string lpNewFileName, int bFailIfExists);

// ReSharper restore InconsistentNaming
Expand Down

0 comments on commit 7b96acc

Please sign in to comment.