| ... | @@ -461,36 +461,26 @@ fn runResource( | ... | @@ -461,36 +461,26 @@ fn runResource( |
| 461 | }; | 461 | }; |
| 462 | defer tmp_directory.handle.close(); | 462 | defer tmp_directory.handle.close(); |
| 463 | | 463 | |
| 464 | const package_dir = try unpackResource(f, resource, uri_path, tmp_directory); | 464 | const pkg_dir = try unpackResource(f, resource, uri_path, tmp_directory); |
| 465 | | 465 | |
| 466 | if (package_dir) |dir_name| { | 466 | var pkg_path: Cache.Path = if (pkg_dir) |pkg_dir_name| |
| 467 | // Position tmp_directory to dir_name inside tmp_dir_sub_path. | 467 | .{ .root_dir = tmp_directory, .sub_path = pkg_dir_name } |
| 468 | const path = try cache_root.join(arena, &.{ tmp_dir_sub_path, dir_name }); | 468 | else |
| 469 | const handle = tmp_directory.handle.openDir(dir_name, .{ .iterate = true }) catch |err| { | 469 | .{ .root_dir = tmp_directory }; |
| 470 | try eb.addRootErrorMessage(.{ | 470 | |
| 471 | .msg = try eb.printString("unable to open temporary directory '{s}': {s}", .{ | 471 | // btrfs workaround; reopen tmp_directory |
| 472 | path, @errorName(err), | 472 | if (native_os == .linux and f.job_queue.work_around_btrfs_bug) { |
| 473 | }), | 473 | // https://github.com/ziglang/zig/issues/17095 |
| 474 | }); | 474 | pkg_path.root_dir.handle.close(); |
| 475 | return error.FetchFailed; | 475 | pkg_path.root_dir.handle = cache_root.handle.makeOpenPath(tmp_dir_sub_path, .{ |
| 476 | }; | 476 | .iterate = true, |
| 477 | tmp_directory.handle.close(); | 477 | }) catch @panic("btrfs workaround failed"); |
| 478 | tmp_directory = .{ .path = path, .handle = handle }; | | |
| 479 | } else { | | |
| 480 | // btrfs workaround; reopen tmp_directory | | |
| 481 | if (native_os == .linux and f.job_queue.work_around_btrfs_bug) { | | |
| 482 | // https://github.com/ziglang/zig/issues/17095 | | |
| 483 | tmp_directory.handle.close(); | | |
| 484 | tmp_directory.handle = cache_root.handle.makeOpenPath(tmp_dir_sub_path, .{ | | |
| 485 | .iterate = true, | | |
| 486 | }) catch @panic("btrfs workaround failed"); | | |
| 487 | } | | |
| 488 | } | 478 | } |
| 489 | | 479 | |
| 490 | // Load, parse, and validate the unpacked build.zig.zon file. It is allowed | 480 | // Load, parse, and validate the unpacked build.zig.zon file. It is allowed |
| 491 | // for the file to be missing, in which case this fetched package is | 481 | // for the file to be missing, in which case this fetched package is |
| 492 | // considered to be a "naked" package. | 482 | // considered to be a "naked" package. |
| 493 | try loadManifest(f, .{ .root_dir = tmp_directory }); | 483 | try loadManifest(f, pkg_path); |
| 494 | | 484 | |
| 495 | // Apply the manifest's inclusion rules to the temporary directory by | 485 | // Apply the manifest's inclusion rules to the temporary directory by |
| 496 | // deleting excluded files. If any error occurred for files that were | 486 | // deleting excluded files. If any error occurred for files that were |
| ... | @@ -505,10 +495,10 @@ fn runResource( | ... | @@ -505,10 +495,10 @@ fn runResource( |
| 505 | | 495 | |
| 506 | // Compute the package hash based on the remaining files in the temporary | 496 | // Compute the package hash based on the remaining files in the temporary |
| 507 | // directory. | 497 | // directory. |
| 508 | f.actual_hash = try computeHash(f, tmp_directory, filter); | 498 | f.actual_hash = try computeHash(f, pkg_path, filter); |
| 509 | | 499 | |
| 510 | break :blk if (package_dir) |dir_name| | 500 | break :blk if (pkg_dir) |pkg_dir_name| |
| 511 | try fs.path.join(arena, &.{ tmp_dir_sub_path, dir_name }) | 501 | try fs.path.join(arena, &.{ tmp_dir_sub_path, pkg_dir_name }) |
| 512 | else | 502 | else |
| 513 | tmp_dir_sub_path; | 503 | tmp_dir_sub_path; |
| 514 | }; | 504 | }; |
| ... | @@ -1388,7 +1378,7 @@ pub fn renameTmpIntoCache( | ... | @@ -1388,7 +1378,7 @@ pub fn renameTmpIntoCache( |
| 1388 | /// function. | 1378 | /// function. |
| 1389 | fn computeHash( | 1379 | fn computeHash( |
| 1390 | f: *Fetch, | 1380 | f: *Fetch, |
| 1391 | tmp_directory: Cache.Directory, | 1381 | pkg_path: Cache.Path, |
| 1392 | filter: Filter, | 1382 | filter: Filter, |
| 1393 | ) RunError!Manifest.Digest { | 1383 | ) RunError!Manifest.Digest { |
| 1394 | // All the path name strings need to be in memory for sorting. | 1384 | // All the path name strings need to be in memory for sorting. |
| ... | @@ -1396,6 +1386,7 @@ fn computeHash( | ... | @@ -1396,6 +1386,7 @@ fn computeHash( |
| 1396 | const gpa = f.arena.child_allocator; | 1386 | const gpa = f.arena.child_allocator; |
| 1397 | const eb = &f.error_bundle; | 1387 | const eb = &f.error_bundle; |
| 1398 | const thread_pool = f.job_queue.thread_pool; | 1388 | const thread_pool = f.job_queue.thread_pool; |
| | 1389 | const root_dir = pkg_path.root_dir.handle; |
| 1399 | | 1390 | |
| 1400 | // Collect all files, recursively, then sort. | 1391 | // Collect all files, recursively, then sort. |
| 1401 | var all_files = std.ArrayList(*HashedFile).init(gpa); | 1392 | var all_files = std.ArrayList(*HashedFile).init(gpa); |
| ... | @@ -1409,7 +1400,7 @@ fn computeHash( | ... | @@ -1409,7 +1400,7 @@ fn computeHash( |
| 1409 | var sus_dirs: std.StringArrayHashMapUnmanaged(void) = .{}; | 1400 | var sus_dirs: std.StringArrayHashMapUnmanaged(void) = .{}; |
| 1410 | defer sus_dirs.deinit(gpa); | 1401 | defer sus_dirs.deinit(gpa); |
| 1411 | | 1402 | |
| 1412 | var walker = try tmp_directory.handle.walk(gpa); | 1403 | var walker = try root_dir.walk(gpa); |
| 1413 | defer walker.deinit(); | 1404 | defer walker.deinit(); |
| 1414 | | 1405 | |
| 1415 | { | 1406 | { |
| ... | @@ -1423,7 +1414,7 @@ fn computeHash( | ... | @@ -1423,7 +1414,7 @@ fn computeHash( |
| 1423 | while (walker.next() catch |err| { | 1414 | while (walker.next() catch |err| { |
| 1424 | try eb.addRootErrorMessage(.{ .msg = try eb.printString( | 1415 | try eb.addRootErrorMessage(.{ .msg = try eb.printString( |
| 1425 | "unable to walk temporary directory '{}': {s}", | 1416 | "unable to walk temporary directory '{}': {s}", |
| 1426 | .{ tmp_directory, @errorName(err) }, | 1417 | .{ pkg_path, @errorName(err) }, |
| 1427 | ) }); | 1418 | ) }); |
| 1428 | return error.FetchFailed; | 1419 | return error.FetchFailed; |
| 1429 | }) |entry| { | 1420 | }) |entry| { |
| ... | @@ -1444,7 +1435,7 @@ fn computeHash( | ... | @@ -1444,7 +1435,7 @@ fn computeHash( |
| 1444 | }; | 1435 | }; |
| 1445 | wait_group.start(); | 1436 | wait_group.start(); |
| 1446 | try thread_pool.spawn(workerDeleteFile, .{ | 1437 | try thread_pool.spawn(workerDeleteFile, .{ |
| 1447 | tmp_directory.handle, deleted_file, &wait_group, | 1438 | root_dir, deleted_file, &wait_group, |
| 1448 | }); | 1439 | }); |
| 1449 | try deleted_files.append(deleted_file); | 1440 | try deleted_files.append(deleted_file); |
| 1450 | continue; | 1441 | continue; |
| ... | @@ -1467,14 +1458,14 @@ fn computeHash( | ... | @@ -1467,14 +1458,14 @@ fn computeHash( |
| 1467 | const hashed_file = try arena.create(HashedFile); | 1458 | const hashed_file = try arena.create(HashedFile); |
| 1468 | hashed_file.* = .{ | 1459 | hashed_file.* = .{ |
| 1469 | .fs_path = fs_path, | 1460 | .fs_path = fs_path, |
| 1470 | .normalized_path = try normalizePathAlloc(arena, fs_path), | 1461 | .normalized_path = try normalizePathAlloc(arena, stripRoot(fs_path, pkg_path.sub_path)), |
| 1471 | .kind = kind, | 1462 | .kind = kind, |
| 1472 | .hash = undefined, // to be populated by the worker | 1463 | .hash = undefined, // to be populated by the worker |
| 1473 | .failure = undefined, // to be populated by the worker | 1464 | .failure = undefined, // to be populated by the worker |
| 1474 | }; | 1465 | }; |
| 1475 | wait_group.start(); | 1466 | wait_group.start(); |
| 1476 | try thread_pool.spawn(workerHashFile, .{ | 1467 | try thread_pool.spawn(workerHashFile, .{ |
| 1477 | tmp_directory.handle, hashed_file, &wait_group, | 1468 | root_dir, hashed_file, &wait_group, |
| 1478 | }); | 1469 | }); |
| 1479 | try all_files.append(hashed_file); | 1470 | try all_files.append(hashed_file); |
| 1480 | } | 1471 | } |
| ... | @@ -1493,7 +1484,7 @@ fn computeHash( | ... | @@ -1493,7 +1484,7 @@ fn computeHash( |
| 1493 | var i: usize = 0; | 1484 | var i: usize = 0; |
| 1494 | while (i < sus_dirs.count()) : (i += 1) { | 1485 | while (i < sus_dirs.count()) : (i += 1) { |
| 1495 | const sus_dir = sus_dirs.keys()[i]; | 1486 | const sus_dir = sus_dirs.keys()[i]; |
| 1496 | tmp_directory.handle.deleteDir(sus_dir) catch |err| switch (err) { | 1487 | root_dir.deleteDir(sus_dir) catch |err| switch (err) { |
| 1497 | error.DirNotEmpty => continue, | 1488 | error.DirNotEmpty => continue, |
| 1498 | error.FileNotFound => continue, | 1489 | error.FileNotFound => continue, |
| 1499 | else => |e| { | 1490 | else => |e| { |
| ... | @@ -1657,6 +1648,17 @@ const HashedFile = struct { | ... | @@ -1657,6 +1648,17 @@ const HashedFile = struct { |
| 1657 | } | 1648 | } |
| 1658 | }; | 1649 | }; |
| 1659 | | 1650 | |
| | 1651 | /// Strips root directory name from file system path. |
| | 1652 | fn stripRoot(fs_path: []const u8, root_dir: []const u8) []const u8 { |
| | 1653 | if (root_dir.len == 0 or fs_path.len <= root_dir.len) return fs_path; |
| | 1654 | |
| | 1655 | if (std.mem.eql(u8, fs_path[0..root_dir.len], root_dir) and fs_path[root_dir.len] == fs.path.sep) { |
| | 1656 | return fs_path[root_dir.len + 1 ..]; |
| | 1657 | } |
| | 1658 | |
| | 1659 | return fs_path; |
| | 1660 | } |
| | 1661 | |
| 1660 | /// Make a file system path identical independently of operating system path inconsistencies. | 1662 | /// Make a file system path identical independently of operating system path inconsistencies. |
| 1661 | /// This converts backslashes into forward slashes. | 1663 | /// This converts backslashes into forward slashes. |
| 1662 | fn normalizePathAlloc(arena: Allocator, fs_path: []const u8) ![]const u8 { | 1664 | fn normalizePathAlloc(arena: Allocator, fs_path: []const u8) ![]const u8 { |