@@ -3,8 +3,13 @@ pub const Options = struct {
3
3
strip_components : u32 = 0 ,
4
4
/// How to handle the "mode" property of files from within the tar file.
5
5
mode_mode : ModeMode = .executable_bit_only ,
6
+ /// Provide this to receive detailed error messages.
7
+ /// When this is provided, some errors which would otherwise be returned immediately
8
+ /// will instead be added to this structure. The API user must check the errors
9
+ /// in diagnostics to know whether the operation succeeded or failed.
10
+ diagnostics : ? * Diagnostics = null ,
6
11
7
- const ModeMode = enum {
12
+ pub const ModeMode = enum {
8
13
/// The mode from the tar file is completely ignored. Files are created
9
14
/// with the default mode when creating files.
10
15
ignore ,
@@ -13,6 +18,32 @@ pub const Options = struct {
13
18
/// Other bits of the mode are left as the default when creating files.
14
19
executable_bit_only ,
15
20
};
21
+
22
+ pub const Diagnostics = struct {
23
+ allocator : std.mem.Allocator ,
24
+ errors : std .ArrayListUnmanaged (Error ) = .{},
25
+
26
+ pub const Error = union (enum ) {
27
+ unable_to_create_sym_link : struct {
28
+ code : anyerror ,
29
+ file_name : []const u8 ,
30
+ link_name : []const u8 ,
31
+ },
32
+ };
33
+
34
+ pub fn deinit (d : * Diagnostics ) void {
35
+ for (d .errors .items ) | item | {
36
+ switch (item ) {
37
+ .unable_to_create_sym_link = > | info | {
38
+ d .allocator .free (info .file_name );
39
+ d .allocator .free (info .link_name );
40
+ },
41
+ }
42
+ }
43
+ d .errors .deinit (d .allocator );
44
+ d .* = undefined ;
45
+ }
46
+ };
16
47
};
17
48
18
49
pub const Header = struct {
@@ -65,6 +96,10 @@ pub const Header = struct {
65
96
return str (header , 0 , 0 + 100 );
66
97
}
67
98
99
+ pub fn linkName (header : Header ) []const u8 {
100
+ return str (header , 157 , 157 + 100 );
101
+ }
102
+
68
103
pub fn prefix (header : Header ) []const u8 {
69
104
return str (header , 345 , 345 + 155 );
70
105
}
@@ -148,7 +183,7 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi
148
183
const header : Header = .{ .bytes = chunk [0.. 512] };
149
184
const file_size = try header .fileSize ();
150
185
const rounded_file_size = std .mem .alignForward (u64 , file_size , 512 );
151
- const pad_len = @as ( usize , @ intCast (rounded_file_size - file_size ) );
186
+ const pad_len : usize = @intCast (rounded_file_size - file_size );
152
187
const unstripped_file_name = if (file_name_override_len > 0 )
153
188
file_name_buffer [0.. file_name_override_len ]
154
189
else
@@ -228,7 +263,22 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi
228
263
buffer .skip (reader , @intCast (rounded_file_size )) catch return error .TarHeadersTooBig ;
229
264
},
230
265
.hard_link = > return error .TarUnsupportedFileType ,
231
- .symbolic_link = > return error .TarUnsupportedFileType ,
266
+ .symbolic_link = > {
267
+ const file_name = try stripComponents (unstripped_file_name , options .strip_components );
268
+ const link_name = header .linkName ();
269
+
270
+ dir .symLink (link_name , file_name , .{}) catch | err | {
271
+ if (options .diagnostics ) | d | {
272
+ try d .errors .append (d .allocator , .{ .unable_to_create_sym_link = .{
273
+ .code = err ,
274
+ .file_name = try d .allocator .dupe (u8 , file_name ),
275
+ .link_name = try d .allocator .dupe (u8 , link_name ),
276
+ } });
277
+ } else {
278
+ return error .UnableToCreateSymLink ;
279
+ }
280
+ };
281
+ },
232
282
else = > return error .TarUnsupportedFileType ,
233
283
}
234
284
}
0 commit comments