Skip to content
This repository was archived by the owner on Sep 3, 2025. It is now read-only.

Commit 273e95c

Browse files
committed
fix: Handle tags with sizes that exceed the file size (fixes #156)
* Invalid tags are returned with the Error::partial_tag field if possible * Also refactor the StorageFile writer to be easier to debug
1 parent b519cd7 commit 273e95c

File tree

5 files changed

+38
-9
lines changed

5 files changed

+38
-9
lines changed

src/storage/plain.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -147,24 +147,25 @@ impl<F: StorageFile> io::Write for PlainWriter<'_, F> {
147147
let old_file_end = self.storage.file.seek(io::SeekFrom::End(0))?;
148148
let old_region_end = self.storage.region.end;
149149
let new_region_end = self.storage.region.start + buf_len;
150-
let new_file_end = old_file_end - (old_region_end - new_region_end);
150+
let new_file_end =
151+
self.storage.region.start + buf_len + (old_file_end - old_region_end);
151152

152153
let mut rwbuf = [0; COPY_BUF_SIZE];
153154
let rwbuf_len = rwbuf.len();
154155
for i in 0.. {
155156
let from = old_region_end + i * rwbuf.len() as u64;
156157
let to = new_region_end + i * rwbuf.len() as u64;
157-
assert!(from >= to);
158+
assert!(from > to);
158159

159-
let part = (to + rwbuf_len as u64).saturating_sub(new_file_end);
160-
let rwbuf_part = &mut rwbuf[part as usize..];
160+
if from >= old_file_end {
161+
break;
162+
}
163+
let part = cmp::min(rwbuf_len as i64, (old_file_end - from) as i64);
164+
let rwbuf_part = &mut rwbuf[..part as usize];
161165
self.storage.file.seek(io::SeekFrom::Start(from))?;
162166
self.storage.file.read_exact(rwbuf_part)?;
163167
self.storage.file.seek(io::SeekFrom::Start(to))?;
164168
self.storage.file.write_all(rwbuf_part)?;
165-
if rwbuf_part.len() < rwbuf_len {
166-
break;
167-
}
168169
}
169170

170171
self.storage.file.set_len(new_file_end)?;

src/stream/tag.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -481,16 +481,26 @@ impl Default for Encoder {
481481

482482
pub fn locate_id3v2(reader: impl io::Read + io::Seek) -> crate::Result<Range<u64>> {
483483
let mut reader = io::BufReader::new(reader);
484+
let start = reader.stream_position()?;
484485

485-
let header = Header::decode(&mut reader)?;
486+
let file_size = reader.seek(io::SeekFrom::End(0))?;
487+
reader.seek(io::SeekFrom::Start(start))?;
486488

489+
let header = Header::decode(&mut reader)?;
487490
let tag_size = header.tag_size();
491+
492+
if start + tag_size >= file_size {
493+
// Seen in the wild: tags that are encoded to be larger than the files actuall are.
494+
reader.seek(io::SeekFrom::End(0))?;
495+
return Ok(start..file_size);
496+
}
497+
488498
reader.seek(io::SeekFrom::Start(tag_size))?;
489499
let num_padding = reader
490500
.bytes()
491501
.take_while(|rs| rs.as_ref().map(|b| *b == 0x00).unwrap_or(false))
492502
.count();
493-
Ok(0..tag_size + num_padding as u64)
503+
Ok(start..tag_size + num_padding as u64)
494504
}
495505

496506
#[cfg(test)]

src/tag.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,24 @@ mod tests {
759759
let _tag = Tag::read_from_path("testdata/github-issue-147.id3").unwrap();
760760
}
761761

762+
#[test]
763+
fn github_issue_156a() {
764+
let tmp = tempfile::NamedTempFile::new().unwrap();
765+
std::fs::copy("testdata/github-issue-156a.id3", &tmp).unwrap();
766+
767+
let tag = crate::partial_tag_ok(Tag::read_from_path(&tmp)).unwrap();
768+
tag.write_to_path(&tmp, Version::Id3v23).unwrap();
769+
}
770+
771+
#[test]
772+
fn github_issue_156b() {
773+
let tmp = tempfile::NamedTempFile::new().unwrap();
774+
std::fs::copy("testdata/github-issue-156b.id3", &tmp).unwrap();
775+
776+
let tag = Tag::read_from_path(&tmp).unwrap();
777+
tag.write_to_path(&tmp, Version::Id3v23).unwrap();
778+
}
779+
762780
#[test]
763781
fn aiff_read_and_write() {
764782
// Copy

testdata/github-issue-156a.id3

1.12 KB
Binary file not shown.

testdata/github-issue-156b.id3

1.12 KB
Binary file not shown.

0 commit comments

Comments
 (0)