Allow to skip volumes in fs ls, use same logic in fs extract.

This commit is contained in:
2026-04-13 12:31:17 +01:00
parent 75b6c32723
commit 189faed554
5 changed files with 2003 additions and 1898 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1128,6 +1128,9 @@
</data>
<data name="Extract_only_from_specified_volume_number" xml:space="preserve">
<value>Extraer solo del número de volumen especificado (indexado desde 0). Si no se especifica, extrae de todos los volúmenes.</value>
</data>
<data name="List_only_specified_volume_number" xml:space="preserve">
<value>Listar solo el número de volumen especificado (indexado desde 0). Si no se especifica, lista todos los volúmenes.</value>
</data>
<data name="Volume_number_0_not_found_only_1_volumes_found" xml:space="preserve">
<value>[red]No se encontró el volumen número [orange3]{0}[/]. Solo se encontraron [orange3]{1}[/] volúmenes.[/]</value>

View File

@@ -376,6 +376,9 @@ In you are unsure, please press N to not continue.</value>
</data>
<data name="Extract_only_from_specified_volume_number" xml:space="preserve">
<value>Extract only from the specified volume number (0-indexed). If not specified, extracts from all volumes.</value>
</data>
<data name="List_only_specified_volume_number" xml:space="preserve">
<value>List only the specified volume number (0-indexed). If not specified, lists all volumes.</value>
</data>
<data name="Volume_number_0_not_found_only_1_volumes_found" xml:space="preserve">
<value>[red]Volume number [orange3]{0}[/] not found. Only [orange3]{1}[/] volumes were found.[/]</value>

View File

