authorgravatar for igor.anic@gmail.comIgor Anić <igor.anic@gmail.com> 2023-11-27 17:17:28+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-13 19:37:33-07:00
log4381241237fc6ff18ee889571774d929700ce7a7
treef25588dc5a8269cf9b553e2da31684785e39f722
parentff8544daa59fa27b1e5c90e5ccdb6c513d719d47

tar: refactor Buffer

Move reader into Buffer and make it BufferedReader. This doesn't introduce any new functionality just grouping similar things.

1 files changed, 94 insertions(+), 80 deletions(-)

lib/std/tar.zig+94-80
...@@ -136,51 +136,90 @@ pub const Header = struct {...@@ -136,51 +136,90 @@ pub const Header = struct {
136 }136 }
137};137};
138138
139const Buffer = struct {139fn BufferedReader(comptime ReaderType: type) type {
140 buffer: [512 * 8]u8 = undefined,140 return struct {
141 start: usize = 0,141 unbuffered_reader: ReaderType,
142 end: usize = 0,142 buffer: [512 * 8]u8 = undefined,
143 start: usize = 0,
144 end: usize = 0,
143145
144 pub fn readChunk(b: *Buffer, reader: anytype, count: usize) ![]const u8 {146 const Self = @This();
145 b.ensureCapacity(1024);
146147
147 const ask = @min(b.buffer.len - b.end, count -| (b.end - b.start));148 pub fn readChunk(self: *Self, count: usize) ![]const u8 {
148 b.end += try reader.readAtLeast(b.buffer[b.end..], ask);149 self.ensureCapacity(1024);
149150
150 return b.buffer[b.start..b.end];151 const ask = @min(self.buffer.len - self.end, count -| (self.end - self.start));
151 }152 self.end += try self.unbuffered_reader.readAtLeast(self.buffer[self.end..], ask);
152153
153 pub fn advance(b: *Buffer, count: usize) void {154 return self.buffer[self.start..self.end];
154 b.start += count;155 }
155 assert(b.start <= b.end);
156 }
157156
158 pub fn skip(b: *Buffer, reader: anytype, count: usize) !void {157 pub fn advance(self: *Self, count: usize) void {
159 if (b.start + count > b.end) {158 self.start += count;
160 try reader.skipBytes(b.start + count - b.end, .{});159 assert(self.start <= self.end);
161 b.start = b.end;160 }
162 } else {161
163 b.advance(count);162 pub fn skip(self: *Self, count: usize) !void {
163 if (self.start + count > self.end) {
164 try self.unbuffered_reader.skipBytes(self.start + count - self.end, .{});
165 self.start = self.end;
166 } else {
167 self.advance(count);
168 }
164 }169 }
165 }
166170
167 inline fn ensureCapacity(b: *Buffer, count: usize) void {171 inline fn ensureCapacity(self: *Self, count: usize) void {
168 if (b.buffer.len - b.start < count) {172 if (self.buffer.len - self.start < count) {
169 const dest_end = b.end - b.start;173 const dest_end = self.end - self.start;
170 @memcpy(b.buffer[0..dest_end], b.buffer[b.start..b.end]);174 @memcpy(self.buffer[0..dest_end], self.buffer[self.start..self.end]);
171 b.end = dest_end;175 self.end = dest_end;
172 b.start = 0;176 self.start = 0;
177 }
173 }178 }
174 }179
175};180 pub fn write(self: *Self, writer: anytype, size: usize) !void {
181 const rounded_file_size = std.mem.alignForward(usize, size, 512);
182 const chunk_size = rounded_file_size + 512;
183 const pad_len: usize = rounded_file_size - size;
184
185 var file_off: usize = 0;
186 while (true) {
187 const temp = try self.readChunk(chunk_size - file_off);
188 if (temp.len == 0) return error.UnexpectedEndOfStream;
189 const slice = temp[0..@min(size - file_off, temp.len)];
190 try writer.writeAll(slice);
191
192 file_off += slice.len;
193 self.advance(slice.len);
194 if (file_off >= size) {
195 self.advance(pad_len);
196 return;
197 }
198 }
199 }
200
201 pub fn copy(self: *Self, dst_buffer: []u8, size: usize) !void {
202 const rounded_file_size = std.mem.alignForward(usize, size, 512);
203 const chunk_size = rounded_file_size + 512;
204
205 var i: usize = 0;
206 while (i < size) {
207 const slice = try self.readChunk(chunk_size - i);
208 if (slice.len == 0) return error.UnexpectedEndOfStream;
209 const copy_size: usize = @min(size - i, slice.len);
210 @memcpy(dst_buffer[i .. i + copy_size], slice[0..copy_size]);
211 self.advance(copy_size);
212 i += copy_size;
213 }
214 }
215 };
216}
176217
177fn Iterator(comptime ReaderType: type) type {218fn Iterator(comptime ReaderType: type) type {
178 return struct {219 return struct {
179 file_name_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined,220 file_name_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined,
180 file_name_len: usize = 0,221 file_name_len: usize = 0,
181 buffer: Buffer = .{},222 reader: BufferedReader(ReaderType),
182 reader: ReaderType,
183 pad_len: usize = 0,
184 diagnostics: ?*Options.Diagnostics,223 diagnostics: ?*Options.Diagnostics,
185224
186 const Self = @This();225 const Self = @This();
...@@ -193,50 +232,32 @@ fn Iterator(comptime ReaderType: type) type {...@@ -193,50 +232,32 @@ fn Iterator(comptime ReaderType: type) type {
193 iter: *Self,232 iter: *Self,
194233
195 pub fn write(self: File, writer: anytype) !void {234 pub fn write(self: File, writer: anytype) !void {
196 const rounded_file_size = std.mem.alignForward(u64, self.size, 512);235 try self.iter.reader.write(writer, self.size);
197 var file_off: usize = 0;
198 while (true) {
199 const temp = try self.iter.buffer.readChunk(self.iter.reader, @intCast(rounded_file_size + 512 - file_off));
200 if (temp.len == 0) return error.UnexpectedEndOfStream;
201 const slice = temp[0..@intCast(@min(self.size - file_off, temp.len))];
202 try writer.writeAll(slice);
203
204 file_off += slice.len;
205 self.iter.buffer.advance(slice.len);
206 if (file_off >= self.size) {
207 return;
208 // self.iter.buffer.advance(pad_len);
209 // continue :header;
210 }
211 }
212 }236 }
213237
214 pub fn skip(self: File) void {238 pub fn skip(self: File) !void {
215 _ = self;239 const rounded_file_size = std.mem.alignForward(usize, self.size, 512);
216 unreachable;240 try self.iter.reader.skip(rounded_file_size);
217 }241 }
218 };242 };
219243
220 pub fn next(self: *Self) !?File {244 pub fn next(self: *Self) !?File {
221 self.buffer.advance(self.pad_len);
222 self.pad_len = 0;
223 self.file_name_len = 0;245 self.file_name_len = 0;
224
225 while (true) {246 while (true) {
226 const chunk = try self.buffer.readChunk(self.reader, 1024);247 const chunk = try self.reader.readChunk(1024);
227 switch (chunk.len) {248 switch (chunk.len) {
228 0 => return null,249 0 => return null,
229 1...511 => return error.UnexpectedEndOfStream,250 1...511 => return error.UnexpectedEndOfStream,
230 else => {},251 else => {},
231 }252 }
232 self.buffer.advance(512);253 self.reader.advance(512);
233254
234 const header: Header = .{ .bytes = chunk[0..512] };255 const header: Header = .{ .bytes = chunk[0..512] };
235 const file_size = try header.fileSize();256 const file_size = try header.fileSize();
236 const file_type = header.fileType();257 const file_type = header.fileType();
237 const link_name = header.linkName();258 const link_name = header.linkName();
238 const rounded_file_size = std.mem.alignForward(u64, file_size, 512);259 const rounded_file_size: usize = std.mem.alignForward(usize, file_size, 512);
239 self.pad_len = @intCast(rounded_file_size - file_size);260
240 const file_name = if (self.file_name_len == 0)261 const file_name = if (self.file_name_len == 0)
241 try header.fullFileName(&self.file_name_buffer)262 try header.fullFileName(&self.file_name_buffer)
242 else263 else
...@@ -253,44 +274,33 @@ fn Iterator(comptime ReaderType: type) type {...@@ -253,44 +274,33 @@ fn Iterator(comptime ReaderType: type) type {
253 };274 };
254 },275 },
255 .global_extended_header => {276 .global_extended_header => {
256 self.buffer.skip(self.reader, @intCast(rounded_file_size)) catch return error.TarHeadersTooBig;277 self.reader.skip(rounded_file_size) catch return error.TarHeadersTooBig;
257 },278 },
258 .extended_header => {279 .extended_header => {
259 if (file_size == 0) {280 if (file_size == 0) continue;
260 self.buffer.advance(@intCast(rounded_file_size));
261 continue;
262 }
263281
264 const chunk_size: usize = @intCast(rounded_file_size + 512);282 const chunk_size: usize = rounded_file_size + 512;
265 var data_off: usize = 0;283 var data_off: usize = 0;
266 const file_name_override_len = while (data_off < file_size) {284 const file_name_override_len = while (data_off < file_size) {
267 const slice = try self.buffer.readChunk(self.reader, chunk_size - data_off);285 const slice = try self.reader.readChunk(chunk_size - data_off);
268 if (slice.len == 0) return error.UnexpectedEndOfStream;286 if (slice.len == 0) return error.UnexpectedEndOfStream;
269 const remaining_size: usize = @intCast(file_size - data_off);287 const remaining_size: usize = file_size - data_off;
270 const attr_info = try parsePaxAttribute(slice[0..@min(remaining_size, slice.len)], remaining_size);288 const attr_info = try parsePaxAttribute(slice[0..@min(remaining_size, slice.len)], remaining_size);
271289
272 if (std.mem.eql(u8, attr_info.key, "path")) {290 if (std.mem.eql(u8, attr_info.key, "path")) {
273 if (attr_info.value_len > self.file_name_buffer.len) return error.NameTooLong;291 if (attr_info.value_len > self.file_name_buffer.len) return error.NameTooLong;
274 self.buffer.advance(attr_info.value_off);292 self.reader.advance(attr_info.value_off);
275 data_off += attr_info.value_off;293 data_off += attr_info.value_off;
276 break attr_info.value_len;294 break attr_info.value_len;
277 }295 }
278296
279 try self.buffer.skip(self.reader, attr_info.size);297 try self.reader.skip(attr_info.size);
280 data_off += attr_info.size;298 data_off += attr_info.size;
281 } else 0;299 } else 0;
282300
283 var i: usize = 0;301 try self.reader.copy(&self.file_name_buffer, file_name_override_len);
284 while (i < file_name_override_len) {
285 const slice = try self.buffer.readChunk(self.reader, chunk_size - data_off - i);
286 if (slice.len == 0) return error.UnexpectedEndOfStream;
287 const copy_size: usize = @intCast(@min(file_name_override_len - i, slice.len));
288 @memcpy(self.file_name_buffer[i .. i + copy_size], slice[0..copy_size]);
289 self.buffer.advance(copy_size);
290 i += copy_size;
291 }
292302
293 try self.buffer.skip(self.reader, @intCast(rounded_file_size - data_off - file_name_override_len));303 try self.reader.skip(rounded_file_size - data_off - file_name_override_len);
294 self.file_name_len = file_name_override_len;304 self.file_name_len = file_name_override_len;
295 continue;305 continue;
296 },306 },
...@@ -309,7 +319,11 @@ fn Iterator(comptime ReaderType: type) type {...@@ -309,7 +319,11 @@ fn Iterator(comptime ReaderType: type) type {
309}319}
310320
311pub fn iterator(reader: anytype, diagnostics: ?*Options.Diagnostics) Iterator(@TypeOf(reader)) {321pub fn iterator(reader: anytype, diagnostics: ?*Options.Diagnostics) Iterator(@TypeOf(reader)) {
312 return .{ .reader = reader, .diagnostics = diagnostics };322 const ReaderType = @TypeOf(reader);
323 return .{
324 .reader = BufferedReader(ReaderType){ .unbuffered_reader = reader },
325 .diagnostics = diagnostics,
326 };
313}327}
314328
315pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !void {329pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !void {
...@@ -364,7 +378,7 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi...@@ -364,7 +378,7 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi
364 if (file) |f| {378 if (file) |f| {
365 try iter_file.write(f);379 try iter_file.write(f);
366 } else {380 } else {
367 iter_file.skip();381 try iter_file.skip();
368 }382 }
369 },383 },
370 .symbolic_link => {384 .symbolic_link => {