diff --git a/src/PSProxmoxVE.Core/Models/Vms/OvfMetadata.cs b/src/PSProxmoxVE.Core/Models/Vms/OvfMetadata.cs index ccc10d5..cded707 100644 --- a/src/PSProxmoxVE.Core/Models/Vms/OvfMetadata.cs +++ b/src/PSProxmoxVE.Core/Models/Vms/OvfMetadata.cs @@ -78,144 +78,27 @@ namespace PSProxmoxVE.Core.Models.Vms } /// - /// Extracts the .ovf XML content from a TAR archive. - /// Uses System.Formats.Tar on .NET 9+ and manual TAR parsing on older frameworks. + /// Extracts the .ovf XML content from a TAR archive using SharpCompress. /// private static string? ExtractOvfFromTar(string tarPath) { -#if NET7_0_OR_GREATER - return ExtractOvfUsingSystemTar(tarPath); -#else - return ExtractOvfManualTar(tarPath); -#endif - } - -#if NET7_0_OR_GREATER - private static string? ExtractOvfUsingSystemTar(string tarPath) - { using var stream = File.OpenRead(tarPath); - using var reader = new System.Formats.Tar.TarReader(stream); + using var reader = SharpCompress.Readers.ReaderFactory.Open(stream); - System.Formats.Tar.TarEntry? entry; - while ((entry = reader.GetNextEntry()) != null) + while (reader.MoveToNextEntry()) { - if (entry.Name.EndsWith(".ovf", StringComparison.OrdinalIgnoreCase) && entry.DataStream != null) + if (!reader.Entry.IsDirectory && + reader.Entry.Key != null && + reader.Entry.Key.EndsWith(".ovf", StringComparison.OrdinalIgnoreCase)) { - using var sr = new StreamReader(entry.DataStream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 4096, leaveOpen: true); + using var entryStream = reader.OpenEntryStream(); + using var sr = new StreamReader(entryStream, Encoding.UTF8); return sr.ReadToEnd(); } } return null; } -#else - /// - /// Minimal TAR reader for netstandard2.0/net48. - /// TAR format: 512-byte header per file, name at offset 0 (100 bytes), size at offset 124 (12 bytes octal), - /// followed by file data padded to 512-byte boundary. - /// - private static string? ExtractOvfManualTar(string tarPath) - { - using var stream = File.OpenRead(tarPath); - var header = new byte[512]; - - while (true) - { - var bytesRead = ReadFull(stream, header, 0, 512); - if (bytesRead < 512) - break; - - // Check for end-of-archive (two zero blocks) - if (IsZeroBlock(header)) - break; - - // Extract name (offset 0, 100 bytes) - var name = ReadNullTerminatedString(header, 0, 100); - - // Extract size (offset 124, 12 bytes, octal) - var sizeStr = ReadNullTerminatedString(header, 124, 12).Trim(); - long size = 0; - if (!string.IsNullOrEmpty(sizeStr)) - { - try { size = Convert.ToInt64(sizeStr, 8); } - catch { size = 0; } - } - - // Check for GNU/POSIX long name prefix (offset 345, 155 bytes) - var prefix = ReadNullTerminatedString(header, 345, 155); - if (!string.IsNullOrEmpty(prefix)) - name = prefix + "/" + name; - - if (name.EndsWith(".ovf", StringComparison.OrdinalIgnoreCase) && size > 0) - { - var data = new byte[size]; - var dataRead = ReadFull(stream, data, 0, (int)size); - if (dataRead < size) - throw new InvalidOperationException("Unexpected end of OVA archive while reading .ovf entry."); - return Encoding.UTF8.GetString(data); - } - - // Skip past the file data (padded to 512-byte boundary) - if (size > 0) - { - var paddedSize = ((size + 511) / 512) * 512; - SkipBytes(stream, paddedSize); - } - } - - return null; - } - - private static int ReadFull(Stream stream, byte[] buffer, int offset, int count) - { - int totalRead = 0; - while (totalRead < count) - { - int read = stream.Read(buffer, offset + totalRead, count - totalRead); - if (read == 0) break; - totalRead += read; - } - return totalRead; - } - - private static void SkipBytes(Stream stream, long count) - { - if (stream.CanSeek) - { - stream.Seek(count, SeekOrigin.Current); - } - else - { - var buf = new byte[Math.Min(count, 8192)]; - long remaining = count; - while (remaining > 0) - { - int toRead = (int)Math.Min(remaining, buf.Length); - int read = stream.Read(buf, 0, toRead); - if (read == 0) break; - remaining -= read; - } - } - } - - private static bool IsZeroBlock(byte[] block) - { - for (int i = 0; i < block.Length; i++) - { - if (block[i] != 0) return false; - } - return true; - } - - private static string ReadNullTerminatedString(byte[] buffer, int offset, int maxLength) - { - int end = offset; - int limit = offset + maxLength; - while (end < limit && buffer[end] != 0) - end++; - return Encoding.ASCII.GetString(buffer, offset, end - offset); - } -#endif /// /// Parses OVF XML and extracts VM metadata. diff --git a/src/PSProxmoxVE.Core/PSProxmoxVE.Core.csproj b/src/PSProxmoxVE.Core/PSProxmoxVE.Core.csproj index 6b52216..0e7c981 100644 --- a/src/PSProxmoxVE.Core/PSProxmoxVE.Core.csproj +++ b/src/PSProxmoxVE.Core/PSProxmoxVE.Core.csproj @@ -19,16 +19,19 @@ + + +