2024-02-28 15:45:30 +01:00
// Copyright (C) 2024, The Duplicati Team
// https://duplicati.com, hello@duplicati.com
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
2015-08-21 21:59:12 +02:00
using System ;
using System.Linq ;
using System.Collections.Generic ;
using System.IO ;
namespace Duplicati.CommandLine.RecoveryTool
{
public static class List
{
public static int Run ( List < string > args , Dictionary < string , string > options , Library . Utility . IFilter filter )
{
if ( args . Count != 2 && args . Count != 3 )
{
Console . WriteLine ( "Invalid argument count ({0} expected 2 or 3): {1}{2}" , args . Count , Environment . NewLine , string . Join ( Environment . NewLine , args ));
return 100 ;
}
var folder = Path . GetFullPath ( args [ 1 ]);
if (! Directory . Exists ( folder ))
{
Console . WriteLine ( "Folder not found: {0}" , folder );
return 100 ;
}
Directory . SetCurrentDirectory ( folder );
if ( args . Count == 2 )
{
var times = ParseListFiles ( folder );
2017-12-25 04:12:19 +07:00
foreach ( var v in times . Zip ( Enumerable . Range ( 0 , times . Length ), ( a , b ) => new KeyValuePair < int , DateTime >( b , a . Key )))
2015-08-21 21:59:12 +02:00
Console . WriteLine ( "{0}: {1}" , v . Key , v . Value . ToLocalTime ());
}
else
{
2015-09-05 09:38:52 +02:00
var file = SelectListFile ( args [ 2 ], folder );
2015-08-21 21:59:12 +02:00
2020-07-19 17:41:28 -07:00
var p = Library . Main . Volumes . VolumeBase . ParseFilename ( Path . GetFileName ( file ));
2015-08-21 21:59:12 +02:00
Library . Main . Volumes . VolumeReaderBase . UpdateOptionsFromManifest ( p . CompressionModule , file , new Duplicati . Library . Main . Options ( options ));
2017-12-25 04:12:19 +07:00
foreach ( var f in EnumerateFilesInDList ( file , filter , options ))
2015-08-21 21:59:12 +02:00
Console . WriteLine ( "{0} ({1})" , f . Path , Library . Utility . Utility . FormatSizeString ( f . Size ));
}
return 0 ;
}
public static IEnumerable < Duplicati . Library . Main . Volumes . IFileEntry > EnumerateFilesInDList ( string file , Duplicati . Library . Utility . IFilter filter , Dictionary < string , string > options )
{
2020-07-19 17:41:28 -07:00
var p = Library . Main . Volumes . VolumeBase . ParseFilename ( Path . GetFileName ( file ));
2017-12-25 04:12:19 +07:00
using ( var fs = new System . IO . FileStream ( file , FileMode . Open , FileAccess . Read , FileShare . Read ))
using ( var cm = Library . DynamicLoader . CompressionLoader . GetModule ( p . CompressionModule , fs , Library . Interface . ArchiveMode . Read , options ))
using ( var filesetreader = new Library . Main . Volumes . FilesetVolumeReader ( cm , new Duplicati . Library . Main . Options ( options )))
foreach ( var f in filesetreader . Files )
2015-08-21 21:59:12 +02:00
{
if ( f . Type != Duplicati . Library . Main . FilelistEntryType . File )
continue ;
bool result ;
2019-04-16 21:35:02 -07:00
bool match = filter . Matches ( f . Path , out result , out _ );
2019-01-01 19:27:04 -08:00
if (! match || result )
2015-08-21 21:59:12 +02:00
yield return f ;
}
}
public static string SelectListFile ( string time , string folder )
{
if ( File . Exists ( Path . Combine ( folder , time )))
return Path . Combine ( folder , time );
int index ;
if ( int . TryParse ( time , out index ))
{
var items = ParseListFiles ( folder );
if ( index < 0 || index >= items . Length )
2018-03-12 14:07:11 +01:00
throw new Duplicati . Library . Interface . UserInformationException ( string . Format ( "Valid range for version is 0 to {0}" , items . Length - 1 ), "RecoveryToolInvalidVersion" );
2015-08-21 21:59:12 +02:00
return items [ index ]. Value ;
}
var parsedtime = Library . Utility . Timeparser . ParseTimeInterval ( time , DateTime . Now , true );
var el = (
from n in ParseListFiles ( folder )
2017-12-25 04:12:19 +07:00
let diff = Math . Abs (( n . Key - parsedtime ). TotalSeconds )
orderby diff
select n ). First ();
2015-08-21 21:59:12 +02:00
Console . WriteLine ( "Selected time {0}" , el . Key );
return el . Value ;
}
public static KeyValuePair < DateTime , string >[] ParseListFiles ( string folder )
{
return (
from v in Directory . EnumerateFiles ( folder )
2020-07-19 17:41:28 -07:00
let p = Library . Main . Volumes . VolumeBase . ParseFilename ( Path . GetFileName ( v ))
2015-08-21 21:59:12 +02:00
where p != null && p . FileType == Duplicati . Library . Main . RemoteVolumeType . Files
orderby p . Time descending
select new KeyValuePair < DateTime , string >( p . Time , v )). ToArray ();
}
}
}