main
dart 62 lines 1.77 KB
Raw
1 import 'dart:io';
2 import 'dart:isolate';
3
4 import 'package:archive/archive.dart';
5 import 'package:path/path.dart' as p;
6
7 Future<int> directorySize(Directory dir) async {
8 var total = 0;
9 if (!await dir.exists()) {
10 return total;
11 }
12
13 await for (final entity in dir.list(recursive: true, followLinks: false)) {
14 if (entity is File) {
15 total += await entity.length();
16 }
17 }
18 return total;
19 }
20
21 Future<void> extractTarBz2({
22 required String archivePath,
23 required Directory targetDir,
24 }) async {
25 await Isolate.run(() => _extractTarBz2Sync(archivePath, targetDir.path));
26 }
27
28 void _extractTarBz2Sync(String archivePath, String targetDirPath) {
29 final archiveBytes = File(archivePath).readAsBytesSync();
30 final tarBytes = BZip2Decoder().decodeBytes(archiveBytes);
31 final archive = TarDecoder().decodeBytes(tarBytes);
32
33 final normalizedTargetDir = p.normalize(targetDirPath);
34
35 for (final file in archive) {
36 final relativePath = file.name;
37 if (relativePath.isEmpty) continue;
38
39 final outputPath = p.normalize(p.join(targetDirPath, relativePath));
40 // Reject any entry whose resolved path would land outside the target
41 // directory (e.g. a `../` traversal sequence in the archive entry name)
42 // rather than trusting the archive's own file names.
43 if (outputPath != normalizedTargetDir &&
44 !p.isWithin(normalizedTargetDir, outputPath)) {
45 continue;
46 }
47
48 if (file.isFile) {
49 final outputFile = File(outputPath);
50 outputFile.createSync(recursive: true);
51 outputFile.writeAsBytesSync(file.content as List<int>, flush: true);
52 } else {
53 Directory(outputPath).createSync(recursive: true);
54 }
55 }
56 }
57
58 Future<void> deleteDirectoryIfExists(Directory dir) async {
59 if (await dir.exists()) {
60 await dir.delete(recursive: true);
61 }
62 }