authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-04-20 13:46:54-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-01 16:35:27-07:00
loge9fd9798f4d6e3cc5af6179881e0323f983095b5
treeb5dd76d64fe2e7cca2e2f9e0eb1917a5bb1e3624
parent24441b184f989dc889c33b6422ec5ddd8f385c5e

std.tar.Writer: update reader/writer API usage


7 files changed, 179 insertions(+), 141 deletions(-)

lib/compiler/std-docs.zig+30-20
......@@ -202,34 +202,33 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {
202202 var walker = try std_dir.walk(gpa);
203203 defer walker.deinit();
204204
205 var archiver = std.tar.writer(response.writer());
206 archiver.prefix = "std";
205 var tar_buffer: [@sizeOf(std.tar.Writer.Header)]u8 = undefined;
206 var response_bw = response.writer().buffered(&tar_buffer);
207 var tar_writer: std.tar.Writer = .{ .underlying_writer = &response_bw };
208 tar_writer.prefix = "std";
207209
208210 while (try walker.next()) |entry| {
209211 switch (entry.kind) {
210212 .file => {
211 if (!std.mem.endsWith(u8, entry.basename, ".zig"))
212 continue;
213 if (std.mem.endsWith(u8, entry.basename, "test.zig"))
214 continue;
213 if (!std.mem.endsWith(u8, entry.basename, ".zig")) continue;
214 if (std.mem.endsWith(u8, entry.basename, "test.zig")) continue;
215215 },
216216 else => continue,
217217 }
218218 var file = try entry.dir.openFile(entry.basename, .{});
219219 defer file.close();
220 try archiver.writeFile(entry.path, file);
220 const stat = try file.stat();
221 try tar_writer.writeFile(entry.path, file, stat);
221222 }
222223
223224 {
224225 // Since this command is JIT compiled, the builtin module available in
225226 // this source file corresponds to the user's host system.
226227 const builtin_zig = @embedFile("builtin");
227 archiver.prefix = "builtin";
228 try archiver.writeFileBytes("builtin.zig", builtin_zig, .{});
228 tar_writer.prefix = "builtin";
229 try tar_writer.writeFileBytes("builtin.zig", builtin_zig, .{});
229230 }
230231
231 // intentionally omitting the pointless trailer
232 //try archiver.finish();
233232 try response.end();
234233}
235234
......@@ -255,16 +254,27 @@ fn serveWasm(
255254 }) catch unreachable) catch unreachable),
256255 .output_mode = .Exe,
257256 });
258 // std.http.Server does not have a sendfile API yet.
259257 const bin_path = try wasm_base_path.join(arena, bin_name);
260 const file_contents = try bin_path.root_dir.handle.readFileAlloc(gpa, bin_path.sub_path, 10 * 1024 * 1024);
261 defer gpa.free(file_contents);
262 try request.respond(file_contents, .{
263 .extra_headers = &.{
264 .{ .name = "content-type", .value = "application/wasm" },
265 cache_control_header,
258 const file = try bin_path.root_dir.handle.openFile(bin_path.sub_path, .{});
259 defer file.close();
260 const content_length = std.math.cast(usize, (try file.stat()).size) orelse return error.FileTooBig;
261
262 var response = try request.respondStreaming(.{
263 .content_length = content_length,
264 .respond_options = .{
265 .extra_headers = &.{
266 .{ .name = "content-type", .value = "application/wasm" },
267 cache_control_header,
268 },
266269 },
267270 });
271
272 var bw = response.writer().unbuffered();
273 try bw.writeFileAll(file, .{
274 .offset = .zero,
275 .limit = .limited(content_length),
276 });
277 try response.end();
268278}
269279
270280const autodoc_root_name = "autodoc";
......@@ -396,8 +406,8 @@ fn receiveWasmMessage(
396406 },
397407 .error_bundle => {
398408 const eb_hdr = try br.takeStructEndian(std.zig.Server.Message.ErrorBundle, .little);
399 const extra_array = try br.readArrayEndianAlloc(arena, u32, eb_hdr.extra_len, .little);
400 const string_bytes = try br.readAlloc(arena, eb_hdr.string_bytes_len);
409 const extra_array = try br.readSliceEndianAlloc(arena, u32, eb_hdr.extra_len, .little);
410 const string_bytes = try br.readSliceAlloc(arena, eb_hdr.string_bytes_len);
401411 result_error_bundle.* = .{
402412 .string_bytes = string_bytes,
403413 .extra = extra_array,
lib/std/compress/flate/inflate.zig+1-1
......@@ -704,7 +704,7 @@ pub fn BitReader(comptime T: type) type {
704704 n += 1;
705705 }
706706 // Then use forward reader for all other bytes.
707 try self.forward_reader.read(buf[n..]);
707 try self.forward_reader.readSlice(buf[n..]);
708708 }
709709
710710 /// Alias for readF(U, 0).
lib/std/io/BufferedReader.zig+18-7
......@@ -51,6 +51,19 @@ pub fn readVec(br: *BufferedReader, data: []const []u8) Reader.Error!usize {
5151 return passthruReadVec(br, data);
5252}
5353
54pub fn read(br: *BufferedReader, bw: *BufferedWriter, limit: Reader.Limit) Reader.RwError!usize {
55 return passthruRead(br, bw, limit);
56}
57
58/// "Pump" data from the reader to the writer.
59pub fn readAll(br: *BufferedReader, bw: *BufferedWriter, limit: Reader.Limit) Reader.RwError!void {
60 var remaining = limit;
61 while (true) {
62 const n = try passthruRead(br, bw, remaining);
63 remaining = remaining.subtract(n).?;
64 }
65}
66
5467fn passthruRead(ctx: ?*anyopaque, bw: *BufferedWriter, limit: Reader.Limit) Reader.RwError!usize {
5568 const br: *BufferedReader = @alignCast(@ptrCast(ctx));
5669 const buffer = br.buffer[0..br.end];
......@@ -134,7 +147,6 @@ pub fn seekForwardBy(br: *BufferedReader, seek_by: u64) !void {
134147///
135148/// See also:
136149/// * `peek`
137/// * `tryPeekArray`
138150/// * `toss`
139151pub fn peek(br: *BufferedReader, n: usize) Reader.Error![]u8 {
140152 assert(n <= br.buffer.len);
......@@ -155,7 +167,6 @@ pub fn peek(br: *BufferedReader, n: usize) Reader.Error![]u8 {
155167///
156168/// See also:
157169/// * `peek`
158/// * `tryPeekGreedy`
159170/// * `toss`
160171pub fn peekGreedy(br: *BufferedReader, n: usize) Reader.Error![]u8 {
161172 assert(n <= br.buffer.len);
......@@ -280,7 +291,7 @@ pub fn discardRemaining(br: *BufferedReader) Reader.ShortError!usize {
280291///
281292/// See also:
282293/// * `peek`
283pub fn read(br: *BufferedReader, buffer: []u8) Reader.Error!void {
294pub fn readSlice(br: *BufferedReader, buffer: []u8) Reader.Error!void {
284295 const in_buffer = br.buffer[br.seek..br.end];
285296 const copy_len = @min(buffer.len, in_buffer.len);
286297 @memcpy(buffer[0..copy_len], in_buffer[0..copy_len]);
......@@ -313,7 +324,7 @@ pub fn readShort(br: *BufferedReader, buffer: []u8) Reader.ShortError!usize {
313324
314325/// The function is inline to avoid the dead code in case `endian` is
315326/// comptime-known and matches host endianness.
316pub inline fn readArrayEndianAlloc(
327pub inline fn readSliceEndianAlloc(
317328 br: *BufferedReader,
318329 allocator: Allocator,
319330 Elem: type,
......@@ -322,17 +333,17 @@ pub inline fn readArrayEndianAlloc(
322333) ReadAllocError![]Elem {
323334 const dest = try allocator.alloc(Elem, len);
324335 errdefer allocator.free(dest);
325 try read(br, @ptrCast(dest));
336 try readSlice(br, @ptrCast(dest));
326337 if (native_endian != endian) std.mem.byteSwapAllFields(Elem, dest);
327338 return dest;
328339}
329340
330341pub const ReadAllocError = Reader.Error || Allocator.Error;
331342
332pub fn readAlloc(br: *BufferedReader, allocator: Allocator, len: usize) ReadAllocError![]u8 {
343pub fn readSliceAlloc(br: *BufferedReader, allocator: Allocator, len: usize) ReadAllocError![]u8 {
333344 const dest = try allocator.alloc(u8, len);
334345 errdefer allocator.free(dest);
335 try read(br, dest);
346 try readSlice(br, dest);
336347 return dest;
337348}
338349
lib/std/io/BufferedWriter.zig+6-6
......@@ -453,24 +453,24 @@ pub inline fn writeStructEndian(bw: *BufferedWriter, value: anytype, endian: std
453453 }
454454}
455455
456pub inline fn writeArrayEndian(
456pub inline fn writeSliceEndian(
457457 bw: *BufferedWriter,
458458 Elem: type,
459 array: []const Elem,
459 slice: []const Elem,
460460 endian: std.builtin.Endian,
461461) Writer.Error!void {
462462 if (native_endian == endian) {
463 return writeAll(bw, @ptrCast(array));
463 return writeAll(bw, @ptrCast(slice));
464464 } else {
465 return bw.writeArraySwap(bw, Elem, array);
465 return bw.writeArraySwap(bw, Elem, slice);
466466 }
467467}
468468
469469/// Asserts that the buffer storage capacity is at least enough to store `@sizeOf(Elem)`
470pub fn writeArraySwap(bw: *BufferedWriter, Elem: type, array: []const Elem) Writer.Error!void {
470pub fn writeSliceSwap(bw: *BufferedWriter, Elem: type, slice: []const Elem) Writer.Error!void {
471471 // copy to storage first, then swap in place
472472 _ = bw;
473 _ = array;
473 _ = slice;
474474 @panic("TODO");
475475}
476476
lib/std/io/Reader.zig+11-3
......@@ -45,18 +45,26 @@ pub const VTable = struct {
4545 discard: *const fn (context: ?*anyopaque, limit: Limit) Error!usize,
4646};
4747
48pub const RwError = RwAllError || error{
48pub const RwError = error{
49 /// See the `Reader` implementation for detailed diagnostics.
50 ReadFailed,
51 /// See the `Writer` implementation for detailed diagnostics.
52 WriteFailed,
4953 /// End of stream indicated from the `Reader`. This error cannot originate
5054 /// from the `Writer`.
5155 EndOfStream,
5256};
5357
54pub const Error = ShortError || error{
58pub const Error = error{
59 /// See the `Reader` implementation for detailed diagnostics.
60 ReadFailed,
5561 EndOfStream,
5662};
5763
5864/// For functions that handle end of stream as a success case.
59pub const RwAllError = ShortError || error{
65pub const RwAllError = error{
66 /// See the `Reader` implementation for detailed diagnostics.
67 ReadFailed,
6068 /// See the `Writer` implementation for detailed diagnostics.
6169 WriteFailed,
6270};
lib/std/tar/Writer.zig+110-101
......@@ -4,7 +4,6 @@ const testing = std.testing;
44const Writer = @This();
55
66const block_size = @sizeOf(Header);
7const empty_block: [block_size]u8 = [_]u8{0} ** block_size;
87
98/// Options for writing file/dir/link. If left empty 0o664 is used for
109/// file mode and current time for mtime.
......@@ -14,80 +13,91 @@ pub const Options = struct {
1413 /// File system modification time.
1514 mtime: u64 = 0,
1615};
17const Self = @This();
1816
1917underlying_writer: *std.io.BufferedWriter,
2018prefix: []const u8 = "",
2119mtime_now: u64 = 0,
2220
21const Error = error{
22 WriteFailed,
23 OctalOverflow,
24 NameTooLong,
25};
26
2327/// Sets prefix for all other write* method paths.
24pub fn setRoot(self: *Self, root: []const u8) !void {
28pub fn setRoot(w: *Writer, root: []const u8) Error!void {
2529 if (root.len > 0)
26 try self.writeDir(root, .{});
30 try w.writeDir(root, .{});
2731
28 self.prefix = root;
32 w.prefix = root;
2933}
3034
31/// Writes directory.
32pub fn writeDir(self: *Self, sub_path: []const u8, opt: Options) !void {
33 try self.writeHeader(.directory, sub_path, "", 0, opt);
35pub fn writeDir(w: *Writer, sub_path: []const u8, options: Options) Error!void {
36 try w.writeHeader(.directory, sub_path, "", 0, options);
3437}
3538
36/// Writes file system file.
37pub fn writeFile(self: *Self, sub_path: []const u8, file: std.fs.File) !void {
38 const stat = try file.stat();
39pub const WriteFileError = std.io.Writer.FileError || Error;
40
41pub fn writeFile(
42 w: *Writer,
43 sub_path: []const u8,
44 file: std.fs.File,
45 stat: std.fs.File.Stat,
46) WriteFileError!void {
3947 const mtime: u64 = @intCast(@divFloor(stat.mtime, std.time.ns_per_s));
4048
41 var header = Header{};
42 try self.setPath(&header, sub_path);
49 var header: Header = .{};
50 try w.setPath(&header, sub_path);
4351 try header.setSize(stat.size);
4452 try header.setMtime(mtime);
45 try header.write(self.underlying_writer);
53 try header.write(w.underlying_writer);
4654
47 try self.underlying_writer.writeFileAll(file, .{ .limit = .limited(stat.size) });
48 try self.writePadding(stat.size);
55 try w.underlying_writer.writeFileAll(file, .{ .limit = .limited(stat.size) });
56 try w.writePadding(stat.size);
4957}
5058
51/// Writes file reading file content from `reader`. Number of bytes in
52/// reader must be equal to `size`.
53pub fn writeFileStream(self: *Self, sub_path: []const u8, size: usize, reader: anytype, opt: Options) !void {
54 try self.writeHeader(.regular, sub_path, "", @intCast(size), opt);
55
56 var counting_reader = std.io.countingReader(reader);
57 var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();
58 try fifo.pump(counting_reader.reader(), self.underlying_writer);
59 if (counting_reader.bytes_read != size) return error.WrongReaderSize;
60 try self.writePadding(size);
59/// Writes file reading file content from `reader`. Reads exactly `size` bytes
60/// from `reader`, or returns `error.EndOfStream`.
61pub fn writeFileStream(
62 w: *Writer,
63 sub_path: []const u8,
64 size: usize,
65 reader: *std.io.BufferedReader,
66 options: Options,
67) std.io.Reader.RwError!void {
68 try w.writeHeader(.regular, sub_path, "", @intCast(size), options);
69 try reader.readAll(w.underlying_writer, .limited(size));
70 try w.writePadding(size);
6171}
6272
6373/// Writes file using bytes buffer `content` for size and file content.
64pub fn writeFileBytes(self: *Self, sub_path: []const u8, content: []const u8, opt: Options) !void {
65 try self.writeHeader(.regular, sub_path, "", @intCast(content.len), opt);
66 try self.underlying_writer.writeAll(content);
67 try self.writePadding(content.len);
74pub fn writeFileBytes(w: *Writer, sub_path: []const u8, content: []const u8, options: Options) Error!void {
75 try w.writeHeader(.regular, sub_path, "", @intCast(content.len), options);
76 try w.underlying_writer.writeAll(content);
77 try w.writePadding(content.len);
6878}
6979
70/// Writes symlink.
71pub fn writeLink(self: *Self, sub_path: []const u8, link_name: []const u8, opt: Options) !void {
72 try self.writeHeader(.symbolic_link, sub_path, link_name, 0, opt);
80pub fn writeLink(w: *Writer, sub_path: []const u8, link_name: []const u8, options: Options) Error!void {
81 try w.writeHeader(.symbolic_link, sub_path, link_name, 0, options);
7382}
7483
7584/// Writes fs.Dir.WalkerEntry. Uses `mtime` from file system entry and
7685/// default for entry mode .
77pub fn writeEntry(self: *Self, entry: std.fs.Dir.Walker.Entry) !void {
86pub fn writeEntry(w: *Writer, entry: std.fs.Dir.Walker.Entry) Error!void {
7887 switch (entry.kind) {
7988 .directory => {
80 try self.writeDir(entry.path, .{ .mtime = try entryMtime(entry) });
89 try w.writeDir(entry.path, .{ .mtime = try entryMtime(entry) });
8190 },
8291 .file => {
8392 var file = try entry.dir.openFile(entry.basename, .{});
8493 defer file.close();
85 try self.writeFile(entry.path, file);
94 const stat = try file.stat();
95 try w.writeFile(entry.path, file, stat);
8696 },
8797 .sym_link => {
8898 var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
8999 const link_name = try entry.dir.readLink(entry.basename, &link_name_buffer);
90 try self.writeLink(entry.path, link_name, .{ .mtime = try entryMtime(entry) });
100 try w.writeLink(entry.path, link_name, .{ .mtime = try entryMtime(entry) });
91101 },
92102 else => {
93103 return error.UnsupportedWalkerEntryKind;
......@@ -96,31 +106,31 @@ pub fn writeEntry(self: *Self, entry: std.fs.Dir.Walker.Entry) !void {
96106}
97107
98108fn writeHeader(
99 self: *Self,
109 w: *Writer,
100110 typeflag: Header.FileType,
101111 sub_path: []const u8,
102112 link_name: []const u8,
103113 size: u64,
104 opt: Options,
105) !void {
114 options: Options,
115) Error!void {
106116 var header = Header.init(typeflag);
107 try self.setPath(&header, sub_path);
117 try w.setPath(&header, sub_path);
108118 try header.setSize(size);
109 try header.setMtime(if (opt.mtime != 0) opt.mtime else self.mtimeNow());
110 if (opt.mode != 0)
111 try header.setMode(opt.mode);
119 try header.setMtime(if (options.mtime != 0) options.mtime else w.mtimeNow());
120 if (options.mode != 0)
121 try header.setMode(options.mode);
112122 if (typeflag == .symbolic_link)
113123 header.setLinkname(link_name) catch |err| switch (err) {
114 error.NameTooLong => try self.writeExtendedHeader(.gnu_long_link, &.{link_name}),
124 error.NameTooLong => try w.writeExtendedHeader(.gnu_long_link, &.{link_name}),
115125 else => return err,
116126 };
117 try header.write(self.underlying_writer);
127 try header.write(w.underlying_writer);
118128}
119129
120fn mtimeNow(self: *Self) u64 {
121 if (self.mtime_now == 0)
122 self.mtime_now = @intCast(std.time.timestamp());
123 return self.mtime_now;
130fn mtimeNow(w: *Writer) u64 {
131 if (w.mtime_now == 0)
132 w.mtime_now = @intCast(std.time.timestamp());
133 return w.mtime_now;
124134}
125135
126136fn entryMtime(entry: std.fs.Dir.Walker.Entry) !u64 {
......@@ -130,52 +140,51 @@ fn entryMtime(entry: std.fs.Dir.Walker.Entry) !u64 {
130140
131141/// Writes path in posix header, if don't fit (in name+prefix; 100+155
132142/// bytes) writes it in gnu extended header.
133fn setPath(self: *Self, header: *Header, sub_path: []const u8) !void {
134 header.setPath(self.prefix, sub_path) catch |err| switch (err) {
143fn setPath(w: *Writer, header: *Header, sub_path: []const u8) Error!void {
144 header.setPath(w.prefix, sub_path) catch |err| switch (err) {
135145 error.NameTooLong => {
136146 // write extended header
137 const buffers: []const []const u8 = if (self.prefix.len == 0)
147 const buffers: []const []const u8 = if (w.prefix.len == 0)
138148 &.{sub_path}
139149 else
140 &.{ self.prefix, "/", sub_path };
141 try self.writeExtendedHeader(.gnu_long_name, buffers);
150 &.{ w.prefix, "/", sub_path };
151 try w.writeExtendedHeader(.gnu_long_name, buffers);
142152 },
143153 else => return err,
144154 };
145155}
146156
147157/// Writes gnu extended header: gnu_long_name or gnu_long_link.
148fn writeExtendedHeader(self: *Self, typeflag: Header.FileType, buffers: []const []const u8) !void {
158fn writeExtendedHeader(w: *Writer, typeflag: Header.FileType, buffers: []const []const u8) Error!void {
149159 var len: usize = 0;
150 for (buffers) |buf|
151 len += buf.len;
160 for (buffers) |buf| len += buf.len;
152161
153 var header = Header.init(typeflag);
162 var header: Header = .init(typeflag);
154163 try header.setSize(len);
155 try header.write(self.underlying_writer);
164 try header.write(w.underlying_writer);
156165 for (buffers) |buf|
157 try self.underlying_writer.writeAll(buf);
158 try self.writePadding(len);
166 try w.underlying_writer.writeAll(buf);
167 try w.writePadding(len);
159168}
160169
161fn writePadding(self: *Self, bytes: u64) !void {
162 const pos: usize = @intCast(bytes % block_size);
170fn writePadding(w: *Writer, bytes: usize) std.io.Writer.Error!void {
171 const pos = bytes % block_size;
163172 if (pos == 0) return;
164 try self.underlying_writer.writeAll(empty_block[pos..]);
173 try w.underlying_writer.splatByteAll(0, block_size - pos);
165174}
166175
167/// Tar should finish with two zero blocks, but 'reasonable system must
168/// not assume that such a block exists when reading an archive' (from
169/// reference). In practice it is safe to skip this finish.
170pub fn finish(self: *Self) !void {
171 try self.underlying_writer.writeAll(&empty_block);
172 try self.underlying_writer.writeAll(&empty_block);
176/// According to the specification, tar should finish with two zero blocks, but
177/// "reasonable system must not assume that such a block exists when reading an
178/// archive". Therefore, the Zig standard library recommends to not call this
179/// function.
180pub fn finishPedantically(w: *Writer) std.io.Writer.Error!void {
181 try w.underlying_writer.writeSplatAll(&.{&.{0}}, block_size * 2);
173182}
174183
175184/// A struct that is exactly 512 bytes and matches tar file format. This is
176185/// intended to be used for outputting tar files; for parsing there is
177186/// `std.tar.Header`.
178const Header = extern struct {
187pub const Header = extern struct {
179188 // This struct was originally copied from
180189 // https://github.com/mattnite/tar/blob/main/src/main.zig which is MIT
181190 // licensed.
......@@ -230,11 +239,11 @@ const Header = extern struct {
230239 };
231240 }
232241
233 pub fn setSize(self: *Header, size: u64) !void {
234 try octal(&self.size, size);
242 pub fn setSize(w: *Header, size: u64) error{OctalOverflow}!void {
243 try octal(&w.size, size);
235244 }
236245
237 fn octal(buf: []u8, value: u64) !void {
246 fn octal(buf: []u8, value: u64) error{OctalOverflow}!void {
238247 var remainder: u64 = value;
239248 var pos: usize = buf.len;
240249 while (remainder > 0 and pos > 0) {
......@@ -246,36 +255,36 @@ const Header = extern struct {
246255 }
247256 }
248257
249 pub fn setMode(self: *Header, mode: u32) !void {
250 try octal(&self.mode, mode);
258 pub fn setMode(w: *Header, mode: u32) error{OctalOverflow}!void {
259 try octal(&w.mode, mode);
251260 }
252261
253262 // Integer number of seconds since January 1, 1970, 00:00 Coordinated Universal Time.
254263 // mtime == 0 will use current time
255 pub fn setMtime(self: *Header, mtime: u64) !void {
256 try octal(&self.mtime, mtime);
264 pub fn setMtime(w: *Header, mtime: u64) error{OctalOverflow}!void {
265 try octal(&w.mtime, mtime);
257266 }
258267
259 pub fn updateChecksum(self: *Header) !void {
260 var checksum: usize = ' '; // other 7 self.checksum bytes are initialized to ' '
261 for (std.mem.asBytes(self)) |val|
268 pub fn updateChecksum(w: *Header) !void {
269 var checksum: usize = ' '; // other 7 w.checksum bytes are initialized to ' '
270 for (std.mem.asBytes(w)) |val|
262271 checksum += val;
263 try octal(&self.checksum, checksum);
272 try octal(&w.checksum, checksum);
264273 }
265274
266 pub fn write(self: *Header, output_writer: anytype) !void {
267 try self.updateChecksum();
268 try output_writer.writeAll(std.mem.asBytes(self));
275 pub fn write(h: *Header, bw: *std.io.BufferedWriter) error{ OctalOverflow, WriteFailed }!void {
276 try h.updateChecksum();
277 try bw.writeAll(std.mem.asBytes(h));
269278 }
270279
271 pub fn setLinkname(self: *Header, link: []const u8) !void {
272 if (link.len > self.linkname.len) return error.NameTooLong;
273 @memcpy(self.linkname[0..link.len], link);
280 pub fn setLinkname(w: *Header, link: []const u8) !void {
281 if (link.len > w.linkname.len) return error.NameTooLong;
282 @memcpy(w.linkname[0..link.len], link);
274283 }
275284
276 pub fn setPath(self: *Header, prefix: []const u8, sub_path: []const u8) !void {
277 const max_prefix = self.prefix.len;
278 const max_name = self.name.len;
285 pub fn setPath(w: *Header, prefix: []const u8, sub_path: []const u8) !void {
286 const max_prefix = w.prefix.len;
287 const max_name = w.name.len;
279288 const sep = std.fs.path.sep_posix;
280289
281290 if (prefix.len + sub_path.len > max_name + max_prefix or prefix.len > max_prefix)
......@@ -283,32 +292,32 @@ const Header = extern struct {
283292
284293 // both fit into name
285294 if (prefix.len > 0 and prefix.len + sub_path.len < max_name) {
286 @memcpy(self.name[0..prefix.len], prefix);
287 self.name[prefix.len] = sep;
288 @memcpy(self.name[prefix.len + 1 ..][0..sub_path.len], sub_path);
295 @memcpy(w.name[0..prefix.len], prefix);
296 w.name[prefix.len] = sep;
297 @memcpy(w.name[prefix.len + 1 ..][0..sub_path.len], sub_path);
289298 return;
290299 }
291300
292301 // sub_path fits into name
293302 // there is no prefix or prefix fits into prefix
294303 if (sub_path.len <= max_name) {
295 @memcpy(self.name[0..sub_path.len], sub_path);
296 @memcpy(self.prefix[0..prefix.len], prefix);
304 @memcpy(w.name[0..sub_path.len], sub_path);
305 @memcpy(w.prefix[0..prefix.len], prefix);
297306 return;
298307 }
299308
300309 if (prefix.len > 0) {
301 @memcpy(self.prefix[0..prefix.len], prefix);
302 self.prefix[prefix.len] = sep;
310 @memcpy(w.prefix[0..prefix.len], prefix);
311 w.prefix[prefix.len] = sep;
303312 }
304313 const prefix_pos = if (prefix.len > 0) prefix.len + 1 else 0;
305314
306315 // add as much to prefix as you can, must split at /
307316 const prefix_remaining = max_prefix - prefix_pos;
308317 if (std.mem.lastIndexOf(u8, sub_path[0..@min(prefix_remaining, sub_path.len)], &.{'/'})) |sep_pos| {
309 @memcpy(self.prefix[prefix_pos..][0..sep_pos], sub_path[0..sep_pos]);
318 @memcpy(w.prefix[prefix_pos..][0..sep_pos], sub_path[0..sep_pos]);
310319 if ((sub_path.len - sep_pos - 1) > max_name) return error.NameTooLong;
311 @memcpy(self.name[0..][0 .. sub_path.len - sep_pos - 1], sub_path[sep_pos + 1 ..]);
320 @memcpy(w.name[0..][0 .. sub_path.len - sep_pos - 1], sub_path[sep_pos + 1 ..]);
312321 return;
313322 }
314323
lib/std/zig/Server.zig+3-3
......@@ -173,7 +173,7 @@ pub fn serveErrorBundle(s: *Server, error_bundle: std.zig.ErrorBundle) !void {
173173 .bytes_len = @intCast(bytes_len),
174174 });
175175 try s.out.writeStructEndian(eb_hdr, .little);
176 try s.out.writeArrayEndian(u32, error_bundle.extra, .little);
176 try s.out.writeSliceEndian(u32, error_bundle.extra, .little);
177177 try s.out.writeAll(error_bundle.string_bytes);
178178 try s.out.flush();
179179}
......@@ -198,8 +198,8 @@ pub fn serveTestMetadata(s: *Server, test_metadata: TestMetadata) !void {
198198 .bytes_len = @intCast(bytes_len),
199199 });
200200 try s.out.writeStructEndian(header, .little);
201 try s.out.writeArrayEndian(u32, test_metadata.names, .little);
202 try s.out.writeArrayEndian(u32, test_metadata.expected_panic_msgs, .little);
201 try s.out.writeSliceEndian(u32, test_metadata.names, .little);
202 try s.out.writeSliceEndian(u32, test_metadata.expected_panic_msgs, .little);
203203 try s.out.writeAll(test_metadata.string_bytes);
204204 try s.out.flush();
205205}