3333const builtin = @import ("builtin" );
3434const std = @import ("std" );
3535
36+ const Allocator = std .mem .Allocator ;
37+ const assert = std .debug .assert ;
3638const fs = std .fs ;
3739const log = std .log ;
3840const mem = std .mem ;
@@ -44,22 +46,24 @@ const xz = @cImport(@cInclude("xz.h"));
4446const MAGIC = "FOILZ" ;
4547const MAX_READ_SIZE = 1000000000 ;
4648
47- pub fn pack_directory (path : []const u8 , archive_path : []const u8 ) anyerror ! void {
48- var arena = std .heap .ArenaAllocator .init (std .heap .page_allocator );
49- defer arena .deinit ();
50- const allocator = arena .allocator ();
51-
49+ pub fn pack_directory (arena : Allocator , path : []const u8 , archive_path : []const u8 ) anyerror ! void {
5250 // Open a file for the archive
53- _ = try fs .cwd ().createFile (archive_path , .{ .truncate = true });
54- const arch_file = try fs .cwd ().openFile (archive_path , .{ .mode = .read_write });
55- const foilz_writer = fs .File .writer (arch_file );
51+ const arch_file = try fs .cwd ().createFile (archive_path , .{ .truncate = true });
52+ defer arch_file .close ();
53+
54+ var foilz_write_buf : [1024 ]u8 = undefined ;
55+ var foilz_writer = arch_file .writer (& foilz_write_buf );
56+ const writer = & foilz_writer .interface ;
5657
5758 var dir = try fs .openDirAbsolute (path , .{ .access_sub_paths = true , .iterate = true });
58- var walker = try dir .walk (allocator );
59+ defer dir .close ();
60+
61+ var walker = try dir .walk (arena );
62+ defer walker .deinit ();
5963
6064 var count : u32 = 0 ;
6165
62- try write_magic_number ( & foilz_writer );
66+ try writer . writeAll ( MAGIC );
6367
6468 while (try walker .next ()) | entry | {
6569 if (entry .kind == .file ) {
@@ -73,67 +77,44 @@ pub fn pack_directory(path: []const u8, archive_path: []const u8) anyerror!void
7377 const index = dest_buff [0.. replacement_size ];
7478 _ = mem .replace (u8 , entry .path , needle , replacement , index );
7579
76- // Read the entire contents of the file into a buffer
7780 const file = try entry .dir .openFile (entry .basename , .{});
7881 defer file .close ();
7982
80- // Allocate memory for the file
81- var file_arena = std .heap .ArenaAllocator .init (std .heap .page_allocator );
82- defer file_arena .deinit ();
83- const file_allocator = file_arena .allocator ();
83+ var read_buf : [1024 ]u8 = undefined ;
84+ var file_reader = file .reader (& read_buf );
85+ const reader = & file_reader .interface ;
8486
85- // Read the file
86- const file_buffer = try file .readToEndAlloc (file_allocator , MAX_READ_SIZE );
8787 const stat = try file .stat ();
8888
8989 // Write file record to archive
90- try write_file_record (& foilz_writer , index , file_buffer , stat .mode );
90+ const name = index ;
91+ try writer .writeInt (u64 , name .len , .little );
92+ try writer .writeAll (name );
93+ try writer .writeInt (u64 , stat .size , .little );
94+ if (stat .size > 0 ) {
95+ assert (stat .size == try reader .streamRemaining (writer ));
96+ }
97+ try writer .writeInt (usize , stat .mode , .little );
9198
92- count = count + 1 ;
99+ count += 1 ;
93100
94101 direct_log ("\r info: 🔍 Files Packed: {}" , .{count });
95102 }
96103 }
97104 direct_log ("\n " , .{});
98105
99106 // Log success
100- log .info ("Archived {} files into payload! 📥" , .{count });
101-
102- // Clean up memory
103- walker .deinit ();
104-
105- // Close the archive file
106- try write_magic_number (& foilz_writer );
107-
108- arch_file .close ();
109- }
110-
111- pub fn write_magic_number (foilz_writer : * const fs.File.Writer ) ! void {
112- _ = try foilz_writer .write (MAGIC );
113- }
114107
115- pub fn write_file_record (foilz_writer : * const fs.File.Writer , name : []const u8 , data : []const u8 , mode : usize ) ! void {
116- _ = try foilz_writer .writeInt (u64 , name .len , .little );
117- _ = try foilz_writer .write (name );
118- _ = try foilz_writer .writeInt (u64 , data .len , .little );
119- if (data .len > 0 ) {
120- _ = try foilz_writer .write (data );
121- }
122- _ = try foilz_writer .writeInt (usize , mode , .little );
123- }
108+ try writer .writeAll (MAGIC );
109+ try writer .flush ();
124110
125- pub fn validate_magic (first_bytes : []const u8 ) bool {
126- return mem .eql (u8 , first_bytes , MAGIC );
111+ log .info ("Archived {} files into payload! 📥" , .{count });
127112}
128113
129- pub fn unpack_files (data : []const u8 , dest_path : []const u8 , uncompressed_size : u64 ) ! void {
114+ pub fn unpack_files (arena : Allocator , data : []const u8 , dest_path : []const u8 , uncompressed_size : u64 ) ! void {
130115 // Decompress the data in the payload
131116
132- var decompress_arena = std .heap .ArenaAllocator .init (std .heap .page_allocator );
133- defer decompress_arena .deinit ();
134- var allocator = decompress_arena .allocator ();
135-
136- var decompressed : []u8 = try allocator .alloc (u8 , uncompressed_size );
117+ var decompressed : []u8 = try arena .alloc (u8 , uncompressed_size );
137118
138119 var xz_buffer : xz.xz_buf = .{
139120 .in = data .ptr ,
@@ -155,7 +136,7 @@ pub fn unpack_files(data: []const u8, dest_path: []const u8, uncompressed_size:
155136 }
156137
157138 // Validate the header of the payload
158- if (! validate_magic ( decompressed [0.. 5])) {
139+ if (! std . mem . eql ( u8 , MAGIC , decompressed [0.. 5])) {
159140 return error .BadHeader ;
160141 }
161142
@@ -190,12 +171,12 @@ pub fn unpack_files(data: []const u8, dest_path: []const u8, uncompressed_size:
190171
191172 //////
192173 // Write the file
193- const full_file_path = try fs .path .join (allocator , &[_ ][]const u8 { dest_path [0.. ], file_name });
174+ const full_file_path = try fs .path .join (arena , &[_ ][]const u8 { dest_path [0.. ], file_name });
194175
195176 //////
196177 // Create any directories needed
197178 const dir_name = fs .path .dirname (file_name );
198- if (dir_name != null ) try create_dirs (dest_path [0.. ], dir_name .? , allocator );
179+ if (dir_name != null ) try create_dirs (dest_path [0.. ], dir_name .? , arena );
199180
200181 log .debug ("Unpacked File: {s}" , .{full_file_path });
201182
@@ -223,7 +204,7 @@ pub fn unpack_files(data: []const u8, dest_path: []const u8, uncompressed_size:
223204 log .debug ("Unpacked {} files" , .{file_count });
224205}
225206
226- fn create_dirs (dest_path : []const u8 , sub_dir_names : []const u8 , allocator : std.mem. Allocator ) ! void {
207+ fn create_dirs (dest_path : []const u8 , sub_dir_names : []const u8 , allocator : Allocator ) ! void {
227208 var iterator = try fs .path .componentIterator (sub_dir_names );
228209 var full_dir_path = try fs .path .join (allocator , &[_ ][]const u8 { dest_path , "" });
229210
@@ -244,8 +225,11 @@ fn create_dirs(dest_path: []const u8, sub_dir_names: []const u8, allocator: std.
244225
245226// Adapted from `std.log`, but without forcing a newline
246227fn direct_log (comptime message : []const u8 , args : anytype ) void {
247- std .debug .lockStdErr ();
248- defer std .debug .unlockStdErr ();
249- const stderr = std .io .getStdErr ().writer (); // Using the same IO as `std.log`
250- nosuspend stderr .print (message , args ) catch return ;
228+ var buffer : [64 ]u8 = undefined ;
229+ const stderr = std .debug .lockStderrWriter (& buffer );
230+ defer std .debug .unlockStderrWriter ();
231+ nosuspend {
232+ stderr .print (message , args ) catch return ;
233+ stderr .flush () catch return ;
234+ }
251235}
0 commit comments