Files
Moonlight/Moonlight.ApiServer/Http/Controllers/Admin/Sys/Files/DecompressController.cs

113 lines
3.8 KiB
C#

using System.Text;
using ICSharpCode.SharpZipLib.GZip;
using ICSharpCode.SharpZipLib.Tar;
using ICSharpCode.SharpZipLib.Zip;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Moonlight.ApiServer.Helpers;
using Moonlight.Shared.Http.Requests.Admin.Sys.Files;
namespace Moonlight.ApiServer.Http.Controllers.Admin.Sys.Files;
[ApiController]
[Route("api/admin/system/files")]
[Authorize(Policy = "permissions:admin.system.files")]
public class DecompressController : Controller
{
private const string BaseDirectory = "storage";
[HttpPost("decompress")]
public async Task Decompress([FromBody] DecompressRequest request)
{
var path = Path.Combine(BaseDirectory, FilePathHelper.SanitizePath(request.Path));
var destination = Path.Combine(BaseDirectory, FilePathHelper.SanitizePath(request.Destination));
switch (request.Format)
{
case "tar.gz":
await DecompressTarGz(path, destination);
break;
case "zip":
await DecompressZip(path, destination);
break;
}
}
#region Tar Gz
private async Task DecompressTarGz(string path, string destination)
{
await using var fs = System.IO.File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
await using var gzipInputStream = new GZipInputStream(fs);
await using var tarInputStream = new TarInputStream(gzipInputStream, Encoding.UTF8);
while (true)
{
var entry = await tarInputStream.GetNextEntryAsync(CancellationToken.None);
if (entry == null)
break;
var safeFilePath = FilePathHelper.SanitizePath(entry.Name);
var fileDestination = Path.Combine(destination, safeFilePath);
var parentFolder = Path.GetDirectoryName(fileDestination);
// Ensure parent directory exists, if it's not the base directory
if (parentFolder != null && parentFolder != BaseDirectory)
Directory.CreateDirectory(parentFolder);
await using var fileDestinationFs =
System.IO.File.Open(fileDestination, FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
await tarInputStream.CopyToAsync(fileDestinationFs, CancellationToken.None);
await fileDestinationFs.FlushAsync();
fileDestinationFs.Close();
}
tarInputStream.Close();
gzipInputStream.Close();
fs.Close();
}
#endregion
#region Zip
private async Task DecompressZip(string path, string destination)
{
await using var fs = System.IO.File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
await using var zipInputStream = new ZipInputStream(fs);
while (true)
{
var entry = zipInputStream.GetNextEntry();
if (entry == null)
break;
if (entry.IsDirectory)
continue;
var safeFilePath = FilePathHelper.SanitizePath(entry.Name);
var fileDestination = Path.Combine(destination, safeFilePath);
var parentFolder = Path.GetDirectoryName(fileDestination);
// Ensure parent directory exists, if it's not the base directory
if (parentFolder != null && parentFolder != BaseDirectory)
Directory.CreateDirectory(parentFolder);
await using var fileDestinationFs =
System.IO.File.Open(fileDestination, FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
await zipInputStream.CopyToAsync(fileDestinationFs, CancellationToken.None);
await fileDestinationFs.FlushAsync();
fileDestinationFs.Close();
}
zipInputStream.Close();
fs.Close();
}
#endregion
}