@@ -232,8 +232,8 @@ sealed class ExtractFilesCommand : Command<ExtractFilesCommand.Settings>
for(var i = 0; i < partitions.Count; i++)
{
AaruLogging.WriteLine();
AaruLogging.WriteLine($"[bold]{string.Format(UI.Partition_0, partitions[i].Sequence)}[/]");
// Skip partitions if we've already found and processed the requested volume
if(settings.Volume.HasValue && volumeCounter > settings.Volume.Value) break;
List<string> idPlugins = null;
@@ -244,11 +244,51 @@ sealed class ExtractFilesCommand : Command<ExtractFilesCommand.Settings>
});
if(idPlugins.Count == 0)
AaruLogging.WriteLine(UI.Filesystem_not_identified);
{
if(!settings.Volume.HasValue)
{
AaruLogging.WriteLine();
AaruLogging.WriteLine($"[bold]{string.Format(UI.Partition_0, partitions[i].Sequence)}[/]");
AaruLogging.WriteLine(UI.Filesystem_not_identified);
}
}
else
{
ErrorNumber error = ErrorNumber.InvalidArgument;
// Check if any identified plugin is a readable filesystem
var hasReadOnlyFs = false;
foreach(string pluginName in idPlugins)
{
if(plugins.ReadOnlyFilesystems.ContainsKey(pluginName))
{
hasReadOnlyFs = true;
break;
}
}
// Count this as a volume if it has a readable filesystem
// If targeting a specific volume and this isn't it, skip entirely
if(hasReadOnlyFs)
{
if(settings.Volume.HasValue && settings.Volume.Value != volumeCounter)
{
volumeCounter++;
continue;
}
volumeCounter++;
}
if(!settings.Volume.HasValue)
{
AaruLogging.WriteLine();
AaruLogging.WriteLine($"[bold]{string.Format(UI.Partition_0, partitions[i].Sequence)}[/]");
}
if(idPlugins.Count > 1)
{
AaruLogging.WriteLine($"[italic]{string.Format(UI.Identified_by_0_plugins, idPlugins.Count)
@@ -277,19 +317,15 @@ sealed class ExtractFilesCommand : Command<ExtractFilesCommand.Settings>
if(error == ErrorNumber.NoError)
{
if(!settings.Volume.HasValue || settings.Volume.Value == volumeCounter)
{
string volumeName = string.IsNullOrEmpty(fs.Metadata.VolumeName)
? "NO NAME"
: fs.Metadata.VolumeName;
string volumeName = string.IsNullOrEmpty(fs.Metadata.VolumeName)
? "NO NAME"
: fs.Metadata.VolumeName;
volumeName = volumeName.Replace('/', '_').Replace('\\', '_');
volumeName = volumeName.Replace('/', '_').Replace('\\', '_');
ExtractFilesInDir("/", fs, volumeName, settings.OutputDir, settings.Xattrs);
}
ExtractFilesInDir("/", fs, volumeName, settings.OutputDir, settings.Xattrs);
Statistics.AddFilesystem(fs.Metadata.Type);
volumeCounter++;
}
else
AaruLogging.Error(UI.Unable_to_mount_volume_error_0, error.ToString());
@@ -301,6 +337,12 @@ sealed class ExtractFilesCommand : Command<ExtractFilesCommand.Settings>
if(fs is null) continue;
if(settings.Volume.HasValue)
{
AaruLogging.WriteLine();
AaruLogging.WriteLine($"[bold]{string.Format(UI.Partition_0, partitions[i].Sequence)}[/]");
}
AaruLogging.WriteLine($"[bold]{string.Format(UI.Identified_by_0, fs.Name)}[/]");
Core.Spectre.ProgressSingleSpinner(ctx =>
@@ -316,19 +358,15 @@ sealed class ExtractFilesCommand : Command<ExtractFilesCommand.Settings>
if(error == ErrorNumber.NoError)
{
if(!settings.Volume.HasValue || settings.Volume.Value == volumeCounter)
{
string volumeName = string.IsNullOrEmpty(fs.Metadata.VolumeName)
? "NO NAME"
: fs.Metadata.VolumeName;
string volumeName = string.IsNullOrEmpty(fs.Metadata.VolumeName)
? "NO NAME"
: fs.Metadata.VolumeName;
volumeName = volumeName.Replace('/', '_').Replace('\\', '_');
volumeName = volumeName.Replace('/', '_').Replace('\\', '_');
ExtractFilesInDir("/", fs, volumeName, settings.OutputDir, settings.Xattrs);
}
ExtractFilesInDir("/", fs, volumeName, settings.OutputDir, settings.Xattrs);
Statistics.AddFilesystem(fs.Metadata.Type);
volumeCounter++;
}
else
AaruLogging.Error(UI.Unable_to_mount_volume_error_0, error.ToString());
@@ -337,9 +375,11 @@ sealed class ExtractFilesCommand : Command<ExtractFilesCommand.Settings>
}
if(settings.Volume.HasValue && settings.Volume.Value >= volumeCounter)
{
AaruLogging.Error(UI.Volume_number_0_not_found_only_1_volumes_found,
settings.Volume.Value,
volumeCounter);
}
}
catch(Exception ex)
{

View File

@@ -65,6 +65,7 @@ sealed class LsCommand : Command<LsCommand.Settings>
AaruLogging.Debug(MODULE_NAME, "--input={0}", Markup.Escape(settings.ImagePath ?? ""));
AaruLogging.Debug(MODULE_NAME, "--options={0}", Markup.Escape(settings.Options ?? ""));
AaruLogging.Debug(MODULE_NAME, "--verbose={0}", settings.Verbose);
AaruLogging.Debug(MODULE_NAME, "--volume={0}", settings.Volume?.ToString() ?? "all");
Statistics.AddCommand("ls");
IFilter inputFilter = null;
@@ -207,10 +208,12 @@ sealed class LsCommand : Command<LsCommand.Settings>
AaruLogging.WriteLine(UI._0_partitions_found, partitions.Count);
var volumeCounter = 0;
for(var i = 0; i < partitions.Count; i++)
{
AaruLogging.WriteLine();
AaruLogging.WriteLine($"[bold]{string.Format(UI.Partition_0, partitions[i].Sequence)}[/]");
// Skip partitions if we've already found and listed the requested volume
if(settings.Volume.HasValue && volumeCounter > settings.Volume.Value) break;
List<string> idPlugins = null;
@@ -221,11 +224,51 @@ sealed class LsCommand : Command<LsCommand.Settings>
});
if(idPlugins.Count == 0)
AaruLogging.WriteLine(UI.Filesystem_not_identified);
{
if(!settings.Volume.HasValue)
{
AaruLogging.WriteLine();
AaruLogging.WriteLine($"[bold]{string.Format(UI.Partition_0, partitions[i].Sequence)}[/]");
AaruLogging.WriteLine(UI.Filesystem_not_identified);
}
}
else
{
ErrorNumber error = ErrorNumber.InvalidArgument;
// Check if any identified plugin is a readable filesystem
var hasReadOnlyFs = false;
foreach(string pluginName in idPlugins)
{
if(plugins.ReadOnlyFilesystems.ContainsKey(pluginName))
{
hasReadOnlyFs = true;
break;
}
}
// Count this as a volume if it has a readable filesystem
// If targeting a specific volume and this isn't it, skip entirely
if(hasReadOnlyFs)
{
if(settings.Volume.HasValue && settings.Volume.Value != volumeCounter)
{
volumeCounter++;
continue;
}
volumeCounter++;
}
if(!settings.Volume.HasValue)
{
AaruLogging.WriteLine();
AaruLogging.WriteLine($"[bold]{string.Format(UI.Partition_0, partitions[i].Sequence)}[/]");
}
if(idPlugins.Count > 1)
{
AaruLogging.WriteLine($"[italic]{string.Format(UI.Identified_by_0_plugins, idPlugins.Count)
@@ -267,6 +310,12 @@ sealed class LsCommand : Command<LsCommand.Settings>
if(fs is null) continue;
if(settings.Volume.HasValue)
{
AaruLogging.WriteLine();
AaruLogging.WriteLine($"[bold]{string.Format(UI.Partition_0, partitions[i].Sequence)}[/]");
}
AaruLogging.WriteLine($"[bold]{string.Format(UI.Identified_by_0, fs.Name)}[/]");
Core.Spectre.ProgressSingleSpinner(ctx =>
@@ -455,6 +504,10 @@ sealed class LsCommand : Command<LsCommand.Settings>
[CommandOption("-n|--namespace")]
[DefaultValue(null)]
public string Namespace { get; init; }
[LocalizedDescription(nameof(UI.List_only_specified_volume_number))]
[CommandOption("--volume")]
[DefaultValue(null)]
public int? Volume { get; init; }
[LocalizedDescription(nameof(UI.Media_image_path))]
[CommandArgument(0, "<image-path>")]
public string ImagePath { get; init; }