authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-04 23:28:51-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-07 11:03:36-08:00
log3bc22dbd940836858311dffbfdabad6ad26d9376
tree5bbf729d67ed21bebca2f2648839d157f0c47b04
parent816565dd077f561a46a9f31d9ecce32f152f9553

std.Build.Step.Options: exploit Io.File.Atomic


1 files changed, 14 insertions(+), 32 deletions(-)

lib/std/Build/Step/Options.zig+14-32
...@@ -476,46 +476,28 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {...@@ -476,46 +476,28 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
476 return;476 return;
477 } else |outer_err| switch (outer_err) {477 } else |outer_err| switch (outer_err) {
478 error.FileNotFound => {478 error.FileNotFound => {
479 const sub_dirname = fs.path.dirname(sub_path).?;479 var atomic_file = b.cache_root.handle.createFileAtomic(io, sub_path, .{
480 b.cache_root.handle.createDirPath(io, sub_dirname) catch |e|480 .replace = false,
481 return step.fail("unable to make path '{f}{s}': {t}", .{ b.cache_root, sub_dirname, e });481 .make_path = true,
482482 }) catch |err| return step.fail("failed to create temporary path for '{f}{s}': {t}", .{
483 const rand_int = std.crypto.random.int(u64);483 b.cache_root, sub_path, err,
484 const tmp_sub_path = "tmp" ++ fs.path.sep_str ++484 });
485 std.fmt.hex(rand_int) ++ fs.path.sep_str ++485 defer atomic_file.deinit(io);
486 basename;
487 const tmp_sub_path_dirname = fs.path.dirname(tmp_sub_path).?;
488
489 b.cache_root.handle.createDirPath(io, tmp_sub_path_dirname) catch |err| {
490 return step.fail("unable to make temporary directory '{f}{s}': {t}", .{
491 b.cache_root, tmp_sub_path_dirname, err,
492 });
493 };
494486
495 b.cache_root.handle.writeFile(io, .{ .sub_path = tmp_sub_path, .data = options.contents.items }) catch |err| {487 atomic_file.file.writeStreamingAll(io, options.contents.items) catch |err| {
496 return step.fail("unable to write options to '{f}{s}': {t}", .{488 return step.fail("failed to write options to temporary path for '{f}{s}': {t}", .{
497 b.cache_root, tmp_sub_path, err,489 b.cache_root, sub_path, err,
498 });490 });
499 };491 };
500492
501 b.cache_root.handle.rename(tmp_sub_path, b.cache_root.handle, sub_path, io) catch |err| switch (err) {493 atomic_file.link(io) catch |err| switch (err) {
502 error.PathAlreadyExists => {494 error.PathAlreadyExists => {
503 // Other process beat us to it. Clean up the temp file.
504 b.cache_root.handle.deleteFile(io, tmp_sub_path) catch |e| {
505 try step.addError("warning: unable to delete temp file '{f}{s}': {t}", .{
506 b.cache_root, tmp_sub_path, e,
507 });
508 };
509 step.result_cached = true;495 step.result_cached = true;
510 return;496 return;
511 },497 },
512 else => {498 else => return step.fail("failed to link temporary file into '{f}{s}': {t}", .{
513 return step.fail("unable to rename options from '{f}{s}' to '{f}{s}': {t}", .{499 b.cache_root, sub_path, err,
514 b.cache_root, tmp_sub_path,500 }),
515 b.cache_root, sub_path,
516 err,
517 });
518 },
519 };501 };
520 },502 },
521 else => |e| return step.fail("unable to access options file '{f}{s}': {t}", .{503 else => |e| return step.fail("unable to access options file '{f}{s}': {t}", .{