2525-behavior (gen_statem ).
2626
2727-export ([init /1 , callback_mode /0 , terminate /3 ]).
28- -export ([opening /3 , opened_gzip /3 , opened_passthrough /3 ]).
28+ -export ([opening /3 , opened_active /3 , opened_passthrough /3 ]).
2929
3030-include (" file_int.hrl" ).
3131
@@ -37,41 +37,71 @@ callback_mode() -> state_functions.
3737init ({Owner , Secret , [compressed ]}) ->
3838 % % 'reset mode', which resets the inflate state at the end of every stream,
3939 % % allowing us to read concatenated gzip files.
40- init (Owner , Secret , reset );
40+ init_zlib (Owner , Secret , reset );
4141init ({Owner , Secret , [compressed_one ]}) ->
4242 % % 'cut mode', which stops the inflate after one member
4343 % % allowing us to read gzipped tar files
44- init (Owner , Secret , cut ).
44+ init_zlib (Owner , Secret , cut );
45+ init ({Owner , Secret , [{zstd , Parameters }]}) ->
46+ % % 'cut mode', which stops the inflate after one member
47+ % % allowing us to read gzipped tar files
48+ init_zstd (Owner , Secret , Parameters ).
4549
46- init (Owner , Secret , Mode ) ->
50+ init_zlib (Owner , Secret , Mode ) ->
4751 Monitor = monitor (process , Owner ),
4852 % % We're using the undocumented inflateInit/3 to set the mode
4953 Z = zlib :open (),
5054 ok = zlib :inflateInit (Z , ? GZIP_WBITS , Mode ),
55+
5156 Data =
5257 #{ owner => Owner ,
5358 monitor => Monitor ,
5459 secret => Secret ,
60+ choose_state => fun (PrivateFd ) ->
61+ % % The old driver fell back to plain reads
62+ % % if the file didn't start with the magic
63+ % % gzip bytes.
64+ State =
65+ case ? CALL_FD (PrivateFd , read , [2 ]) of
66+ {ok , <<16#1F , 16#8B >>} ->
67+ opened_active ;
68+ _Other ->
69+ opened_passthrough
70+ end ,
71+ {ok , 0 } = ? CALL_FD (PrivateFd , position , [0 ]),
72+ State
73+ end ,
5574 position => 0 ,
5675 buffer => prim_buffer :new (),
57- zlib => Z },
76+ inflate => fun (Data ) -> zlib :inflate (Z , Data ) end ,
77+ reset => fun () -> zlib :inflateReset (Z ) end },
5878 {ok , opening , Data }.
5979
60- % % The old driver fell back to plain reads if the file didn't start with the
61- % % magic gzip bytes.
62- choose_decompression_state (PrivateFd ) ->
63- State =
64- case ? CALL_FD (PrivateFd , read , [2 ]) of
65- {ok , <<16#1F , 16#8B >>} -> opened_gzip ;
66- _Other -> opened_passthrough
67- end ,
68- {ok , 0 } = ? CALL_FD (PrivateFd , position , [0 ]),
69- State .
80+ init_zstd (Owner , Secret , Parameters ) ->
81+ Monitor = monitor (process , Owner ),
82+ try zstd :context (decompress , Parameters ) of
83+ {ok , Z } ->
84+ Data =
85+ #{ owner => Owner ,
86+ monitor => Monitor ,
87+ secret => Secret ,
88+ choose_state => fun (_ ) -> opened_active end ,
89+ position => 0 ,
90+ buffer => prim_buffer :new (),
91+ inflate => fun (Data ) -> zstd :decompress (Data , Z ) end ,
92+ reset => fun () -> zstd :reset (Z ) end },
93+ {ok , opening , Data }
94+ catch
95+ _ :_ ->
96+ {error , badarg }
97+ end .
7098
71- opening ({call , From }, {'$open' , Secret , Filename , Modes }, #{ secret := Secret } = Data ) ->
99+ opening ({call , From },
100+ {'$open' , Secret , Filename , Modes },
101+ #{ secret := Secret , choose_state := ChooseState } = Data ) ->
72102 case raw_file_io :open (Filename , Modes ) of
73103 {ok , PrivateFd } ->
74- NextState = choose_decompression_state (PrivateFd ),
104+ NextState = ChooseState (PrivateFd ),
75105 NewData = Data #{ handle => PrivateFd },
76106 {next_state , NextState , NewData , [{reply , From , ok }]};
77107 Other ->
@@ -109,16 +139,16 @@ opened_passthrough(_Event, _Request, _Data) ->
109139
110140% %
111141
112- opened_gzip (info , {'DOWN' , Monitor , process , _Owner , _Reason }, #{ monitor := Monitor }) ->
142+ opened_active (info , {'DOWN' , Monitor , process , _Owner , _Reason }, #{ monitor := Monitor }) ->
113143 {stop , shutdown };
114144
115- opened_gzip (info , _Message , _Data ) ->
145+ opened_active (info , _Message , _Data ) ->
116146 keep_state_and_data ;
117147
118- opened_gzip ({call , {Owner , _Tag } = From }, [close ], #{ owner := Owner } = Data ) ->
148+ opened_active ({call , {Owner , _Tag } = From }, [close ], #{ owner := Owner } = Data ) ->
119149 internal_close (From , Data );
120150
121- opened_gzip ({call , {Owner , _Tag } = From }, [position , Mark ], #{ owner := Owner } = Data ) ->
151+ opened_active ({call , {Owner , _Tag } = From }, [position , Mark ], #{ owner := Owner } = Data ) ->
122152 case position (Data , Mark ) of
123153 {ok , NewData , Result } ->
124154 Response = {ok , Result },
@@ -127,7 +157,7 @@ opened_gzip({call, {Owner, _Tag} = From}, [position, Mark], #{ owner := Owner }
127157 {keep_state_and_data , [{reply , From , Other }]}
128158 end ;
129159
130- opened_gzip ({call , {Owner , _Tag } = From }, [read , Size ], #{ owner := Owner } = Data ) ->
160+ opened_active ({call , {Owner , _Tag } = From }, [read , Size ], #{ owner := Owner } = Data ) ->
131161 case read (Data , Size ) of
132162 {ok , NewData , Result } ->
133163 Response = {ok , Result },
@@ -136,7 +166,7 @@ opened_gzip({call, {Owner, _Tag} = From}, [read, Size], #{ owner := Owner } = Da
136166 {keep_state_and_data , [{reply , From , Other }]}
137167 end ;
138168
139- opened_gzip ({call , {Owner , _Tag } = From }, [read_line ], #{ owner := Owner } = Data ) ->
169+ opened_active ({call , {Owner , _Tag } = From }, [read_line ], #{ owner := Owner } = Data ) ->
140170 case read_line (Data ) of
141171 {ok , NewData , Result } ->
142172 Response = {ok , Result },
@@ -145,20 +175,20 @@ opened_gzip({call, {Owner, _Tag} = From}, [read_line], #{ owner := Owner } = Dat
145175 {keep_state_and_data , [{reply , From , Other }]}
146176 end ;
147177
148- opened_gzip ({call , {Owner , _Tag } = From }, [write , _IOData ], #{ owner := Owner }) ->
178+ opened_active ({call , {Owner , _Tag } = From }, [write , _IOData ], #{ owner := Owner }) ->
149179 Response = {error , ebadf },
150180 {keep_state_and_data , [{reply , From , Response }]};
151181
152- opened_gzip ({call , {Owner , _Tag } = From }, _Request , #{ owner := Owner }) ->
182+ opened_active ({call , {Owner , _Tag } = From }, _Request , #{ owner := Owner }) ->
153183 Response = {error , enotsup },
154184 {keep_state_and_data , [{reply , From , Response }]};
155185
156- opened_gzip ({call , _From }, _Request , _Data ) ->
186+ opened_active ({call , _From }, _Request , _Data ) ->
157187 % % The client functions filter this out, so we'll crash if the user does
158188 % % anything stupid on purpose.
159189 {shutdown , protocol_violation };
160190
161- opened_gzip (_Event , _Request , _Data ) ->
191+ opened_active (_Event , _Request , _Data ) ->
162192 keep_state_and_data .
163193
164194% %
@@ -178,8 +208,8 @@ read_1(Data, Buffer, BufferSize, ReadSize) when BufferSize < ReadSize ->
178208 #{ handle := PrivateFd } = Data ,
179209 case ? CALL_FD (PrivateFd , read , [? INFLATE_CHUNK_SIZE ]) of
180210 {ok , Compressed } ->
181- #{ zlib := Z } = Data ,
182- Uncompressed = erlang :iolist_to_iovec (zlib : inflate ( Z , Compressed )),
211+ #{ inflate := Inflate } = Data ,
212+ Uncompressed = erlang :iolist_to_iovec (Inflate ( Compressed )),
183213 prim_buffer :write (Buffer , Uncompressed ),
184214 read_1 (Data , Buffer , prim_buffer :size (Buffer ), ReadSize );
185215 eof when BufferSize > 0 ->
@@ -198,10 +228,10 @@ read_line(#{ buffer := Buffer } = Data) ->
198228 end .
199229
200230read_line_1 (Data , Buffer , not_found ) ->
201- #{ handle := PrivateFd , zlib := Z } = Data ,
231+ #{ handle := PrivateFd , inflate := Inflate } = Data ,
202232 case ? CALL_FD (PrivateFd , read , [? INFLATE_CHUNK_SIZE ]) of
203233 {ok , Compressed } ->
204- Uncompressed = erlang :iolist_to_iovec (zlib : inflate ( Z , Compressed )),
234+ Uncompressed = erlang :iolist_to_iovec (Inflate ( Compressed )),
205235 prim_buffer :write (Buffer , Uncompressed ),
206236 read_line_1 (Data , Buffer , prim_buffer :find_byte_index (Buffer , $\n ));
207237 eof ->
@@ -257,10 +287,10 @@ position_1(#{ position := Current } = Data, Desired) when Current < Desired ->
257287 Other -> Other
258288 end ;
259289position_1 (#{ position := Current } = Data , Desired ) when Current > Desired ->
260- #{ handle := PrivateFd , buffer := Buffer , zlib := Z } = Data ,
290+ #{ handle := PrivateFd , buffer := Buffer , reset := Reset } = Data ,
261291 case ? CALL_FD (PrivateFd , position , [bof ]) of
262292 {ok , 0 } ->
263- ok = zlib : inflateReset ( Z ),
293+ ok = Reset ( ),
264294 prim_buffer :wipe (Buffer ),
265295 position_1 (Data #{ position => 0 }, Desired );
266296 Other ->
0 commit comments