Allow multiple zero blocks at the end
diff --git a/lib/src/reader.dart b/lib/src/reader.dart
index f4b356f..eff4135 100644
--- a/lib/src/reader.dart
+++ b/lib/src/reader.dart
@@ -309,15 +309,20 @@
return size;
}
+ /// Ater we detected the end of a tar file, optionally check for trailing
+ /// data.
Future<void> _handleExpectedEof() async {
if (_checkNoTrailingData) {
- // This will be empty iff the stream is done
- final furtherData = await _chunkedStream.read(1);
-
- // Note that throwing will automatically cancel the reader
- if (furtherData.isNotEmpty) {
- throw TarException('Illegal content after the end of the tar archive.');
- }
+ // Trailing zeroes are okay, but don't allow any more data here.
+ Uint8List block;
+ do {
+ block = await _chunkedStream.readBytes(blockSize);
+ if (!block.isAllZeroes) {
+ throw TarException(
+ 'Illegal content after the end of the tar archive.');
+ }
+ } while (block.length == blockSize);
+ // The stream is done when we couldn't read the full block.
}
await cancel();
diff --git a/reference/pub/pana-0.12.19.tar.gz b/reference/pub/pana-0.12.19.tar.gz
new file mode 100644
index 0000000..dfb2aae
--- /dev/null
+++ b/reference/pub/pana-0.12.19.tar.gz
Binary files differ
diff --git a/test/pub_test.dart b/test/pub_test.dart
index 6cb7e70..756ee09 100644
--- a/test/pub_test.dart
+++ b/test/pub_test.dart
@@ -11,17 +11,18 @@
void main() {
const onceBroken = [
'access_settings_menu-0.0.1',
+ 'pana-0.12.19',
'RAL-1.28.0',
'rikulo_commons-0.7.6',
];
for (final package in onceBroken) {
- test('can read $package', () {
+ test('can read $package', () async {
final file = File('reference/pub/$package.tar.gz');
final tarStream = file.openRead().transform(gzip.decoder);
- return TarReader.forEach(tarStream, (entry) {
- // do nothing, we just want to make sure that the package can be read.
- });
+
+ final reader = TarReader(tarStream, disallowTrailingData: true);
+ while (await reader.moveNext()) {}
});
}
}
diff --git a/test/reader_test.dart b/test/reader_test.dart
index a1e2ba4..04a0572 100644
--- a/test/reader_test.dart
+++ b/test/reader_test.dart
@@ -135,7 +135,12 @@
final input = StreamController<Uint8List>()
..add(emptyBlock)
..add(emptyBlock)
- ..add(Uint8List(1)); // illegal content after end marker
+ // illegal content after end marker
+ ..add(Uint8List.fromList([0, 1, 2, 3]));
+
+ // The reader checks for empty data in chunks, so we timeout if the stream
+ // goes stale.
+ Timer.run(input.close);
final reader = TarReader(input.stream, disallowTrailingData: true);
await expectLater(reader.moveNext(), throwsA(isA<TarException>()));
@@ -153,6 +158,17 @@
expectLater(reader.moveNext(), completion(isFalse));
});
+ test('does not throw or cancel when there are many empty blocks', () {
+ final input = StreamController<Uint8List>();
+ for (var i = 0; i < 100; i++) {
+ input.add(emptyBlock);
+ }
+ closeLater(input);
+
+ final reader = TarReader(input.stream, disallowTrailingData: true);
+ expectLater(reader.moveNext(), completion(isFalse));
+ });
+
test('does not throw or cancel if the stream ends without marker', () {
final input = StreamController<Uint8List>();
closeLater(input);