Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ because it turns other people's test suites red.
5493 B, to 320x240 at 7732 B and to 640x480 at 18722 B, about a tenth above
where it did. A file between the old step and the new one is not byte for
byte what 0.5.0 wrote.
- **A tar.gz 16 KiB to 64 KiB larger than the files inside it now opens in
Alpine Linux.** busybox, the `gzip` and `tar` of Alpine and many small
container images, refused these archives as corrupted data - the default
64 KiB one among them. The gzip header now carries at most 16 KiB of the
padding, which busybox reads, and the padding file inside the archive takes
the rest, as it did for larger archives. Those archives are not byte for
byte what 0.5.0 wrote. Every other tar.gz is unchanged.

### Added

Expand Down Expand Up @@ -78,8 +85,7 @@ because it turns other people's test suites red.
the manifest's `damage` now carries `cut`: `in` (`content`, `padding`,
`structure` or `end`) and `content_kept_bytes`, and `content_bytes` where
the length of the content is known. A cut in the padding also gets the
note `cut_in_padding`. In a compressed tar.gz a cut in the padding is
reported as a cut in the content.
note `cut_in_padding`.
- **`truncate` cuts the picture of a PNG, a GIF, a JPEG or an icon by the
percentage you set.** `--damage truncate:missing=90` on a 1 MB PNG or GIF
used to cut only padding and leave the whole picture, and on a JPEG or a
Expand All @@ -94,6 +100,13 @@ because it turns other people's test suites red.
file inside. In a small file a cut of a few percent can fall in the index at
its end, and then every file inside is kept - the manifest says `in: end`.
Files nothing cuts are unchanged.
- **`truncate` cuts the files inside a tar.gz by the percentage you set,
compressed or not.** `--damage truncate:missing=50` on a 1 MB tar.gz used
to cut only padding. Now it removes half of the files' content, so
`tar -xzf` gets back the first part of the file inside and then stops at
the unexpected end. When the cut is shorter than the end of the archive -
1% of 64 KiB - it falls there and every file is kept, and the manifest says
`in: end`. Files nothing cuts are unchanged.

- **tfg is on npm, for tests in Node.**
`npm install --save-dev testing-files-generator` gives Playwright, Vitest
Expand Down
4 changes: 4 additions & 0 deletions internal/format/opc/cut.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ func SettleForACut(parts []Part, shape Shape, want, cutAt int64) (Package, error
}
pad := want - shape.Bare
front := format.PaddingInFront(0, c.content, cutAt, want)
// The parts are marked with their length whether or not a part goes in
// front: the cut stops the writing before the mark behind them, so a cut
// inside them says how much of them there was only from this.
p.Content = c.content
if front <= 0 || pad < c.frontOverhead {
return p, nil
}
Expand Down
10 changes: 5 additions & 5 deletions internal/format/opc/opc.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,16 +267,16 @@ func write(ctx context.Context, w io.Writer, p Package, withPadding bool) error
// archive/zip writes it (archive.StreamMap). A package laid out for a cut
// opens with a padding part, and the content starts behind it.
behind := FillerName
content := p.Content
if content <= 0 {
content = -1
}
if p.Front == NoFiller {
format.Mark(w, format.RoleContent, 0, -1)
format.Mark(w, format.RoleContent, 0, content)
} else {
if err := writePaddingPart(ctx, zw, zm, paddingPart{FillerName, p.Seed, p.Front, withPadding}); err != nil {
return err
}
content := p.Content
if content <= 0 {
content = -1
}
format.Mark(w, format.RoleContent, zm.Pos(), content)
behind = FillerEndName
}
Expand Down
6 changes: 3 additions & 3 deletions internal/format/targz/compress.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ import (
//
// Measured 2026-09-01 across levels 1, 6 and 9 and targets from 64 KB to
// 10 MB: every one landed on the ordered size, and the remainder left for the
// extra field came out between 567 and 3759 bytes - far inside the 65 531 the
// field holds (O163).
// extra field came out between 567 and 3759 bytes - far inside the 16 384 the
// field holds (extraPaddingLimit).
//
// This costs passes, and the cost is real: one pass over a 10 MB archive is
// 25 ms at level 1 and 140 ms at level 6, against 8 ms stored. It buys the one
Expand Down Expand Up @@ -143,7 +143,7 @@ func nextFiller(target, got, filler int64) (next, extra int64, useExtra, done bo
// compiler broke it. Probe: tools/probes/targzsettle.
//
// Undershooting is safe and overshooting is not: the extra field adds
// exactly what it is given, up to 65 531 B, so a round that lands under
// exactly what it is given, up to extraPaddingLimit, so a round that lands under
// the target finishes on the next pass. A whole block is well inside
// that.
next := filler - (2 - deficit) - tarBlock
Expand Down
Loading
Loading