@@ -99,50 +99,48 @@ export async function writeTarFixture(
9999 entries : readonly TarFixtureEntry [ ] ,
100100) : Promise < void > {
101101 const pack = tar . pack ( ) ;
102- const zeroModeNames = new Set < string > ( ) ;
103- for ( const entry of entries ) {
104- if ( entry . header . mode === 0 ) zeroModeNames . add ( entry . header . name ) ;
102+ const zeroModeEntries = new Set < number > ( ) ;
103+ entries . forEach ( ( entry , index ) => {
104+ if ( entry . header . mode === 0 ) zeroModeEntries . add ( index ) ;
105105 const header : tar . Headers & { pax ?: Record < string , string > } = entry . pax
106106 ? { ...entry . header , pax : entry . pax }
107107 : { ...entry . header } ;
108108 pack . entry ( header , Buffer . from ( entry . data ?? '' ) ) ;
109- }
109+ } ) ;
110110 pack . finalize ( ) ;
111111 const chunks : Buffer [ ] = [ ] ;
112112 for await ( const chunk of pack ) chunks . push ( Buffer . from ( chunk ) ) ;
113113 const archive = Buffer . concat ( chunks ) ;
114- restoreZeroTarModes ( archive , zeroModeNames ) ;
114+ restoreZeroTarModes ( archive , zeroModeEntries ) ;
115115 await fs . writeFile ( archivePath , archive ) ;
116116}
117117
118118const TAR_BLOCK = 512 ;
119+ const PAX_TYPEFLAGS = new Set ( [ 'x' , 'g' ] ) ;
119120
120121/**
121122 * tar-stream's pack replaces a zero mode with its default, so a declared zero is written back into
122- * the emitted ustar header, checksum included.
123+ * the emitted ustar header, checksum included. Entries are matched by emitted order; the PAX
124+ * extended header tar-stream emits before an entry is not counted.
123125 */
124- function restoreZeroTarModes ( archive : Buffer , names : ReadonlySet < string > ) : void {
125- if ( names . size === 0 ) return ;
126+ function restoreZeroTarModes ( archive : Buffer , zeroModeEntries : ReadonlySet < number > ) : void {
127+ if ( zeroModeEntries . size === 0 ) return ;
128+ let entryIndex = 0 ;
126129 for ( let offset = 0 ; offset + TAR_BLOCK <= archive . length ; ) {
127130 const block = archive . subarray ( offset , offset + TAR_BLOCK ) ;
128- const name = readTarField ( block , 0 , 100 ) ;
129- if ( ! name ) return ;
130- if ( names . has ( name . replace ( / \/ $ / , '' ) ) ) {
131- block . write ( '000000 ' , 100 , 'ascii' ) ;
132- block . write ( `${ tarChecksum ( block ) . toString ( 8 ) . padStart ( 6 , '0' ) } ` , 148 , 'ascii' ) ;
131+ if ( block . every ( ( byte ) => byte === 0 ) ) return ;
132+ if ( ! PAX_TYPEFLAGS . has ( String . fromCharCode ( block [ 156 ] ! ) ) ) {
133+ if ( zeroModeEntries . has ( entryIndex ) ) {
134+ block . write ( '000000 ' , 100 , 'ascii' ) ;
135+ block . write ( `${ tarChecksum ( block ) . toString ( 8 ) . padStart ( 6 , '0' ) } ` , 148 , 'ascii' ) ;
136+ }
137+ entryIndex += 1 ;
133138 }
134- const size = Number . parseInt ( readTarField ( block , 124 , 12 ) , 8 ) || 0 ;
139+ const size = Number . parseInt ( block . toString ( 'ascii' , 124 , 136 ) . split ( '\0' ) [ 0 ] ! , 8 ) || 0 ;
135140 offset += TAR_BLOCK + Math . ceil ( size / TAR_BLOCK ) * TAR_BLOCK ;
136141 }
137142}
138143
139- function readTarField ( block : Buffer , start : number , length : number ) : string {
140- return block
141- . toString ( 'ascii' , start , start + length )
142- . split ( '\0' ) [ 0 ] !
143- . trim ( ) ;
144- }
145-
146144function tarChecksum ( block : Buffer ) : number {
147145 let sum = 8 * 0x20 ;
148146 for ( let index = 0 ; index < TAR_BLOCK ; index += 1 ) {
0 commit comments