@ -18,11 +18,32 @@ namespace NzbDrone.Mono.Test.DiskProviderTests
[Platform(Exclude = "Win")]
public class DiskProviderFixture : DiskProviderFixtureBase < DiskProvider >
{
private string _tempPath ;
public DiskProviderFixture ( )
{
PosixOnly ( ) ;
}
[TearDown]
public void MonoDiskProviderFixtureTearDown ( )
{
// Give ourselves back write permissions so we can delete it
if ( _tempPath ! = null )
{
if ( Directory . Exists ( _tempPath ) )
{
Syscall . chmod ( _tempPath , FilePermissions . S_IRWXU ) ;
}
else if ( File . Exists ( _tempPath ) )
{
Syscall . chmod ( _tempPath , FilePermissions . S_IRUSR | FilePermissions . S_IWUSR ) ;
}
_tempPath = null ;
}
}
protected override void SetWritePermissions ( string path , bool writable )
{
if ( Environment . UserName = = "root" )
@ -30,16 +51,41 @@ namespace NzbDrone.Mono.Test.DiskProviderTests
Assert . Inconclusive ( "Need non-root user to test write permissions." ) ;
}
SetWritePermissionsInternal ( path , writable , false ) ;
}
protected void SetWritePermissionsInternal ( string path , bool writable , bool setgid )
{
// Remove Write permissions, we're still owner so we can clean it up, but we'll have to do that explicitly.
var entry = UnixFileSystemInfo . GetFileSystemEntry ( path ) ;
Stat stat ;
Syscall . stat ( path , out stat ) ;
FilePermissions mode = stat . st_mode ;
if ( writable )
{
entry . FileAccessPermissions | = FileAccessPermissions . UserWrite | FileAccessPermissions . GroupWrite | FileAccessPermissions . OtherWrite ;
mode | = FilePermissions . S_IWUSR | FilePermissions . S_IWGRP | FilePermissions . S_IWOTH ;
}
else
{
mode & = ~ ( FilePermissions . S_IWUSR | FilePermissions . S_IWGRP | FilePermissions . S_IWOTH ) ;
}
if ( setgid )
{
mode | = FilePermissions . S_ISGID ;
}
else
{
entry . FileAccessPermissions & = ~ ( FileAccessPermissions . UserWrite | FileAccessPermissions . GroupWrite | FileAccessPermissions . OtherWrite ) ;
mode & = ~ FilePermissions . S_ISGID ;
}
if ( stat . st_mode ! = mode )
{
if ( Syscall . chmod ( path , mode ) < 0 )
{
var error = Stdlib . GetLastError ( ) ;
throw new LinuxPermissionsException ( "Error setting group: " + error ) ;
}
}
}
@ -165,24 +211,25 @@ namespace NzbDrone.Mono.Test.DiskProviderTests
var tempFile = GetTempFilePath ( ) ;
File . WriteAllText ( tempFile , "File1" ) ;
SetWritePermissions ( tempFile , false ) ;
SetWritePermissionsInternal ( tempFile , false , false ) ;
_tempPath = tempFile ;
// Verify test setup
Syscall . stat ( tempFile , out var fileStat ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "0444" ) ;
Subject . SetPermissions ( tempFile , " 644" ) ;
Subject . SetPermissions ( tempFile , " 755", null ) ;
Syscall . stat ( tempFile , out fileStat ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "0644" ) ;
Subject . SetPermissions ( tempFile , "0 644" ) ;
Subject . SetPermissions ( tempFile , "0 755", null ) ;
Syscall . stat ( tempFile , out fileStat ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "0644" ) ;
if ( OsInfo . Os ! = Os . Bsd )
{
// This is not allowed on BSD
Subject . SetPermissions ( tempFile , "1 664" ) ;
Subject . SetPermissions ( tempFile , "1 775", null ) ;
Syscall . stat ( tempFile , out fileStat ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "1664" ) ;
}
@ -194,62 +241,118 @@ namespace NzbDrone.Mono.Test.DiskProviderTests
var tempPath = GetTempFilePath ( ) ;
Directory . CreateDirectory ( tempPath ) ;
SetWritePermissions ( tempPath , false ) ;
SetWritePermissionsInternal ( tempPath , false , false ) ;
_tempPath = tempPath ;
// Verify test setup
Syscall . stat ( tempPath , out var fileStat ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "0555" ) ;
Subject . SetPermissions ( tempPath , " 644" ) ;
Subject . SetPermissions ( tempPath , " 755", null ) ;
Syscall . stat ( tempPath , out fileStat ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "0755" ) ;
Subject . SetPermissions ( tempPath , " 0644" ) ;
Subject . SetPermissions ( tempPath , " 775", null ) ;
Syscall . stat ( tempPath , out fileStat ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "07 5 5") ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "07 7 5") ;
Subject . SetPermissions ( tempPath , " 1664" ) ;
Subject . SetPermissions ( tempPath , " 750", null ) ;
Syscall . stat ( tempPath , out fileStat ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( " 1775 ") ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( " 0750 ") ;
Subject . SetPermissions ( tempPath , " 775" ) ;
Subject . SetPermissions ( tempPath , " 051", null ) ;
Syscall . stat ( tempPath , out fileStat ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "0775" ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "0051" ) ;
}
[Test]
public void should_preserve_setgid_on_set_folder_permissions ( )
{
var tempPath = GetTempFilePath ( ) ;
Subject . SetPermissions ( tempPath , "640" ) ;
Directory . CreateDirectory ( tempPath ) ;
SetWritePermissionsInternal ( tempPath , false , true ) ;
_tempPath = tempPath ;
// Verify test setup
Syscall . stat ( tempPath , out var fileStat ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "2555" ) ;
Subject . SetPermissions ( tempPath , "755" , null ) ;
Syscall . stat ( tempPath , out fileStat ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "0750" ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( " 2755 ") ;
Subject . SetPermissions ( tempPath , "0041" ) ;
Subject . SetPermissions ( tempPath , " 775", null ) ;
Syscall . stat ( tempPath , out fileStat ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "0051" ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( " 2775 ") ;
// reinstate sane permissions so fokder can be cleaned up
Subject . SetPermissions ( tempPath , "775" ) ;
Subject . SetPermissions ( tempPath , "750" , null ) ;
Syscall . stat ( tempPath , out fileStat ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "0775" ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "2750" ) ;
Subject . SetPermissions ( tempPath , "051" , null ) ;
Syscall . stat ( tempPath , out fileStat ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "2051" ) ;
}
[Test]
public void IsValidFilePermissionMask_should_return_correct ( )
public void should_clear_setgid_on_set_folder_permissions ( )
{
// Files may not be executable
Subject . IsValidFilePermissionMask ( "0777" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFilePermissionMask ( "0544" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFilePermissionMask ( "0454" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFilePermissionMask ( "0445" ) . Should ( ) . BeFalse ( ) ;
var tempPath = GetTempFilePath ( ) ;
Directory . CreateDirectory ( tempPath ) ;
SetWritePermissionsInternal ( tempPath , false , true ) ;
_tempPath = tempPath ;
// Verify test setup
Syscall . stat ( tempPath , out var fileStat ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "2555" ) ;
Subject . SetPermissions ( tempPath , "0755" , null ) ;
Syscall . stat ( tempPath , out fileStat ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "0755" ) ;
Subject . SetPermissions ( tempPath , "0775" , null ) ;
Syscall . stat ( tempPath , out fileStat ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "0775" ) ;
Subject . SetPermissions ( tempPath , "0750" , null ) ;
Syscall . stat ( tempPath , out fileStat ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "0750" ) ;
Subject . SetPermissions ( tempPath , "0051" , null ) ;
Syscall . stat ( tempPath , out fileStat ) ;
NativeConvert . ToOctalPermissionString ( fileStat . st_mode ) . Should ( ) . Be ( "0051" ) ;
}
[Test]
public void IsValidFolderPermissionMask_should_return_correct ( )
{
// No special bits should be set
Subject . IsValidFilePermissionMask ( "1644" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFilePermissionMask ( "2644" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFilePermissionMask ( "4644" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFilePermissionMask ( "7644" ) . Should ( ) . BeFalse ( ) ;
// Files should be readable and writeable by owner
Subject . IsValidFilePermissionMask ( "0400" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFilePermissionMask ( "0000" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFilePermissionMask ( "0200" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFilePermissionMask ( "0600" ) . Should ( ) . BeTrue ( ) ;
Subject . IsValidFolderPermissionMask ( "1755" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFolderPermissionMask ( "2755" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFolderPermissionMask ( "4755" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFolderPermissionMask ( "7755" ) . Should ( ) . BeFalse ( ) ;
// Folder should be readable and writeable by owner
Subject . IsValidFolderPermissionMask ( "000" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFolderPermissionMask ( "100" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFolderPermissionMask ( "200" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFolderPermissionMask ( "300" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFolderPermissionMask ( "400" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFolderPermissionMask ( "500" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFolderPermissionMask ( "600" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFolderPermissionMask ( "700" ) . Should ( ) . BeTrue ( ) ;
// Folder should be readable and writeable by owner
Subject . IsValidFolderPermissionMask ( "0000" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFolderPermissionMask ( "0100" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFolderPermissionMask ( "0200" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFolderPermissionMask ( "0300" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFolderPermissionMask ( "0400" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFolderPermissionMask ( "0500" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFolderPermissionMask ( "0600" ) . Should ( ) . BeFalse ( ) ;
Subject . IsValidFolderPermissionMask ( "0700" ) . Should ( ) . BeTrue ( ) ;
}
}
}