std/tar/untar_stream.ts

397 lines
11 KiB
TypeScript
Raw Permalink Normal View History

feat(archive): `UntarStream` and `TarStream` (#4548) * refactor(archive): An implementation of Tar as streams * fmt(archive): Ran `deno fmt` * fix(archive): fixed JSDoc examples in tar_streams.ts * fix(archive): fixed JSDoc examples so `deno task test` doesn't complain * fix(archive): lint license error * fix(archive): lint error files not exported * set(archive): Set current time as mtime for default * resolve(archive): resolves comments made * add(archive): `{ mode: 'byob' }` support for TarStream * add(archive): `{ mode: 'byob' }` support for UnTarStream * adjust(archive): The logical flow of a few if statements * tests(archive): Updated Tests for Un/TarStream * fix(archive): TarStream mtime wasn't an octal * fix(archive): TarStream tests * add(archive): Added parsePathname function Added parsePathname function abstracting the logic out of TarStream allowing the developer to validate pathnames before providing them to TarStream hoping it doesn't throw an error and require the archive creation to start all over again. * fix(archive): extra bytes incorrectly appending at the end of files When the appending file was exactly divisible by 512 bytes, an extra 512 bytes was being appending instead of zero to fill in the gap, causing the next header to be read at the wrong place. * adjust(archive): to always return the amount of bytes requested Instead of using enqueue, the leftover bytes are saved for later for the next buffer provided. * tweaks * fix * docs(archive): Link to the spec that they're following * docs(archive): fix spelling * add(archive): function validTarSteamOptions - To make sure, if TarStreamOptions are being provided, that they are in the correct format so as to not create bad tarballs. * add(archive): more tests * fix(archive): validTarStreamOptions * add(archive): tests for validTarStreamOptions * refactor(archive): code to copy the changes made in the @doctor/tar-stream version * test(archive): added from @doctor/tar-stream * chore: nit on anonymous function * refactor(archive): UnTarStream that fixes unexplainable memory leak - The second newest test introduced here '... with invalid ending' seems to detect a memory leak due to an invalid tarball. I couldn't figure out why the memory leak was happening but I know this restructure of the code doesn't have that same memory leak. * chore: fmt * tests(archive): added remaining tests to cover many lines as possible * adjust(archive): remove simplify pathname code * adjust(archive): remove checking for duplicate pathnames in taring process * adjust(archive): A readable will exist on TarEntry unless string values 1-6 * tests(archive): added more tests for higher coverage * adjust(archives): TarStream and UnTarStream to implement TransformStream * docs(archive): moved TarStreamOptions docs into properties. * adjust(archive): TarStreamFile to take a ReadableSteam instead of an Iterable | AsyncIterable * adjust(archive): to use FixedChunkStream instead of rolling it's own implementation * fix(archive): lint error * adjust(archive): Error types and messages * adjust(archive): more Error messages / improve tests * refactor(archive): UnTarStream to return TarStreamChunk instead of TarStreamEntry * fix(archive): JSDoc example * adjust(archive): mode, uid, gid options to be provided as numbers instead of strings. * adjust(archive): TarStream's pathname to be only of type string * fix(archive): prefix/name to ignore everything past the first NULL * adjust(archive): `checksum` and `pad` to not be exposed from UnTarStream * adjust(archive): checksum calculation * change(archive): `.slice` to `.subarray` * doc(archive): "octal number" to "octal literal" * adjust(archive): TarStreamOptions to be optional with defaults * doc(archive): added more docs for the interfaces * docs(archive): denoting defaults * docs(archive): updated for new lint rules * adjust(archive): Tests to use assertRejects where appropriate & add `validPathname` function - The `validPathname` is meant to be a nicer exposed function for users of this lib to validate that their pathnames are valid before pipping it through the TarStream, over exposing parsePathname where the user may be confused about what to do with the result. * adjust(archive): to use `Date.now()` instead of `new Date().getTime()` Co-authored-by: ud2 <sjx233@qq.com> * adjust(archive): mode, uid, and gid to be numbers instead of strings when Untaring * tests(archive): adjust two tests to also validate the contents of the files are valid * adjust(archive): linkname, uname, and gname to follow the same decoding rules as name and prefix * rename(archive): UnTarStream to UntarStream * fix(archive): type that was missed getting updated * tests(archive): adjust check headers test to validate all header properties instead of just pathnames * rename(archive): `pathname` properties to `path` * docs(archive): updated to be more descriptive * docs(archive): Updated error types * adjust(archive): `validPath` to `assertValidPath` * adjust(archive): `validTarStreamOptions` to `assertValidTarStreamOptions` * revert(archive): UntarStream to produce TarStreamEntry instead of TarStreamChunk * refactor: remove redundant `void` return types * docs: cleanup assertion function docs * docs: correct `TarStream` example * docs: minor docs cleanups * refactor: improve error class specificity * docs: add `@experimental` JSDoc tags * docs(archive): Updated examples for `assertValidPath` and `assertValidTarStreamOptions``` * fix(archive): problem with tests - I suspect the problem is that a file that was read by `Deno.readDir` changed size between being read at `Deno.stat` and when `Deno.open` finished pulling it all in. * update error messages * update error messages * fix typos * refactor: tweak error messages * refactor: tweaks and add type field --------- Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com> Co-authored-by: ud2 <sjx233@qq.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
2024-09-02 07:43:22 +00:00
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { FixedChunkStream } from "@std/streams/unstable-fixed-chunk-stream";
feat(archive): `UntarStream` and `TarStream` (#4548) * refactor(archive): An implementation of Tar as streams * fmt(archive): Ran `deno fmt` * fix(archive): fixed JSDoc examples in tar_streams.ts * fix(archive): fixed JSDoc examples so `deno task test` doesn't complain * fix(archive): lint license error * fix(archive): lint error files not exported * set(archive): Set current time as mtime for default * resolve(archive): resolves comments made * add(archive): `{ mode: 'byob' }` support for TarStream * add(archive): `{ mode: 'byob' }` support for UnTarStream * adjust(archive): The logical flow of a few if statements * tests(archive): Updated Tests for Un/TarStream * fix(archive): TarStream mtime wasn't an octal * fix(archive): TarStream tests * add(archive): Added parsePathname function Added parsePathname function abstracting the logic out of TarStream allowing the developer to validate pathnames before providing them to TarStream hoping it doesn't throw an error and require the archive creation to start all over again. * fix(archive): extra bytes incorrectly appending at the end of files When the appending file was exactly divisible by 512 bytes, an extra 512 bytes was being appending instead of zero to fill in the gap, causing the next header to be read at the wrong place. * adjust(archive): to always return the amount of bytes requested Instead of using enqueue, the leftover bytes are saved for later for the next buffer provided. * tweaks * fix * docs(archive): Link to the spec that they're following * docs(archive): fix spelling * add(archive): function validTarSteamOptions - To make sure, if TarStreamOptions are being provided, that they are in the correct format so as to not create bad tarballs. * add(archive): more tests * fix(archive): validTarStreamOptions * add(archive): tests for validTarStreamOptions * refactor(archive): code to copy the changes made in the @doctor/tar-stream version * test(archive): added from @doctor/tar-stream * chore: nit on anonymous function * refactor(archive): UnTarStream that fixes unexplainable memory leak - The second newest test introduced here '... with invalid ending' seems to detect a memory leak due to an invalid tarball. I couldn't figure out why the memory leak was happening but I know this restructure of the code doesn't have that same memory leak. * chore: fmt * tests(archive): added remaining tests to cover many lines as possible * adjust(archive): remove simplify pathname code * adjust(archive): remove checking for duplicate pathnames in taring process * adjust(archive): A readable will exist on TarEntry unless string values 1-6 * tests(archive): added more tests for higher coverage * adjust(archives): TarStream and UnTarStream to implement TransformStream * docs(archive): moved TarStreamOptions docs into properties. * adjust(archive): TarStreamFile to take a ReadableSteam instead of an Iterable | AsyncIterable * adjust(archive): to use FixedChunkStream instead of rolling it's own implementation * fix(archive): lint error * adjust(archive): Error types and messages * adjust(archive): more Error messages / improve tests * refactor(archive): UnTarStream to return TarStreamChunk instead of TarStreamEntry * fix(archive): JSDoc example * adjust(archive): mode, uid, gid options to be provided as numbers instead of strings. * adjust(archive): TarStream's pathname to be only of type string * fix(archive): prefix/name to ignore everything past the first NULL * adjust(archive): `checksum` and `pad` to not be exposed from UnTarStream * adjust(archive): checksum calculation * change(archive): `.slice` to `.subarray` * doc(archive): "octal number" to "octal literal" * adjust(archive): TarStreamOptions to be optional with defaults * doc(archive): added more docs for the interfaces * docs(archive): denoting defaults * docs(archive): updated for new lint rules * adjust(archive): Tests to use assertRejects where appropriate & add `validPathname` function - The `validPathname` is meant to be a nicer exposed function for users of this lib to validate that their pathnames are valid before pipping it through the TarStream, over exposing parsePathname where the user may be confused about what to do with the result. * adjust(archive): to use `Date.now()` instead of `new Date().getTime()` Co-authored-by: ud2 <sjx233@qq.com> * adjust(archive): mode, uid, and gid to be numbers instead of strings when Untaring * tests(archive): adjust two tests to also validate the contents of the files are valid * adjust(archive): linkname, uname, and gname to follow the same decoding rules as name and prefix * rename(archive): UnTarStream to UntarStream * fix(archive): type that was missed getting updated * tests(archive): adjust check headers test to validate all header properties instead of just pathnames * rename(archive): `pathname` properties to `path` * docs(archive): updated to be more descriptive * docs(archive): Updated error types * adjust(archive): `validPath` to `assertValidPath` * adjust(archive): `validTarStreamOptions` to `assertValidTarStreamOptions` * revert(archive): UntarStream to produce TarStreamEntry instead of TarStreamChunk * refactor: remove redundant `void` return types * docs: cleanup assertion function docs * docs: correct `TarStream` example * docs: minor docs cleanups * refactor: improve error class specificity * docs: add `@experimental` JSDoc tags * docs(archive): Updated examples for `assertValidPath` and `assertValidTarStreamOptions``` * fix(archive): problem with tests - I suspect the problem is that a file that was read by `Deno.readDir` changed size between being read at `Deno.stat` and when `Deno.open` finished pulling it all in. * update error messages * update error messages * fix typos * refactor: tweak error messages * refactor: tweaks and add type field --------- Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com> Co-authored-by: ud2 <sjx233@qq.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
2024-09-02 07:43:22 +00:00
/**
* The original tar archive header format.
*
* @experimental **UNSTABLE**: New API, yet to be vetted.
*/
export interface OldStyleFormat {
/**
* The name of the entry.
*/
name: string;
/**
* The mode of the entry.
*/
mode: number;
/**
* The uid of the entry.
*/
uid: number;
/**
* The gid of the entry.
*/
gid: number;
/**
* The size of the entry.
*/
size: number;
/**
* The mtime of the entry.
*/
mtime: number;
/**
* The typeflag of the entry.
*/
typeflag: string;
/**
* The linkname of the entry.
*/
linkname: string;
}
/**
* The POSIX ustar archive header format.
*
* @experimental **UNSTABLE**: New API, yet to be vetted.
*/
export interface PosixUstarFormat {
/**
* The latter half of the name of the entry.
*/
name: string;
/**
* The mode of the entry.
*/
mode: number;
/**
* The uid of the entry.
*/
uid: number;
/**
* The gid of the entry.
*/
gid: number;
/**
* The size of the entry.
*/
size: number;
/**
* The mtime of the entry.
*/
mtime: number;
/**
* The typeflag of the entry.
*/
typeflag: string;
/**
* The linkname of the entry.
*/
linkname: string;
/**
* The magic number of the entry.
*/
magic: string;
/**
* The version number of the entry.
*/
version: string;
/**
* The uname of the entry.
*/
uname: string;
/**
* The gname of the entry.
*/
gname: string;
/**
* The devmajor of the entry.
*/
devmajor: string;
/**
* The devminor of the entry.
*/
devminor: string;
/**
* The former half of the name of the entry.
*/
prefix: string;
}
/**
* The structure of an entry extracted from a Tar archive.
*
* @experimental **UNSTABLE**: New API, yet to be vetted.
*/
export interface TarStreamEntry {
/**
* The header information attributed to the entry, presented in one of two
* valid forms.
*/
header: OldStyleFormat | PosixUstarFormat;
/**
* The path of the entry as stated in the archive.
*/
path: string;
/**
* The content of the entry, if the entry is a file.
*/
readable?: ReadableStream<Uint8Array>;
}
/**
* ### Overview
* A TransformStream to expand a tar archive. Tar archives allow for storing
* multiple files in a single file (called an archive, or sometimes a tarball).
*
* These archives typically have a single '.tar' extension. This
* implementation follows the [FreeBSD 15.0](https://man.freebsd.org/cgi/man.cgi?query=tar&sektion=5&apropos=0&manpath=FreeBSD+15.0-CURRENT) spec.
*
* ### Supported File Formats
* Only the ustar file format is supported. This is the most common format.
* Additionally the numeric extension for file size.
*
* ### Usage
* When expanding the archive, as demonstrated in the example, one must decide
* to either consume the ReadableStream property, if present, or cancel it. The
* next entry won't be resolved until the previous ReadableStream is either
* consumed or cancelled.
*
* ### Understanding Compressed
* A tar archive may be compressed, often identified by an additional file
* extension, such as '.tar.gz' for gzip. This TransformStream does not support
* decompression which must be done before expanding the archive.
*
* @experimental **UNSTABLE**: New API, yet to be vetted.
*
* @example Usage
* ```ts ignore
* import { UntarStream } from "@std/tar/untar-stream";
feat(archive): `UntarStream` and `TarStream` (#4548) * refactor(archive): An implementation of Tar as streams * fmt(archive): Ran `deno fmt` * fix(archive): fixed JSDoc examples in tar_streams.ts * fix(archive): fixed JSDoc examples so `deno task test` doesn't complain * fix(archive): lint license error * fix(archive): lint error files not exported * set(archive): Set current time as mtime for default * resolve(archive): resolves comments made * add(archive): `{ mode: 'byob' }` support for TarStream * add(archive): `{ mode: 'byob' }` support for UnTarStream * adjust(archive): The logical flow of a few if statements * tests(archive): Updated Tests for Un/TarStream * fix(archive): TarStream mtime wasn't an octal * fix(archive): TarStream tests * add(archive): Added parsePathname function Added parsePathname function abstracting the logic out of TarStream allowing the developer to validate pathnames before providing them to TarStream hoping it doesn't throw an error and require the archive creation to start all over again. * fix(archive): extra bytes incorrectly appending at the end of files When the appending file was exactly divisible by 512 bytes, an extra 512 bytes was being appending instead of zero to fill in the gap, causing the next header to be read at the wrong place. * adjust(archive): to always return the amount of bytes requested Instead of using enqueue, the leftover bytes are saved for later for the next buffer provided. * tweaks * fix * docs(archive): Link to the spec that they're following * docs(archive): fix spelling * add(archive): function validTarSteamOptions - To make sure, if TarStreamOptions are being provided, that they are in the correct format so as to not create bad tarballs. * add(archive): more tests * fix(archive): validTarStreamOptions * add(archive): tests for validTarStreamOptions * refactor(archive): code to copy the changes made in the @doctor/tar-stream version * test(archive): added from @doctor/tar-stream * chore: nit on anonymous function * refactor(archive): UnTarStream that fixes unexplainable memory leak - The second newest test introduced here '... with invalid ending' seems to detect a memory leak due to an invalid tarball. I couldn't figure out why the memory leak was happening but I know this restructure of the code doesn't have that same memory leak. * chore: fmt * tests(archive): added remaining tests to cover many lines as possible * adjust(archive): remove simplify pathname code * adjust(archive): remove checking for duplicate pathnames in taring process * adjust(archive): A readable will exist on TarEntry unless string values 1-6 * tests(archive): added more tests for higher coverage * adjust(archives): TarStream and UnTarStream to implement TransformStream * docs(archive): moved TarStreamOptions docs into properties. * adjust(archive): TarStreamFile to take a ReadableSteam instead of an Iterable | AsyncIterable * adjust(archive): to use FixedChunkStream instead of rolling it's own implementation * fix(archive): lint error * adjust(archive): Error types and messages * adjust(archive): more Error messages / improve tests * refactor(archive): UnTarStream to return TarStreamChunk instead of TarStreamEntry * fix(archive): JSDoc example * adjust(archive): mode, uid, gid options to be provided as numbers instead of strings. * adjust(archive): TarStream's pathname to be only of type string * fix(archive): prefix/name to ignore everything past the first NULL * adjust(archive): `checksum` and `pad` to not be exposed from UnTarStream * adjust(archive): checksum calculation * change(archive): `.slice` to `.subarray` * doc(archive): "octal number" to "octal literal" * adjust(archive): TarStreamOptions to be optional with defaults * doc(archive): added more docs for the interfaces * docs(archive): denoting defaults * docs(archive): updated for new lint rules * adjust(archive): Tests to use assertRejects where appropriate & add `validPathname` function - The `validPathname` is meant to be a nicer exposed function for users of this lib to validate that their pathnames are valid before pipping it through the TarStream, over exposing parsePathname where the user may be confused about what to do with the result. * adjust(archive): to use `Date.now()` instead of `new Date().getTime()` Co-authored-by: ud2 <sjx233@qq.com> * adjust(archive): mode, uid, and gid to be numbers instead of strings when Untaring * tests(archive): adjust two tests to also validate the contents of the files are valid * adjust(archive): linkname, uname, and gname to follow the same decoding rules as name and prefix * rename(archive): UnTarStream to UntarStream * fix(archive): type that was missed getting updated * tests(archive): adjust check headers test to validate all header properties instead of just pathnames * rename(archive): `pathname` properties to `path` * docs(archive): updated to be more descriptive * docs(archive): Updated error types * adjust(archive): `validPath` to `assertValidPath` * adjust(archive): `validTarStreamOptions` to `assertValidTarStreamOptions` * revert(archive): UntarStream to produce TarStreamEntry instead of TarStreamChunk * refactor: remove redundant `void` return types * docs: cleanup assertion function docs * docs: correct `TarStream` example * docs: minor docs cleanups * refactor: improve error class specificity * docs: add `@experimental` JSDoc tags * docs(archive): Updated examples for `assertValidPath` and `assertValidTarStreamOptions``` * fix(archive): problem with tests - I suspect the problem is that a file that was read by `Deno.readDir` changed size between being read at `Deno.stat` and when `Deno.open` finished pulling it all in. * update error messages * update error messages * fix typos * refactor: tweak error messages * refactor: tweaks and add type field --------- Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com> Co-authored-by: ud2 <sjx233@qq.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
2024-09-02 07:43:22 +00:00
* import { dirname, normalize } from "@std/path";
*
* for await (
* const entry of (await Deno.open("./out.tar.gz"))
* .readable
* .pipeThrough(new DecompressionStream("gzip"))
* .pipeThrough(new UntarStream())
* ) {
* const path = normalize(entry.path);
* await Deno.mkdir(dirname(path), { recursive: true });
feat(archive): `UntarStream` and `TarStream` (#4548) * refactor(archive): An implementation of Tar as streams * fmt(archive): Ran `deno fmt` * fix(archive): fixed JSDoc examples in tar_streams.ts * fix(archive): fixed JSDoc examples so `deno task test` doesn't complain * fix(archive): lint license error * fix(archive): lint error files not exported * set(archive): Set current time as mtime for default * resolve(archive): resolves comments made * add(archive): `{ mode: 'byob' }` support for TarStream * add(archive): `{ mode: 'byob' }` support for UnTarStream * adjust(archive): The logical flow of a few if statements * tests(archive): Updated Tests for Un/TarStream * fix(archive): TarStream mtime wasn't an octal * fix(archive): TarStream tests * add(archive): Added parsePathname function Added parsePathname function abstracting the logic out of TarStream allowing the developer to validate pathnames before providing them to TarStream hoping it doesn't throw an error and require the archive creation to start all over again. * fix(archive): extra bytes incorrectly appending at the end of files When the appending file was exactly divisible by 512 bytes, an extra 512 bytes was being appending instead of zero to fill in the gap, causing the next header to be read at the wrong place. * adjust(archive): to always return the amount of bytes requested Instead of using enqueue, the leftover bytes are saved for later for the next buffer provided. * tweaks * fix * docs(archive): Link to the spec that they're following * docs(archive): fix spelling * add(archive): function validTarSteamOptions - To make sure, if TarStreamOptions are being provided, that they are in the correct format so as to not create bad tarballs. * add(archive): more tests * fix(archive): validTarStreamOptions * add(archive): tests for validTarStreamOptions * refactor(archive): code to copy the changes made in the @doctor/tar-stream version * test(archive): added from @doctor/tar-stream * chore: nit on anonymous function * refactor(archive): UnTarStream that fixes unexplainable memory leak - The second newest test introduced here '... with invalid ending' seems to detect a memory leak due to an invalid tarball. I couldn't figure out why the memory leak was happening but I know this restructure of the code doesn't have that same memory leak. * chore: fmt * tests(archive): added remaining tests to cover many lines as possible * adjust(archive): remove simplify pathname code * adjust(archive): remove checking for duplicate pathnames in taring process * adjust(archive): A readable will exist on TarEntry unless string values 1-6 * tests(archive): added more tests for higher coverage * adjust(archives): TarStream and UnTarStream to implement TransformStream * docs(archive): moved TarStreamOptions docs into properties. * adjust(archive): TarStreamFile to take a ReadableSteam instead of an Iterable | AsyncIterable * adjust(archive): to use FixedChunkStream instead of rolling it's own implementation * fix(archive): lint error * adjust(archive): Error types and messages * adjust(archive): more Error messages / improve tests * refactor(archive): UnTarStream to return TarStreamChunk instead of TarStreamEntry * fix(archive): JSDoc example * adjust(archive): mode, uid, gid options to be provided as numbers instead of strings. * adjust(archive): TarStream's pathname to be only of type string * fix(archive): prefix/name to ignore everything past the first NULL * adjust(archive): `checksum` and `pad` to not be exposed from UnTarStream * adjust(archive): checksum calculation * change(archive): `.slice` to `.subarray` * doc(archive): "octal number" to "octal literal" * adjust(archive): TarStreamOptions to be optional with defaults * doc(archive): added more docs for the interfaces * docs(archive): denoting defaults * docs(archive): updated for new lint rules * adjust(archive): Tests to use assertRejects where appropriate & add `validPathname` function - The `validPathname` is meant to be a nicer exposed function for users of this lib to validate that their pathnames are valid before pipping it through the TarStream, over exposing parsePathname where the user may be confused about what to do with the result. * adjust(archive): to use `Date.now()` instead of `new Date().getTime()` Co-authored-by: ud2 <sjx233@qq.com> * adjust(archive): mode, uid, and gid to be numbers instead of strings when Untaring * tests(archive): adjust two tests to also validate the contents of the files are valid * adjust(archive): linkname, uname, and gname to follow the same decoding rules as name and prefix * rename(archive): UnTarStream to UntarStream * fix(archive): type that was missed getting updated * tests(archive): adjust check headers test to validate all header properties instead of just pathnames * rename(archive): `pathname` properties to `path` * docs(archive): updated to be more descriptive * docs(archive): Updated error types * adjust(archive): `validPath` to `assertValidPath` * adjust(archive): `validTarStreamOptions` to `assertValidTarStreamOptions` * revert(archive): UntarStream to produce TarStreamEntry instead of TarStreamChunk * refactor: remove redundant `void` return types * docs: cleanup assertion function docs * docs: correct `TarStream` example * docs: minor docs cleanups * refactor: improve error class specificity * docs: add `@experimental` JSDoc tags * docs(archive): Updated examples for `assertValidPath` and `assertValidTarStreamOptions``` * fix(archive): problem with tests - I suspect the problem is that a file that was read by `Deno.readDir` changed size between being read at `Deno.stat` and when `Deno.open` finished pulling it all in. * update error messages * update error messages * fix typos * refactor: tweak error messages * refactor: tweaks and add type field --------- Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com> Co-authored-by: ud2 <sjx233@qq.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
2024-09-02 07:43:22 +00:00
* await entry.readable?.pipeTo((await Deno.create(path)).writable);
* }
* ```
*/
export class UntarStream
implements TransformStream<Uint8Array, TarStreamEntry> {
#readable: ReadableStream<TarStreamEntry>;
#writable: WritableStream<Uint8Array>;
#reader: ReadableStreamDefaultReader<Uint8Array>;
#buffer: Uint8Array[] = [];
feat(archive): `UntarStream` and `TarStream` (#4548) * refactor(archive): An implementation of Tar as streams * fmt(archive): Ran `deno fmt` * fix(archive): fixed JSDoc examples in tar_streams.ts * fix(archive): fixed JSDoc examples so `deno task test` doesn't complain * fix(archive): lint license error * fix(archive): lint error files not exported * set(archive): Set current time as mtime for default * resolve(archive): resolves comments made * add(archive): `{ mode: 'byob' }` support for TarStream * add(archive): `{ mode: 'byob' }` support for UnTarStream * adjust(archive): The logical flow of a few if statements * tests(archive): Updated Tests for Un/TarStream * fix(archive): TarStream mtime wasn't an octal * fix(archive): TarStream tests * add(archive): Added parsePathname function Added parsePathname function abstracting the logic out of TarStream allowing the developer to validate pathnames before providing them to TarStream hoping it doesn't throw an error and require the archive creation to start all over again. * fix(archive): extra bytes incorrectly appending at the end of files When the appending file was exactly divisible by 512 bytes, an extra 512 bytes was being appending instead of zero to fill in the gap, causing the next header to be read at the wrong place. * adjust(archive): to always return the amount of bytes requested Instead of using enqueue, the leftover bytes are saved for later for the next buffer provided. * tweaks * fix * docs(archive): Link to the spec that they're following * docs(archive): fix spelling * add(archive): function validTarSteamOptions - To make sure, if TarStreamOptions are being provided, that they are in the correct format so as to not create bad tarballs. * add(archive): more tests * fix(archive): validTarStreamOptions * add(archive): tests for validTarStreamOptions * refactor(archive): code to copy the changes made in the @doctor/tar-stream version * test(archive): added from @doctor/tar-stream * chore: nit on anonymous function * refactor(archive): UnTarStream that fixes unexplainable memory leak - The second newest test introduced here '... with invalid ending' seems to detect a memory leak due to an invalid tarball. I couldn't figure out why the memory leak was happening but I know this restructure of the code doesn't have that same memory leak. * chore: fmt * tests(archive): added remaining tests to cover many lines as possible * adjust(archive): remove simplify pathname code * adjust(archive): remove checking for duplicate pathnames in taring process * adjust(archive): A readable will exist on TarEntry unless string values 1-6 * tests(archive): added more tests for higher coverage * adjust(archives): TarStream and UnTarStream to implement TransformStream * docs(archive): moved TarStreamOptions docs into properties. * adjust(archive): TarStreamFile to take a ReadableSteam instead of an Iterable | AsyncIterable * adjust(archive): to use FixedChunkStream instead of rolling it's own implementation * fix(archive): lint error * adjust(archive): Error types and messages * adjust(archive): more Error messages / improve tests * refactor(archive): UnTarStream to return TarStreamChunk instead of TarStreamEntry * fix(archive): JSDoc example * adjust(archive): mode, uid, gid options to be provided as numbers instead of strings. * adjust(archive): TarStream's pathname to be only of type string * fix(archive): prefix/name to ignore everything past the first NULL * adjust(archive): `checksum` and `pad` to not be exposed from UnTarStream * adjust(archive): checksum calculation * change(archive): `.slice` to `.subarray` * doc(archive): "octal number" to "octal literal" * adjust(archive): TarStreamOptions to be optional with defaults * doc(archive): added more docs for the interfaces * docs(archive): denoting defaults * docs(archive): updated for new lint rules * adjust(archive): Tests to use assertRejects where appropriate & add `validPathname` function - The `validPathname` is meant to be a nicer exposed function for users of this lib to validate that their pathnames are valid before pipping it through the TarStream, over exposing parsePathname where the user may be confused about what to do with the result. * adjust(archive): to use `Date.now()` instead of `new Date().getTime()` Co-authored-by: ud2 <sjx233@qq.com> * adjust(archive): mode, uid, and gid to be numbers instead of strings when Untaring * tests(archive): adjust two tests to also validate the contents of the files are valid * adjust(archive): linkname, uname, and gname to follow the same decoding rules as name and prefix * rename(archive): UnTarStream to UntarStream * fix(archive): type that was missed getting updated * tests(archive): adjust check headers test to validate all header properties instead of just pathnames * rename(archive): `pathname` properties to `path` * docs(archive): updated to be more descriptive * docs(archive): Updated error types * adjust(archive): `validPath` to `assertValidPath` * adjust(archive): `validTarStreamOptions` to `assertValidTarStreamOptions` * revert(archive): UntarStream to produce TarStreamEntry instead of TarStreamChunk * refactor: remove redundant `void` return types * docs: cleanup assertion function docs * docs: correct `TarStream` example * docs: minor docs cleanups * refactor: improve error class specificity * docs: add `@experimental` JSDoc tags * docs(archive): Updated examples for `assertValidPath` and `assertValidTarStreamOptions``` * fix(archive): problem with tests - I suspect the problem is that a file that was read by `Deno.readDir` changed size between being read at `Deno.stat` and when `Deno.open` finished pulling it all in. * update error messages * update error messages * fix typos * refactor: tweak error messages * refactor: tweaks and add type field --------- Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com> Co-authored-by: ud2 <sjx233@qq.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
2024-09-02 07:43:22 +00:00
#lock = false;
constructor() {
const { readable, writable } = new TransformStream<
Uint8Array,
Uint8Array
>();
this.#readable = ReadableStream.from(this.#untar());
this.#writable = writable;
this.#reader = readable.pipeThrough(new FixedChunkStream(512)).getReader();
}
feat(archive): `UntarStream` and `TarStream` (#4548) * refactor(archive): An implementation of Tar as streams * fmt(archive): Ran `deno fmt` * fix(archive): fixed JSDoc examples in tar_streams.ts * fix(archive): fixed JSDoc examples so `deno task test` doesn't complain * fix(archive): lint license error * fix(archive): lint error files not exported * set(archive): Set current time as mtime for default * resolve(archive): resolves comments made * add(archive): `{ mode: 'byob' }` support for TarStream * add(archive): `{ mode: 'byob' }` support for UnTarStream * adjust(archive): The logical flow of a few if statements * tests(archive): Updated Tests for Un/TarStream * fix(archive): TarStream mtime wasn't an octal * fix(archive): TarStream tests * add(archive): Added parsePathname function Added parsePathname function abstracting the logic out of TarStream allowing the developer to validate pathnames before providing them to TarStream hoping it doesn't throw an error and require the archive creation to start all over again. * fix(archive): extra bytes incorrectly appending at the end of files When the appending file was exactly divisible by 512 bytes, an extra 512 bytes was being appending instead of zero to fill in the gap, causing the next header to be read at the wrong place. * adjust(archive): to always return the amount of bytes requested Instead of using enqueue, the leftover bytes are saved for later for the next buffer provided. * tweaks * fix * docs(archive): Link to the spec that they're following * docs(archive): fix spelling * add(archive): function validTarSteamOptions - To make sure, if TarStreamOptions are being provided, that they are in the correct format so as to not create bad tarballs. * add(archive): more tests * fix(archive): validTarStreamOptions * add(archive): tests for validTarStreamOptions * refactor(archive): code to copy the changes made in the @doctor/tar-stream version * test(archive): added from @doctor/tar-stream * chore: nit on anonymous function * refactor(archive): UnTarStream that fixes unexplainable memory leak - The second newest test introduced here '... with invalid ending' seems to detect a memory leak due to an invalid tarball. I couldn't figure out why the memory leak was happening but I know this restructure of the code doesn't have that same memory leak. * chore: fmt * tests(archive): added remaining tests to cover many lines as possible * adjust(archive): remove simplify pathname code * adjust(archive): remove checking for duplicate pathnames in taring process * adjust(archive): A readable will exist on TarEntry unless string values 1-6 * tests(archive): added more tests for higher coverage * adjust(archives): TarStream and UnTarStream to implement TransformStream * docs(archive): moved TarStreamOptions docs into properties. * adjust(archive): TarStreamFile to take a ReadableSteam instead of an Iterable | AsyncIterable * adjust(archive): to use FixedChunkStream instead of rolling it's own implementation * fix(archive): lint error * adjust(archive): Error types and messages * adjust(archive): more Error messages / improve tests * refactor(archive): UnTarStream to return TarStreamChunk instead of TarStreamEntry * fix(archive): JSDoc example * adjust(archive): mode, uid, gid options to be provided as numbers instead of strings. * adjust(archive): TarStream's pathname to be only of type string * fix(archive): prefix/name to ignore everything past the first NULL * adjust(archive): `checksum` and `pad` to not be exposed from UnTarStream * adjust(archive): checksum calculation * change(archive): `.slice` to `.subarray` * doc(archive): "octal number" to "octal literal" * adjust(archive): TarStreamOptions to be optional with defaults * doc(archive): added more docs for the interfaces * docs(archive): denoting defaults * docs(archive): updated for new lint rules * adjust(archive): Tests to use assertRejects where appropriate & add `validPathname` function - The `validPathname` is meant to be a nicer exposed function for users of this lib to validate that their pathnames are valid before pipping it through the TarStream, over exposing parsePathname where the user may be confused about what to do with the result. * adjust(archive): to use `Date.now()` instead of `new Date().getTime()` Co-authored-by: ud2 <sjx233@qq.com> * adjust(archive): mode, uid, and gid to be numbers instead of strings when Untaring * tests(archive): adjust two tests to also validate the contents of the files are valid * adjust(archive): linkname, uname, and gname to follow the same decoding rules as name and prefix * rename(archive): UnTarStream to UntarStream * fix(archive): type that was missed getting updated * tests(archive): adjust check headers test to validate all header properties instead of just pathnames * rename(archive): `pathname` properties to `path` * docs(archive): updated to be more descriptive * docs(archive): Updated error types * adjust(archive): `validPath` to `assertValidPath` * adjust(archive): `validTarStreamOptions` to `assertValidTarStreamOptions` * revert(archive): UntarStream to produce TarStreamEntry instead of TarStreamChunk * refactor: remove redundant `void` return types * docs: cleanup assertion function docs * docs: correct `TarStream` example * docs: minor docs cleanups * refactor: improve error class specificity * docs: add `@experimental` JSDoc tags * docs(archive): Updated examples for `assertValidPath` and `assertValidTarStreamOptions``` * fix(archive): problem with tests - I suspect the problem is that a file that was read by `Deno.readDir` changed size between being read at `Deno.stat` and when `Deno.open` finished pulling it all in. * update error messages * update error messages * fix typos * refactor: tweak error messages * refactor: tweaks and add type field --------- Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com> Co-authored-by: ud2 <sjx233@qq.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
2024-09-02 07:43:22 +00:00
async #read(): Promise<Uint8Array | undefined> {
const { done, value } = await this.#reader.read();
if (done) return undefined;
if (value.length !== 512) {
throw new RangeError(
`Cannot extract the tar archive: The tarball chunk has an unexpected number of bytes (${value.length})`,
);
}
this.#buffer.push(value);
return this.#buffer.shift();
}
feat(archive): `UntarStream` and `TarStream` (#4548) * refactor(archive): An implementation of Tar as streams * fmt(archive): Ran `deno fmt` * fix(archive): fixed JSDoc examples in tar_streams.ts * fix(archive): fixed JSDoc examples so `deno task test` doesn't complain * fix(archive): lint license error * fix(archive): lint error files not exported * set(archive): Set current time as mtime for default * resolve(archive): resolves comments made * add(archive): `{ mode: 'byob' }` support for TarStream * add(archive): `{ mode: 'byob' }` support for UnTarStream * adjust(archive): The logical flow of a few if statements * tests(archive): Updated Tests for Un/TarStream * fix(archive): TarStream mtime wasn't an octal * fix(archive): TarStream tests * add(archive): Added parsePathname function Added parsePathname function abstracting the logic out of TarStream allowing the developer to validate pathnames before providing them to TarStream hoping it doesn't throw an error and require the archive creation to start all over again. * fix(archive): extra bytes incorrectly appending at the end of files When the appending file was exactly divisible by 512 bytes, an extra 512 bytes was being appending instead of zero to fill in the gap, causing the next header to be read at the wrong place. * adjust(archive): to always return the amount of bytes requested Instead of using enqueue, the leftover bytes are saved for later for the next buffer provided. * tweaks * fix * docs(archive): Link to the spec that they're following * docs(archive): fix spelling * add(archive): function validTarSteamOptions - To make sure, if TarStreamOptions are being provided, that they are in the correct format so as to not create bad tarballs. * add(archive): more tests * fix(archive): validTarStreamOptions * add(archive): tests for validTarStreamOptions * refactor(archive): code to copy the changes made in the @doctor/tar-stream version * test(archive): added from @doctor/tar-stream * chore: nit on anonymous function * refactor(archive): UnTarStream that fixes unexplainable memory leak - The second newest test introduced here '... with invalid ending' seems to detect a memory leak due to an invalid tarball. I couldn't figure out why the memory leak was happening but I know this restructure of the code doesn't have that same memory leak. * chore: fmt * tests(archive): added remaining tests to cover many lines as possible * adjust(archive): remove simplify pathname code * adjust(archive): remove checking for duplicate pathnames in taring process * adjust(archive): A readable will exist on TarEntry unless string values 1-6 * tests(archive): added more tests for higher coverage * adjust(archives): TarStream and UnTarStream to implement TransformStream * docs(archive): moved TarStreamOptions docs into properties. * adjust(archive): TarStreamFile to take a ReadableSteam instead of an Iterable | AsyncIterable * adjust(archive): to use FixedChunkStream instead of rolling it's own implementation * fix(archive): lint error * adjust(archive): Error types and messages * adjust(archive): more Error messages / improve tests * refactor(archive): UnTarStream to return TarStreamChunk instead of TarStreamEntry * fix(archive): JSDoc example * adjust(archive): mode, uid, gid options to be provided as numbers instead of strings. * adjust(archive): TarStream's pathname to be only of type string * fix(archive): prefix/name to ignore everything past the first NULL * adjust(archive): `checksum` and `pad` to not be exposed from UnTarStream * adjust(archive): checksum calculation * change(archive): `.slice` to `.subarray` * doc(archive): "octal number" to "octal literal" * adjust(archive): TarStreamOptions to be optional with defaults * doc(archive): added more docs for the interfaces * docs(archive): denoting defaults * docs(archive): updated for new lint rules * adjust(archive): Tests to use assertRejects where appropriate & add `validPathname` function - The `validPathname` is meant to be a nicer exposed function for users of this lib to validate that their pathnames are valid before pipping it through the TarStream, over exposing parsePathname where the user may be confused about what to do with the result. * adjust(archive): to use `Date.now()` instead of `new Date().getTime()` Co-authored-by: ud2 <sjx233@qq.com> * adjust(archive): mode, uid, and gid to be numbers instead of strings when Untaring * tests(archive): adjust two tests to also validate the contents of the files are valid * adjust(archive): linkname, uname, and gname to follow the same decoding rules as name and prefix * rename(archive): UnTarStream to UntarStream * fix(archive): type that was missed getting updated * tests(archive): adjust check headers test to validate all header properties instead of just pathnames * rename(archive): `pathname` properties to `path` * docs(archive): updated to be more descriptive * docs(archive): Updated error types * adjust(archive): `validPath` to `assertValidPath` * adjust(archive): `validTarStreamOptions` to `assertValidTarStreamOptions` * revert(archive): UntarStream to produce TarStreamEntry instead of TarStreamChunk * refactor: remove redundant `void` return types * docs: cleanup assertion function docs * docs: correct `TarStream` example * docs: minor docs cleanups * refactor: improve error class specificity * docs: add `@experimental` JSDoc tags * docs(archive): Updated examples for `assertValidPath` and `assertValidTarStreamOptions``` * fix(archive): problem with tests - I suspect the problem is that a file that was read by `Deno.readDir` changed size between being read at `Deno.stat` and when `Deno.open` finished pulling it all in. * update error messages * update error messages * fix typos * refactor: tweak error messages * refactor: tweaks and add type field --------- Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com> Co-authored-by: ud2 <sjx233@qq.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
2024-09-02 07:43:22 +00:00
async *#untar(): AsyncGenerator<TarStreamEntry> {
for (let i = 0; i < 2; ++i) {
const { done, value } = await this.#reader.read();
if (done || value.length !== 512) {
feat(archive): `UntarStream` and `TarStream` (#4548) * refactor(archive): An implementation of Tar as streams * fmt(archive): Ran `deno fmt` * fix(archive): fixed JSDoc examples in tar_streams.ts * fix(archive): fixed JSDoc examples so `deno task test` doesn't complain * fix(archive): lint license error * fix(archive): lint error files not exported * set(archive): Set current time as mtime for default * resolve(archive): resolves comments made * add(archive): `{ mode: 'byob' }` support for TarStream * add(archive): `{ mode: 'byob' }` support for UnTarStream * adjust(archive): The logical flow of a few if statements * tests(archive): Updated Tests for Un/TarStream * fix(archive): TarStream mtime wasn't an octal * fix(archive): TarStream tests * add(archive): Added parsePathname function Added parsePathname function abstracting the logic out of TarStream allowing the developer to validate pathnames before providing them to TarStream hoping it doesn't throw an error and require the archive creation to start all over again. * fix(archive): extra bytes incorrectly appending at the end of files When the appending file was exactly divisible by 512 bytes, an extra 512 bytes was being appending instead of zero to fill in the gap, causing the next header to be read at the wrong place. * adjust(archive): to always return the amount of bytes requested Instead of using enqueue, the leftover bytes are saved for later for the next buffer provided. * tweaks * fix * docs(archive): Link to the spec that they're following * docs(archive): fix spelling * add(archive): function validTarSteamOptions - To make sure, if TarStreamOptions are being provided, that they are in the correct format so as to not create bad tarballs. * add(archive): more tests * fix(archive): validTarStreamOptions * add(archive): tests for validTarStreamOptions * refactor(archive): code to copy the changes made in the @doctor/tar-stream version * test(archive): added from @doctor/tar-stream * chore: nit on anonymous function * refactor(archive): UnTarStream that fixes unexplainable memory leak - The second newest test introduced here '... with invalid ending' seems to detect a memory leak due to an invalid tarball. I couldn't figure out why the memory leak was happening but I know this restructure of the code doesn't have that same memory leak. * chore: fmt * tests(archive): added remaining tests to cover many lines as possible * adjust(archive): remove simplify pathname code * adjust(archive): remove checking for duplicate pathnames in taring process * adjust(archive): A readable will exist on TarEntry unless string values 1-6 * tests(archive): added more tests for higher coverage * adjust(archives): TarStream and UnTarStream to implement TransformStream * docs(archive): moved TarStreamOptions docs into properties. * adjust(archive): TarStreamFile to take a ReadableSteam instead of an Iterable | AsyncIterable * adjust(archive): to use FixedChunkStream instead of rolling it's own implementation * fix(archive): lint error * adjust(archive): Error types and messages * adjust(archive): more Error messages / improve tests * refactor(archive): UnTarStream to return TarStreamChunk instead of TarStreamEntry * fix(archive): JSDoc example * adjust(archive): mode, uid, gid options to be provided as numbers instead of strings. * adjust(archive): TarStream's pathname to be only of type string * fix(archive): prefix/name to ignore everything past the first NULL * adjust(archive): `checksum` and `pad` to not be exposed from UnTarStream * adjust(archive): checksum calculation * change(archive): `.slice` to `.subarray` * doc(archive): "octal number" to "octal literal" * adjust(archive): TarStreamOptions to be optional with defaults * doc(archive): added more docs for the interfaces * docs(archive): denoting defaults * docs(archive): updated for new lint rules * adjust(archive): Tests to use assertRejects where appropriate & add `validPathname` function - The `validPathname` is meant to be a nicer exposed function for users of this lib to validate that their pathnames are valid before pipping it through the TarStream, over exposing parsePathname where the user may be confused about what to do with the result. * adjust(archive): to use `Date.now()` instead of `new Date().getTime()` Co-authored-by: ud2 <sjx233@qq.com> * adjust(archive): mode, uid, and gid to be numbers instead of strings when Untaring * tests(archive): adjust two tests to also validate the contents of the files are valid * adjust(archive): linkname, uname, and gname to follow the same decoding rules as name and prefix * rename(archive): UnTarStream to UntarStream * fix(archive): type that was missed getting updated * tests(archive): adjust check headers test to validate all header properties instead of just pathnames * rename(archive): `pathname` properties to `path` * docs(archive): updated to be more descriptive * docs(archive): Updated error types * adjust(archive): `validPath` to `assertValidPath` * adjust(archive): `validTarStreamOptions` to `assertValidTarStreamOptions` * revert(archive): UntarStream to produce TarStreamEntry instead of TarStreamChunk * refactor: remove redundant `void` return types * docs: cleanup assertion function docs * docs: correct `TarStream` example * docs: minor docs cleanups * refactor: improve error class specificity * docs: add `@experimental` JSDoc tags * docs(archive): Updated examples for `assertValidPath` and `assertValidTarStreamOptions``` * fix(archive): problem with tests - I suspect the problem is that a file that was read by `Deno.readDir` changed size between being read at `Deno.stat` and when `Deno.open` finished pulling it all in. * update error messages * update error messages * fix typos * refactor: tweak error messages * refactor: tweaks and add type field --------- Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com> Co-authored-by: ud2 <sjx233@qq.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
2024-09-02 07:43:22 +00:00
throw new RangeError(
"Cannot extract the tar archive: The tarball is too small to be valid",
);
}
this.#buffer.push(value);
}
feat(archive): `UntarStream` and `TarStream` (#4548) * refactor(archive): An implementation of Tar as streams * fmt(archive): Ran `deno fmt` * fix(archive): fixed JSDoc examples in tar_streams.ts * fix(archive): fixed JSDoc examples so `deno task test` doesn't complain * fix(archive): lint license error * fix(archive): lint error files not exported * set(archive): Set current time as mtime for default * resolve(archive): resolves comments made * add(archive): `{ mode: 'byob' }` support for TarStream * add(archive): `{ mode: 'byob' }` support for UnTarStream * adjust(archive): The logical flow of a few if statements * tests(archive): Updated Tests for Un/TarStream * fix(archive): TarStream mtime wasn't an octal * fix(archive): TarStream tests * add(archive): Added parsePathname function Added parsePathname function abstracting the logic out of TarStream allowing the developer to validate pathnames before providing them to TarStream hoping it doesn't throw an error and require the archive creation to start all over again. * fix(archive): extra bytes incorrectly appending at the end of files When the appending file was exactly divisible by 512 bytes, an extra 512 bytes was being appending instead of zero to fill in the gap, causing the next header to be read at the wrong place. * adjust(archive): to always return the amount of bytes requested Instead of using enqueue, the leftover bytes are saved for later for the next buffer provided. * tweaks * fix * docs(archive): Link to the spec that they're following * docs(archive): fix spelling * add(archive): function validTarSteamOptions - To make sure, if TarStreamOptions are being provided, that they are in the correct format so as to not create bad tarballs. * add(archive): more tests * fix(archive): validTarStreamOptions * add(archive): tests for validTarStreamOptions * refactor(archive): code to copy the changes made in the @doctor/tar-stream version * test(archive): added from @doctor/tar-stream * chore: nit on anonymous function * refactor(archive): UnTarStream that fixes unexplainable memory leak - The second newest test introduced here '... with invalid ending' seems to detect a memory leak due to an invalid tarball. I couldn't figure out why the memory leak was happening but I know this restructure of the code doesn't have that same memory leak. * chore: fmt * tests(archive): added remaining tests to cover many lines as possible * adjust(archive): remove simplify pathname code * adjust(archive): remove checking for duplicate pathnames in taring process * adjust(archive): A readable will exist on TarEntry unless string values 1-6 * tests(archive): added more tests for higher coverage * adjust(archives): TarStream and UnTarStream to implement TransformStream * docs(archive): moved TarStreamOptions docs into properties. * adjust(archive): TarStreamFile to take a ReadableSteam instead of an Iterable | AsyncIterable * adjust(archive): to use FixedChunkStream instead of rolling it's own implementation * fix(archive): lint error * adjust(archive): Error types and messages * adjust(archive): more Error messages / improve tests * refactor(archive): UnTarStream to return TarStreamChunk instead of TarStreamEntry * fix(archive): JSDoc example * adjust(archive): mode, uid, gid options to be provided as numbers instead of strings. * adjust(archive): TarStream's pathname to be only of type string * fix(archive): prefix/name to ignore everything past the first NULL * adjust(archive): `checksum` and `pad` to not be exposed from UnTarStream * adjust(archive): checksum calculation * change(archive): `.slice` to `.subarray` * doc(archive): "octal number" to "octal literal" * adjust(archive): TarStreamOptions to be optional with defaults * doc(archive): added more docs for the interfaces * docs(archive): denoting defaults * docs(archive): updated for new lint rules * adjust(archive): Tests to use assertRejects where appropriate & add `validPathname` function - The `validPathname` is meant to be a nicer exposed function for users of this lib to validate that their pathnames are valid before pipping it through the TarStream, over exposing parsePathname where the user may be confused about what to do with the result. * adjust(archive): to use `Date.now()` instead of `new Date().getTime()` Co-authored-by: ud2 <sjx233@qq.com> * adjust(archive): mode, uid, and gid to be numbers instead of strings when Untaring * tests(archive): adjust two tests to also validate the contents of the files are valid * adjust(archive): linkname, uname, and gname to follow the same decoding rules as name and prefix * rename(archive): UnTarStream to UntarStream * fix(archive): type that was missed getting updated * tests(archive): adjust check headers test to validate all header properties instead of just pathnames * rename(archive): `pathname` properties to `path` * docs(archive): updated to be more descriptive * docs(archive): Updated error types * adjust(archive): `validPath` to `assertValidPath` * adjust(archive): `validTarStreamOptions` to `assertValidTarStreamOptions` * revert(archive): UntarStream to produce TarStreamEntry instead of TarStreamChunk * refactor: remove redundant `void` return types * docs: cleanup assertion function docs * docs: correct `TarStream` example * docs: minor docs cleanups * refactor: improve error class specificity * docs: add `@experimental` JSDoc tags * docs(archive): Updated examples for `assertValidPath` and `assertValidTarStreamOptions``` * fix(archive): problem with tests - I suspect the problem is that a file that was read by `Deno.readDir` changed size between being read at `Deno.stat` and when `Deno.open` finished pulling it all in. * update error messages * update error messages * fix typos * refactor: tweak error messages * refactor: tweaks and add type field --------- Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com> Co-authored-by: ud2 <sjx233@qq.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
2024-09-02 07:43:22 +00:00
const decoder = new TextDecoder();
while (true) {
while (this.#lock) {
await new Promise((resolve) => setTimeout(resolve, 0));
}
// Check for premature ending
if (this.#buffer.every((value) => value.every((x) => x === 0))) {
await this.#reader.cancel("Tar stream finished prematurely");
return;
}
const value = await this.#read();
if (value == undefined) {
if (this.#buffer.every((value) => value.every((x) => x === 0))) break;
throw new TypeError(
"Cannot extract the tar archive: The tarball has invalid ending",
);
}
feat(archive): `UntarStream` and `TarStream` (#4548) * refactor(archive): An implementation of Tar as streams * fmt(archive): Ran `deno fmt` * fix(archive): fixed JSDoc examples in tar_streams.ts * fix(archive): fixed JSDoc examples so `deno task test` doesn't complain * fix(archive): lint license error * fix(archive): lint error files not exported * set(archive): Set current time as mtime for default * resolve(archive): resolves comments made * add(archive): `{ mode: 'byob' }` support for TarStream * add(archive): `{ mode: 'byob' }` support for UnTarStream * adjust(archive): The logical flow of a few if statements * tests(archive): Updated Tests for Un/TarStream * fix(archive): TarStream mtime wasn't an octal * fix(archive): TarStream tests * add(archive): Added parsePathname function Added parsePathname function abstracting the logic out of TarStream allowing the developer to validate pathnames before providing them to TarStream hoping it doesn't throw an error and require the archive creation to start all over again. * fix(archive): extra bytes incorrectly appending at the end of files When the appending file was exactly divisible by 512 bytes, an extra 512 bytes was being appending instead of zero to fill in the gap, causing the next header to be read at the wrong place. * adjust(archive): to always return the amount of bytes requested Instead of using enqueue, the leftover bytes are saved for later for the next buffer provided. * tweaks * fix * docs(archive): Link to the spec that they're following * docs(archive): fix spelling * add(archive): function validTarSteamOptions - To make sure, if TarStreamOptions are being provided, that they are in the correct format so as to not create bad tarballs. * add(archive): more tests * fix(archive): validTarStreamOptions * add(archive): tests for validTarStreamOptions * refactor(archive): code to copy the changes made in the @doctor/tar-stream version * test(archive): added from @doctor/tar-stream * chore: nit on anonymous function * refactor(archive): UnTarStream that fixes unexplainable memory leak - The second newest test introduced here '... with invalid ending' seems to detect a memory leak due to an invalid tarball. I couldn't figure out why the memory leak was happening but I know this restructure of the code doesn't have that same memory leak. * chore: fmt * tests(archive): added remaining tests to cover many lines as possible * adjust(archive): remove simplify pathname code * adjust(archive): remove checking for duplicate pathnames in taring process * adjust(archive): A readable will exist on TarEntry unless string values 1-6 * tests(archive): added more tests for higher coverage * adjust(archives): TarStream and UnTarStream to implement TransformStream * docs(archive): moved TarStreamOptions docs into properties. * adjust(archive): TarStreamFile to take a ReadableSteam instead of an Iterable | AsyncIterable * adjust(archive): to use FixedChunkStream instead of rolling it's own implementation * fix(archive): lint error * adjust(archive): Error types and messages * adjust(archive): more Error messages / improve tests * refactor(archive): UnTarStream to return TarStreamChunk instead of TarStreamEntry * fix(archive): JSDoc example * adjust(archive): mode, uid, gid options to be provided as numbers instead of strings. * adjust(archive): TarStream's pathname to be only of type string * fix(archive): prefix/name to ignore everything past the first NULL * adjust(archive): `checksum` and `pad` to not be exposed from UnTarStream * adjust(archive): checksum calculation * change(archive): `.slice` to `.subarray` * doc(archive): "octal number" to "octal literal" * adjust(archive): TarStreamOptions to be optional with defaults * doc(archive): added more docs for the interfaces * docs(archive): denoting defaults * docs(archive): updated for new lint rules * adjust(archive): Tests to use assertRejects where appropriate & add `validPathname` function - The `validPathname` is meant to be a nicer exposed function for users of this lib to validate that their pathnames are valid before pipping it through the TarStream, over exposing parsePathname where the user may be confused about what to do with the result. * adjust(archive): to use `Date.now()` instead of `new Date().getTime()` Co-authored-by: ud2 <sjx233@qq.com> * adjust(archive): mode, uid, and gid to be numbers instead of strings when Untaring * tests(archive): adjust two tests to also validate the contents of the files are valid * adjust(archive): linkname, uname, and gname to follow the same decoding rules as name and prefix * rename(archive): UnTarStream to UntarStream * fix(archive): type that was missed getting updated * tests(archive): adjust check headers test to validate all header properties instead of just pathnames * rename(archive): `pathname` properties to `path` * docs(archive): updated to be more descriptive * docs(archive): Updated error types * adjust(archive): `validPath` to `assertValidPath` * adjust(archive): `validTarStreamOptions` to `assertValidTarStreamOptions` * revert(archive): UntarStream to produce TarStreamEntry instead of TarStreamChunk * refactor: remove redundant `void` return types * docs: cleanup assertion function docs * docs: correct `TarStream` example * docs: minor docs cleanups * refactor: improve error class specificity * docs: add `@experimental` JSDoc tags * docs(archive): Updated examples for `assertValidPath` and `assertValidTarStreamOptions``` * fix(archive): problem with tests - I suspect the problem is that a file that was read by `Deno.readDir` changed size between being read at `Deno.stat` and when `Deno.open` finished pulling it all in. * update error messages * update error messages * fix typos * refactor: tweak error messages * refactor: tweaks and add type field --------- Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com> Co-authored-by: ud2 <sjx233@qq.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
2024-09-02 07:43:22 +00:00
// Validate Checksum
const checksum = parseInt(
decoder.decode(value.subarray(148, 156 - 2)),
8,
);
value.fill(32, 148, 156);
if (value.reduce((x, y) => x + y) !== checksum) {
throw new SyntaxError(
"Cannot extract the tar archive: An archive entry has invalid header checksum",
);
}
// Decode Header
let header: OldStyleFormat | PosixUstarFormat = {
name: decoder.decode(value.subarray(0, 100)).split("\0")[0]!,
mode: parseInt(decoder.decode(value.subarray(100, 108 - 2))),
uid: parseInt(decoder.decode(value.subarray(108, 116 - 2))),
gid: parseInt(decoder.decode(value.subarray(116, 124 - 2))),
size: parseInt(decoder.decode(value.subarray(124, 136)).trimEnd(), 8),
mtime: parseInt(decoder.decode(value.subarray(136, 148 - 1)), 8),
typeflag: decoder.decode(value.subarray(156, 157)),
linkname: decoder.decode(value.subarray(157, 257)).split("\0")[0]!,
};
if (header.typeflag === "\0") header.typeflag = "0";
// "ustar\u000000"
if (
[117, 115, 116, 97, 114, 0, 48, 48].every((byte, i) =>
value[i + 257] === byte
)
) {
header = {
...header,
magic: decoder.decode(value.subarray(257, 263)),
version: decoder.decode(value.subarray(263, 265)),
uname: decoder.decode(value.subarray(265, 297)).split("\0")[0]!,
gname: decoder.decode(value.subarray(297, 329)).split("\0")[0]!,
devmajor: decoder.decode(value.subarray(329, 337)).replaceAll(
"\0",
"",
),
devminor: decoder.decode(value.subarray(337, 345)).replaceAll(
"\0",
"",
),
prefix: decoder.decode(value.subarray(345, 500)).split("\0")[0]!,
};
}
const entry: TarStreamEntry = {
path: (
"prefix" in header && header.prefix.length ? header.prefix + "/" : ""
) + header.name,
feat(archive): `UntarStream` and `TarStream` (#4548) * refactor(archive): An implementation of Tar as streams * fmt(archive): Ran `deno fmt` * fix(archive): fixed JSDoc examples in tar_streams.ts * fix(archive): fixed JSDoc examples so `deno task test` doesn't complain * fix(archive): lint license error * fix(archive): lint error files not exported * set(archive): Set current time as mtime for default * resolve(archive): resolves comments made * add(archive): `{ mode: 'byob' }` support for TarStream * add(archive): `{ mode: 'byob' }` support for UnTarStream * adjust(archive): The logical flow of a few if statements * tests(archive): Updated Tests for Un/TarStream * fix(archive): TarStream mtime wasn't an octal * fix(archive): TarStream tests * add(archive): Added parsePathname function Added parsePathname function abstracting the logic out of TarStream allowing the developer to validate pathnames before providing them to TarStream hoping it doesn't throw an error and require the archive creation to start all over again. * fix(archive): extra bytes incorrectly appending at the end of files When the appending file was exactly divisible by 512 bytes, an extra 512 bytes was being appending instead of zero to fill in the gap, causing the next header to be read at the wrong place. * adjust(archive): to always return the amount of bytes requested Instead of using enqueue, the leftover bytes are saved for later for the next buffer provided. * tweaks * fix * docs(archive): Link to the spec that they're following * docs(archive): fix spelling * add(archive): function validTarSteamOptions - To make sure, if TarStreamOptions are being provided, that they are in the correct format so as to not create bad tarballs. * add(archive): more tests * fix(archive): validTarStreamOptions * add(archive): tests for validTarStreamOptions * refactor(archive): code to copy the changes made in the @doctor/tar-stream version * test(archive): added from @doctor/tar-stream * chore: nit on anonymous function * refactor(archive): UnTarStream that fixes unexplainable memory leak - The second newest test introduced here '... with invalid ending' seems to detect a memory leak due to an invalid tarball. I couldn't figure out why the memory leak was happening but I know this restructure of the code doesn't have that same memory leak. * chore: fmt * tests(archive): added remaining tests to cover many lines as possible * adjust(archive): remove simplify pathname code * adjust(archive): remove checking for duplicate pathnames in taring process * adjust(archive): A readable will exist on TarEntry unless string values 1-6 * tests(archive): added more tests for higher coverage * adjust(archives): TarStream and UnTarStream to implement TransformStream * docs(archive): moved TarStreamOptions docs into properties. * adjust(archive): TarStreamFile to take a ReadableSteam instead of an Iterable | AsyncIterable * adjust(archive): to use FixedChunkStream instead of rolling it's own implementation * fix(archive): lint error * adjust(archive): Error types and messages * adjust(archive): more Error messages / improve tests * refactor(archive): UnTarStream to return TarStreamChunk instead of TarStreamEntry * fix(archive): JSDoc example * adjust(archive): mode, uid, gid options to be provided as numbers instead of strings. * adjust(archive): TarStream's pathname to be only of type string * fix(archive): prefix/name to ignore everything past the first NULL * adjust(archive): `checksum` and `pad` to not be exposed from UnTarStream * adjust(archive): checksum calculation * change(archive): `.slice` to `.subarray` * doc(archive): "octal number" to "octal literal" * adjust(archive): TarStreamOptions to be optional with defaults * doc(archive): added more docs for the interfaces * docs(archive): denoting defaults * docs(archive): updated for new lint rules * adjust(archive): Tests to use assertRejects where appropriate & add `validPathname` function - The `validPathname` is meant to be a nicer exposed function for users of this lib to validate that their pathnames are valid before pipping it through the TarStream, over exposing parsePathname where the user may be confused about what to do with the result. * adjust(archive): to use `Date.now()` instead of `new Date().getTime()` Co-authored-by: ud2 <sjx233@qq.com> * adjust(archive): mode, uid, and gid to be numbers instead of strings when Untaring * tests(archive): adjust two tests to also validate the contents of the files are valid * adjust(archive): linkname, uname, and gname to follow the same decoding rules as name and prefix * rename(archive): UnTarStream to UntarStream * fix(archive): type that was missed getting updated * tests(archive): adjust check headers test to validate all header properties instead of just pathnames * rename(archive): `pathname` properties to `path` * docs(archive): updated to be more descriptive * docs(archive): Updated error types * adjust(archive): `validPath` to `assertValidPath` * adjust(archive): `validTarStreamOptions` to `assertValidTarStreamOptions` * revert(archive): UntarStream to produce TarStreamEntry instead of TarStreamChunk * refactor: remove redundant `void` return types * docs: cleanup assertion function docs * docs: correct `TarStream` example * docs: minor docs cleanups * refactor: improve error class specificity * docs: add `@experimental` JSDoc tags * docs(archive): Updated examples for `assertValidPath` and `assertValidTarStreamOptions``` * fix(archive): problem with tests - I suspect the problem is that a file that was read by `Deno.readDir` changed size between being read at `Deno.stat` and when `Deno.open` finished pulling it all in. * update error messages * update error messages * fix typos * refactor: tweak error messages * refactor: tweaks and add type field --------- Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com> Co-authored-by: ud2 <sjx233@qq.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
2024-09-02 07:43:22 +00:00
header,
};
if (!["1", "2", "3", "4", "5", "6"].includes(header.typeflag)) {
entry.readable = this.#readableFile(header.size);
}
yield entry;
feat(archive): `UntarStream` and `TarStream` (#4548) * refactor(archive): An implementation of Tar as streams * fmt(archive): Ran `deno fmt` * fix(archive): fixed JSDoc examples in tar_streams.ts * fix(archive): fixed JSDoc examples so `deno task test` doesn't complain * fix(archive): lint license error * fix(archive): lint error files not exported * set(archive): Set current time as mtime for default * resolve(archive): resolves comments made * add(archive): `{ mode: 'byob' }` support for TarStream * add(archive): `{ mode: 'byob' }` support for UnTarStream * adjust(archive): The logical flow of a few if statements * tests(archive): Updated Tests for Un/TarStream * fix(archive): TarStream mtime wasn't an octal * fix(archive): TarStream tests * add(archive): Added parsePathname function Added parsePathname function abstracting the logic out of TarStream allowing the developer to validate pathnames before providing them to TarStream hoping it doesn't throw an error and require the archive creation to start all over again. * fix(archive): extra bytes incorrectly appending at the end of files When the appending file was exactly divisible by 512 bytes, an extra 512 bytes was being appending instead of zero to fill in the gap, causing the next header to be read at the wrong place. * adjust(archive): to always return the amount of bytes requested Instead of using enqueue, the leftover bytes are saved for later for the next buffer provided. * tweaks * fix * docs(archive): Link to the spec that they're following * docs(archive): fix spelling * add(archive): function validTarSteamOptions - To make sure, if TarStreamOptions are being provided, that they are in the correct format so as to not create bad tarballs. * add(archive): more tests * fix(archive): validTarStreamOptions * add(archive): tests for validTarStreamOptions * refactor(archive): code to copy the changes made in the @doctor/tar-stream version * test(archive): added from @doctor/tar-stream * chore: nit on anonymous function * refactor(archive): UnTarStream that fixes unexplainable memory leak - The second newest test introduced here '... with invalid ending' seems to detect a memory leak due to an invalid tarball. I couldn't figure out why the memory leak was happening but I know this restructure of the code doesn't have that same memory leak. * chore: fmt * tests(archive): added remaining tests to cover many lines as possible * adjust(archive): remove simplify pathname code * adjust(archive): remove checking for duplicate pathnames in taring process * adjust(archive): A readable will exist on TarEntry unless string values 1-6 * tests(archive): added more tests for higher coverage * adjust(archives): TarStream and UnTarStream to implement TransformStream * docs(archive): moved TarStreamOptions docs into properties. * adjust(archive): TarStreamFile to take a ReadableSteam instead of an Iterable | AsyncIterable * adjust(archive): to use FixedChunkStream instead of rolling it's own implementation * fix(archive): lint error * adjust(archive): Error types and messages * adjust(archive): more Error messages / improve tests * refactor(archive): UnTarStream to return TarStreamChunk instead of TarStreamEntry * fix(archive): JSDoc example * adjust(archive): mode, uid, gid options to be provided as numbers instead of strings. * adjust(archive): TarStream's pathname to be only of type string * fix(archive): prefix/name to ignore everything past the first NULL * adjust(archive): `checksum` and `pad` to not be exposed from UnTarStream * adjust(archive): checksum calculation * change(archive): `.slice` to `.subarray` * doc(archive): "octal number" to "octal literal" * adjust(archive): TarStreamOptions to be optional with defaults * doc(archive): added more docs for the interfaces * docs(archive): denoting defaults * docs(archive): updated for new lint rules * adjust(archive): Tests to use assertRejects where appropriate & add `validPathname` function - The `validPathname` is meant to be a nicer exposed function for users of this lib to validate that their pathnames are valid before pipping it through the TarStream, over exposing parsePathname where the user may be confused about what to do with the result. * adjust(archive): to use `Date.now()` instead of `new Date().getTime()` Co-authored-by: ud2 <sjx233@qq.com> * adjust(archive): mode, uid, and gid to be numbers instead of strings when Untaring * tests(archive): adjust two tests to also validate the contents of the files are valid * adjust(archive): linkname, uname, and gname to follow the same decoding rules as name and prefix * rename(archive): UnTarStream to UntarStream * fix(archive): type that was missed getting updated * tests(archive): adjust check headers test to validate all header properties instead of just pathnames * rename(archive): `pathname` properties to `path` * docs(archive): updated to be more descriptive * docs(archive): Updated error types * adjust(archive): `validPath` to `assertValidPath` * adjust(archive): `validTarStreamOptions` to `assertValidTarStreamOptions` * revert(archive): UntarStream to produce TarStreamEntry instead of TarStreamChunk * refactor: remove redundant `void` return types * docs: cleanup assertion function docs * docs: correct `TarStream` example * docs: minor docs cleanups * refactor: improve error class specificity * docs: add `@experimental` JSDoc tags * docs(archive): Updated examples for `assertValidPath` and `assertValidTarStreamOptions``` * fix(archive): problem with tests - I suspect the problem is that a file that was read by `Deno.readDir` changed size between being read at `Deno.stat` and when `Deno.open` finished pulling it all in. * update error messages * update error messages * fix typos * refactor: tweak error messages * refactor: tweaks and add type field --------- Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com> Co-authored-by: ud2 <sjx233@qq.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
2024-09-02 07:43:22 +00:00
}
}
async *#genFile(size: number): AsyncGenerator<Uint8Array> {
for (let i = Math.ceil(size / 512); i > 0; --i) {
const value = await this.#read();
if (value == undefined) {
feat(archive): `UntarStream` and `TarStream` (#4548) * refactor(archive): An implementation of Tar as streams * fmt(archive): Ran `deno fmt` * fix(archive): fixed JSDoc examples in tar_streams.ts * fix(archive): fixed JSDoc examples so `deno task test` doesn't complain * fix(archive): lint license error * fix(archive): lint error files not exported * set(archive): Set current time as mtime for default * resolve(archive): resolves comments made * add(archive): `{ mode: 'byob' }` support for TarStream * add(archive): `{ mode: 'byob' }` support for UnTarStream * adjust(archive): The logical flow of a few if statements * tests(archive): Updated Tests for Un/TarStream * fix(archive): TarStream mtime wasn't an octal * fix(archive): TarStream tests * add(archive): Added parsePathname function Added parsePathname function abstracting the logic out of TarStream allowing the developer to validate pathnames before providing them to TarStream hoping it doesn't throw an error and require the archive creation to start all over again. * fix(archive): extra bytes incorrectly appending at the end of files When the appending file was exactly divisible by 512 bytes, an extra 512 bytes was being appending instead of zero to fill in the gap, causing the next header to be read at the wrong place. * adjust(archive): to always return the amount of bytes requested Instead of using enqueue, the leftover bytes are saved for later for the next buffer provided. * tweaks * fix * docs(archive): Link to the spec that they're following * docs(archive): fix spelling * add(archive): function validTarSteamOptions - To make sure, if TarStreamOptions are being provided, that they are in the correct format so as to not create bad tarballs. * add(archive): more tests * fix(archive): validTarStreamOptions * add(archive): tests for validTarStreamOptions * refactor(archive): code to copy the changes made in the @doctor/tar-stream version * test(archive): added from @doctor/tar-stream * chore: nit on anonymous function * refactor(archive): UnTarStream that fixes unexplainable memory leak - The second newest test introduced here '... with invalid ending' seems to detect a memory leak due to an invalid tarball. I couldn't figure out why the memory leak was happening but I know this restructure of the code doesn't have that same memory leak. * chore: fmt * tests(archive): added remaining tests to cover many lines as possible * adjust(archive): remove simplify pathname code * adjust(archive): remove checking for duplicate pathnames in taring process * adjust(archive): A readable will exist on TarEntry unless string values 1-6 * tests(archive): added more tests for higher coverage * adjust(archives): TarStream and UnTarStream to implement TransformStream * docs(archive): moved TarStreamOptions docs into properties. * adjust(archive): TarStreamFile to take a ReadableSteam instead of an Iterable | AsyncIterable * adjust(archive): to use FixedChunkStream instead of rolling it's own implementation * fix(archive): lint error * adjust(archive): Error types and messages * adjust(archive): more Error messages / improve tests * refactor(archive): UnTarStream to return TarStreamChunk instead of TarStreamEntry * fix(archive): JSDoc example * adjust(archive): mode, uid, gid options to be provided as numbers instead of strings. * adjust(archive): TarStream's pathname to be only of type string * fix(archive): prefix/name to ignore everything past the first NULL * adjust(archive): `checksum` and `pad` to not be exposed from UnTarStream * adjust(archive): checksum calculation * change(archive): `.slice` to `.subarray` * doc(archive): "octal number" to "octal literal" * adjust(archive): TarStreamOptions to be optional with defaults * doc(archive): added more docs for the interfaces * docs(archive): denoting defaults * docs(archive): updated for new lint rules * adjust(archive): Tests to use assertRejects where appropriate & add `validPathname` function - The `validPathname` is meant to be a nicer exposed function for users of this lib to validate that their pathnames are valid before pipping it through the TarStream, over exposing parsePathname where the user may be confused about what to do with the result. * adjust(archive): to use `Date.now()` instead of `new Date().getTime()` Co-authored-by: ud2 <sjx233@qq.com> * adjust(archive): mode, uid, and gid to be numbers instead of strings when Untaring * tests(archive): adjust two tests to also validate the contents of the files are valid * adjust(archive): linkname, uname, and gname to follow the same decoding rules as name and prefix * rename(archive): UnTarStream to UntarStream * fix(archive): type that was missed getting updated * tests(archive): adjust check headers test to validate all header properties instead of just pathnames * rename(archive): `pathname` properties to `path` * docs(archive): updated to be more descriptive * docs(archive): Updated error types * adjust(archive): `validPath` to `assertValidPath` * adjust(archive): `validTarStreamOptions` to `assertValidTarStreamOptions` * revert(archive): UntarStream to produce TarStreamEntry instead of TarStreamChunk * refactor: remove redundant `void` return types * docs: cleanup assertion function docs * docs: correct `TarStream` example * docs: minor docs cleanups * refactor: improve error class specificity * docs: add `@experimental` JSDoc tags * docs(archive): Updated examples for `assertValidPath` and `assertValidTarStreamOptions``` * fix(archive): problem with tests - I suspect the problem is that a file that was read by `Deno.readDir` changed size between being read at `Deno.stat` and when `Deno.open` finished pulling it all in. * update error messages * update error messages * fix typos * refactor: tweak error messages * refactor: tweaks and add type field --------- Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com> Co-authored-by: ud2 <sjx233@qq.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
2024-09-02 07:43:22 +00:00
throw new SyntaxError(
"Cannot extract the tar archive: Unexpected end of Tarball",
);
}
if (i === 1 && size % 512) yield value.subarray(0, size % 512);
else yield value;
}
}
#readableFile(size: number): ReadableStream<Uint8Array> {
this.#lock = true;
const releaseLock = () => this.#lock = false;
const gen = this.#genFile(size);
return new ReadableStream({
type: "bytes",
async pull(controller) {
const { done, value } = await gen.next();
if (done) {
releaseLock();
controller.close();
return controller.byobRequest?.respond(0);
}
if (controller.byobRequest?.view) {
const buffer = new Uint8Array(controller.byobRequest.view.buffer);
const size = buffer.length;
if (size < value.length) {
buffer.set(value.slice(0, size));
controller.byobRequest.respond(size);
controller.enqueue(value.slice(size));
} else {
buffer.set(value);
controller.byobRequest.respond(value.length);
}
} else {
controller.enqueue(value);
}
},
async cancel() {
// deno-lint-ignore no-empty
for await (const _ of gen) {}
releaseLock();
},
});
}
/**
* The ReadableStream
*
* @return ReadableStream<TarStreamChunk>
*
* @example Usage
* ```ts ignore
* import { UntarStream } from "@std/tar/untar-stream";
feat(archive): `UntarStream` and `TarStream` (#4548) * refactor(archive): An implementation of Tar as streams * fmt(archive): Ran `deno fmt` * fix(archive): fixed JSDoc examples in tar_streams.ts * fix(archive): fixed JSDoc examples so `deno task test` doesn't complain * fix(archive): lint license error * fix(archive): lint error files not exported * set(archive): Set current time as mtime for default * resolve(archive): resolves comments made * add(archive): `{ mode: 'byob' }` support for TarStream * add(archive): `{ mode: 'byob' }` support for UnTarStream * adjust(archive): The logical flow of a few if statements * tests(archive): Updated Tests for Un/TarStream * fix(archive): TarStream mtime wasn't an octal * fix(archive): TarStream tests * add(archive): Added parsePathname function Added parsePathname function abstracting the logic out of TarStream allowing the developer to validate pathnames before providing them to TarStream hoping it doesn't throw an error and require the archive creation to start all over again. * fix(archive): extra bytes incorrectly appending at the end of files When the appending file was exactly divisible by 512 bytes, an extra 512 bytes was being appending instead of zero to fill in the gap, causing the next header to be read at the wrong place. * adjust(archive): to always return the amount of bytes requested Instead of using enqueue, the leftover bytes are saved for later for the next buffer provided. * tweaks * fix * docs(archive): Link to the spec that they're following * docs(archive): fix spelling * add(archive): function validTarSteamOptions - To make sure, if TarStreamOptions are being provided, that they are in the correct format so as to not create bad tarballs. * add(archive): more tests * fix(archive): validTarStreamOptions * add(archive): tests for validTarStreamOptions * refactor(archive): code to copy the changes made in the @doctor/tar-stream version * test(archive): added from @doctor/tar-stream * chore: nit on anonymous function * refactor(archive): UnTarStream that fixes unexplainable memory leak - The second newest test introduced here '... with invalid ending' seems to detect a memory leak due to an invalid tarball. I couldn't figure out why the memory leak was happening but I know this restructure of the code doesn't have that same memory leak. * chore: fmt * tests(archive): added remaining tests to cover many lines as possible * adjust(archive): remove simplify pathname code * adjust(archive): remove checking for duplicate pathnames in taring process * adjust(archive): A readable will exist on TarEntry unless string values 1-6 * tests(archive): added more tests for higher coverage * adjust(archives): TarStream and UnTarStream to implement TransformStream * docs(archive): moved TarStreamOptions docs into properties. * adjust(archive): TarStreamFile to take a ReadableSteam instead of an Iterable | AsyncIterable * adjust(archive): to use FixedChunkStream instead of rolling it's own implementation * fix(archive): lint error * adjust(archive): Error types and messages * adjust(archive): more Error messages / improve tests * refactor(archive): UnTarStream to return TarStreamChunk instead of TarStreamEntry * fix(archive): JSDoc example * adjust(archive): mode, uid, gid options to be provided as numbers instead of strings. * adjust(archive): TarStream's pathname to be only of type string * fix(archive): prefix/name to ignore everything past the first NULL * adjust(archive): `checksum` and `pad` to not be exposed from UnTarStream * adjust(archive): checksum calculation * change(archive): `.slice` to `.subarray` * doc(archive): "octal number" to "octal literal" * adjust(archive): TarStreamOptions to be optional with defaults * doc(archive): added more docs for the interfaces * docs(archive): denoting defaults * docs(archive): updated for new lint rules * adjust(archive): Tests to use assertRejects where appropriate & add `validPathname` function - The `validPathname` is meant to be a nicer exposed function for users of this lib to validate that their pathnames are valid before pipping it through the TarStream, over exposing parsePathname where the user may be confused about what to do with the result. * adjust(archive): to use `Date.now()` instead of `new Date().getTime()` Co-authored-by: ud2 <sjx233@qq.com> * adjust(archive): mode, uid, and gid to be numbers instead of strings when Untaring * tests(archive): adjust two tests to also validate the contents of the files are valid * adjust(archive): linkname, uname, and gname to follow the same decoding rules as name and prefix * rename(archive): UnTarStream to UntarStream * fix(archive): type that was missed getting updated * tests(archive): adjust check headers test to validate all header properties instead of just pathnames * rename(archive): `pathname` properties to `path` * docs(archive): updated to be more descriptive * docs(archive): Updated error types * adjust(archive): `validPath` to `assertValidPath` * adjust(archive): `validTarStreamOptions` to `assertValidTarStreamOptions` * revert(archive): UntarStream to produce TarStreamEntry instead of TarStreamChunk * refactor: remove redundant `void` return types * docs: cleanup assertion function docs * docs: correct `TarStream` example * docs: minor docs cleanups * refactor: improve error class specificity * docs: add `@experimental` JSDoc tags * docs(archive): Updated examples for `assertValidPath` and `assertValidTarStreamOptions``` * fix(archive): problem with tests - I suspect the problem is that a file that was read by `Deno.readDir` changed size between being read at `Deno.stat` and when `Deno.open` finished pulling it all in. * update error messages * update error messages * fix typos * refactor: tweak error messages * refactor: tweaks and add type field --------- Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com> Co-authored-by: ud2 <sjx233@qq.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
2024-09-02 07:43:22 +00:00
* import { dirname, normalize } from "@std/path";
*
* for await (
* const entry of (await Deno.open("./out.tar.gz"))
* .readable
* .pipeThrough(new DecompressionStream("gzip"))
* .pipeThrough(new UntarStream())
* ) {
* const path = normalize(entry.path);
* await Deno.mkdir(dirname(path), { recursive: true });
feat(archive): `UntarStream` and `TarStream` (#4548) * refactor(archive): An implementation of Tar as streams * fmt(archive): Ran `deno fmt` * fix(archive): fixed JSDoc examples in tar_streams.ts * fix(archive): fixed JSDoc examples so `deno task test` doesn't complain * fix(archive): lint license error * fix(archive): lint error files not exported * set(archive): Set current time as mtime for default * resolve(archive): resolves comments made * add(archive): `{ mode: 'byob' }` support for TarStream * add(archive): `{ mode: 'byob' }` support for UnTarStream * adjust(archive): The logical flow of a few if statements * tests(archive): Updated Tests for Un/TarStream * fix(archive): TarStream mtime wasn't an octal * fix(archive): TarStream tests * add(archive): Added parsePathname function Added parsePathname function abstracting the logic out of TarStream allowing the developer to validate pathnames before providing them to TarStream hoping it doesn't throw an error and require the archive creation to start all over again. * fix(archive): extra bytes incorrectly appending at the end of files When the appending file was exactly divisible by 512 bytes, an extra 512 bytes was being appending instead of zero to fill in the gap, causing the next header to be read at the wrong place. * adjust(archive): to always return the amount of bytes requested Instead of using enqueue, the leftover bytes are saved for later for the next buffer provided. * tweaks * fix * docs(archive): Link to the spec that they're following * docs(archive): fix spelling * add(archive): function validTarSteamOptions - To make sure, if TarStreamOptions are being provided, that they are in the correct format so as to not create bad tarballs. * add(archive): more tests * fix(archive): validTarStreamOptions * add(archive): tests for validTarStreamOptions * refactor(archive): code to copy the changes made in the @doctor/tar-stream version * test(archive): added from @doctor/tar-stream * chore: nit on anonymous function * refactor(archive): UnTarStream that fixes unexplainable memory leak - The second newest test introduced here '... with invalid ending' seems to detect a memory leak due to an invalid tarball. I couldn't figure out why the memory leak was happening but I know this restructure of the code doesn't have that same memory leak. * chore: fmt * tests(archive): added remaining tests to cover many lines as possible * adjust(archive): remove simplify pathname code * adjust(archive): remove checking for duplicate pathnames in taring process * adjust(archive): A readable will exist on TarEntry unless string values 1-6 * tests(archive): added more tests for higher coverage * adjust(archives): TarStream and UnTarStream to implement TransformStream * docs(archive): moved TarStreamOptions docs into properties. * adjust(archive): TarStreamFile to take a ReadableSteam instead of an Iterable | AsyncIterable * adjust(archive): to use FixedChunkStream instead of rolling it's own implementation * fix(archive): lint error * adjust(archive): Error types and messages * adjust(archive): more Error messages / improve tests * refactor(archive): UnTarStream to return TarStreamChunk instead of TarStreamEntry * fix(archive): JSDoc example * adjust(archive): mode, uid, gid options to be provided as numbers instead of strings. * adjust(archive): TarStream's pathname to be only of type string * fix(archive): prefix/name to ignore everything past the first NULL * adjust(archive): `checksum` and `pad` to not be exposed from UnTarStream * adjust(archive): checksum calculation * change(archive): `.slice` to `.subarray` * doc(archive): "octal number" to "octal literal" * adjust(archive): TarStreamOptions to be optional with defaults * doc(archive): added more docs for the interfaces * docs(archive): denoting defaults * docs(archive): updated for new lint rules * adjust(archive): Tests to use assertRejects where appropriate & add `validPathname` function - The `validPathname` is meant to be a nicer exposed function for users of this lib to validate that their pathnames are valid before pipping it through the TarStream, over exposing parsePathname where the user may be confused about what to do with the result. * adjust(archive): to use `Date.now()` instead of `new Date().getTime()` Co-authored-by: ud2 <sjx233@qq.com> * adjust(archive): mode, uid, and gid to be numbers instead of strings when Untaring * tests(archive): adjust two tests to also validate the contents of the files are valid * adjust(archive): linkname, uname, and gname to follow the same decoding rules as name and prefix * rename(archive): UnTarStream to UntarStream * fix(archive): type that was missed getting updated * tests(archive): adjust check headers test to validate all header properties instead of just pathnames * rename(archive): `pathname` properties to `path` * docs(archive): updated to be more descriptive * docs(archive): Updated error types * adjust(archive): `validPath` to `assertValidPath` * adjust(archive): `validTarStreamOptions` to `assertValidTarStreamOptions` * revert(archive): UntarStream to produce TarStreamEntry instead of TarStreamChunk * refactor: remove redundant `void` return types * docs: cleanup assertion function docs * docs: correct `TarStream` example * docs: minor docs cleanups * refactor: improve error class specificity * docs: add `@experimental` JSDoc tags * docs(archive): Updated examples for `assertValidPath` and `assertValidTarStreamOptions``` * fix(archive): problem with tests - I suspect the problem is that a file that was read by `Deno.readDir` changed size between being read at `Deno.stat` and when `Deno.open` finished pulling it all in. * update error messages * update error messages * fix typos * refactor: tweak error messages * refactor: tweaks and add type field --------- Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com> Co-authored-by: ud2 <sjx233@qq.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
2024-09-02 07:43:22 +00:00
* await entry.readable?.pipeTo((await Deno.create(path)).writable);
* }
* ```
*/
get readable(): ReadableStream<TarStreamEntry> {
return this.#readable;
}
/**
* The WritableStream
*
* @return WritableStream<Uint8Array>
*
* @example Usage
* ```ts ignore
* import { UntarStream } from "@std/tar/untar-stream";
feat(archive): `UntarStream` and `TarStream` (#4548) * refactor(archive): An implementation of Tar as streams * fmt(archive): Ran `deno fmt` * fix(archive): fixed JSDoc examples in tar_streams.ts * fix(archive): fixed JSDoc examples so `deno task test` doesn't complain * fix(archive): lint license error * fix(archive): lint error files not exported * set(archive): Set current time as mtime for default * resolve(archive): resolves comments made * add(archive): `{ mode: 'byob' }` support for TarStream * add(archive): `{ mode: 'byob' }` support for UnTarStream * adjust(archive): The logical flow of a few if statements * tests(archive): Updated Tests for Un/TarStream * fix(archive): TarStream mtime wasn't an octal * fix(archive): TarStream tests * add(archive): Added parsePathname function Added parsePathname function abstracting the logic out of TarStream allowing the developer to validate pathnames before providing them to TarStream hoping it doesn't throw an error and require the archive creation to start all over again. * fix(archive): extra bytes incorrectly appending at the end of files When the appending file was exactly divisible by 512 bytes, an extra 512 bytes was being appending instead of zero to fill in the gap, causing the next header to be read at the wrong place. * adjust(archive): to always return the amount of bytes requested Instead of using enqueue, the leftover bytes are saved for later for the next buffer provided. * tweaks * fix * docs(archive): Link to the spec that they're following * docs(archive): fix spelling * add(archive): function validTarSteamOptions - To make sure, if TarStreamOptions are being provided, that they are in the correct format so as to not create bad tarballs. * add(archive): more tests * fix(archive): validTarStreamOptions * add(archive): tests for validTarStreamOptions * refactor(archive): code to copy the changes made in the @doctor/tar-stream version * test(archive): added from @doctor/tar-stream * chore: nit on anonymous function * refactor(archive): UnTarStream that fixes unexplainable memory leak - The second newest test introduced here '... with invalid ending' seems to detect a memory leak due to an invalid tarball. I couldn't figure out why the memory leak was happening but I know this restructure of the code doesn't have that same memory leak. * chore: fmt * tests(archive): added remaining tests to cover many lines as possible * adjust(archive): remove simplify pathname code * adjust(archive): remove checking for duplicate pathnames in taring process * adjust(archive): A readable will exist on TarEntry unless string values 1-6 * tests(archive): added more tests for higher coverage * adjust(archives): TarStream and UnTarStream to implement TransformStream * docs(archive): moved TarStreamOptions docs into properties. * adjust(archive): TarStreamFile to take a ReadableSteam instead of an Iterable | AsyncIterable * adjust(archive): to use FixedChunkStream instead of rolling it's own implementation * fix(archive): lint error * adjust(archive): Error types and messages * adjust(archive): more Error messages / improve tests * refactor(archive): UnTarStream to return TarStreamChunk instead of TarStreamEntry * fix(archive): JSDoc example * adjust(archive): mode, uid, gid options to be provided as numbers instead of strings. * adjust(archive): TarStream's pathname to be only of type string * fix(archive): prefix/name to ignore everything past the first NULL * adjust(archive): `checksum` and `pad` to not be exposed from UnTarStream * adjust(archive): checksum calculation * change(archive): `.slice` to `.subarray` * doc(archive): "octal number" to "octal literal" * adjust(archive): TarStreamOptions to be optional with defaults * doc(archive): added more docs for the interfaces * docs(archive): denoting defaults * docs(archive): updated for new lint rules * adjust(archive): Tests to use assertRejects where appropriate & add `validPathname` function - The `validPathname` is meant to be a nicer exposed function for users of this lib to validate that their pathnames are valid before pipping it through the TarStream, over exposing parsePathname where the user may be confused about what to do with the result. * adjust(archive): to use `Date.now()` instead of `new Date().getTime()` Co-authored-by: ud2 <sjx233@qq.com> * adjust(archive): mode, uid, and gid to be numbers instead of strings when Untaring * tests(archive): adjust two tests to also validate the contents of the files are valid * adjust(archive): linkname, uname, and gname to follow the same decoding rules as name and prefix * rename(archive): UnTarStream to UntarStream * fix(archive): type that was missed getting updated * tests(archive): adjust check headers test to validate all header properties instead of just pathnames * rename(archive): `pathname` properties to `path` * docs(archive): updated to be more descriptive * docs(archive): Updated error types * adjust(archive): `validPath` to `assertValidPath` * adjust(archive): `validTarStreamOptions` to `assertValidTarStreamOptions` * revert(archive): UntarStream to produce TarStreamEntry instead of TarStreamChunk * refactor: remove redundant `void` return types * docs: cleanup assertion function docs * docs: correct `TarStream` example * docs: minor docs cleanups * refactor: improve error class specificity * docs: add `@experimental` JSDoc tags * docs(archive): Updated examples for `assertValidPath` and `assertValidTarStreamOptions``` * fix(archive): problem with tests - I suspect the problem is that a file that was read by `Deno.readDir` changed size between being read at `Deno.stat` and when `Deno.open` finished pulling it all in. * update error messages * update error messages * fix typos * refactor: tweak error messages * refactor: tweaks and add type field --------- Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com> Co-authored-by: ud2 <sjx233@qq.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
2024-09-02 07:43:22 +00:00
* import { dirname, normalize } from "@std/path";
*
* for await (
* const entry of (await Deno.open("./out.tar.gz"))
* .readable
* .pipeThrough(new DecompressionStream("gzip"))
* .pipeThrough(new UntarStream())
* ) {
* const path = normalize(entry.path);
* await Deno.mkdir(dirname(path));
* await entry.readable?.pipeTo((await Deno.create(path)).writable);
* }
* ```
*/
get writable(): WritableStream<Uint8Array> {
return this.#writable;
}
}