| ... | ... | @@ -353,18 +353,13 @@ pub fn deleteTree(full_path: []const u8) !void { |
| 353 | 353 | |
| 354 | 354 | return dir.deleteTree(path.basename(full_path)); |
| 355 | 355 | } else { |
| 356 | | return Dir.posix_cwd.deleteTree(full_path); |
| 356 | return Dir.cwd().deleteTree(full_path); |
| 357 | 357 | } |
| 358 | 358 | } |
| 359 | 359 | |
| 360 | 360 | pub const Dir = struct { |
| 361 | 361 | fd: os.fd_t, |
| 362 | 362 | |
| 363 | | /// An open handle to the current working directory. |
| 364 | | /// Closing this directory is safety-checked illegal behavior. |
| 365 | | /// Not available on Windows. |
| 366 | | pub const posix_cwd = Dir{ .fd = os.AT_FDCWD }; |
| 367 | | |
| 368 | 363 | pub const Entry = struct { |
| 369 | 364 | name: []const u8, |
| 370 | 365 | kind: Kind, |
| ... | ... | @@ -386,12 +381,10 @@ pub const Dir = struct { |
| 386 | 381 | .macosx, .ios, .freebsd, .netbsd => struct { |
| 387 | 382 | dir: Dir, |
| 388 | 383 | seek: i64, |
| 389 | | buf: [buffer_len]u8, |
| 384 | buf: [8192]u8, // TODO align(@alignOf(os.dirent)), |
| 390 | 385 | index: usize, |
| 391 | 386 | end_index: usize, |
| 392 | 387 | |
| 393 | | pub const buffer_len = 8192; |
| 394 | | |
| 395 | 388 | const Self = @This(); |
| 396 | 389 | |
| 397 | 390 | /// Memory such as file names referenced in this returned entry becomes invalid |
| ... | ... | @@ -407,27 +400,24 @@ pub const Dir = struct { |
| 407 | 400 | fn nextDarwin(self: *Self) !?Entry { |
| 408 | 401 | start_over: while (true) { |
| 409 | 402 | if (self.index >= self.end_index) { |
| 410 | | while (true) { |
| 411 | | const rc = os.system.__getdirentries64( |
| 412 | | self.dir.fd, |
| 413 | | &self.buf, |
| 414 | | self.buf.len, |
| 415 | | &self.seek, |
| 416 | | ); |
| 417 | | if (rc == 0) return null; |
| 418 | | if (rc < 0) { |
| 419 | | switch (os.errno(rc)) { |
| 420 | | os.EBADF => unreachable, |
| 421 | | os.EFAULT => unreachable, |
| 422 | | os.ENOTDIR => unreachable, |
| 423 | | os.EINVAL => unreachable, |
| 424 | | else => |err| return os.unexpectedErrno(err), |
| 425 | | } |
| 403 | const rc = os.system.__getdirentries64( |
| 404 | self.dir.fd, |
| 405 | &self.buf, |
| 406 | self.buf.len, |
| 407 | &self.seek, |
| 408 | ); |
| 409 | if (rc == 0) return null; |
| 410 | if (rc < 0) { |
| 411 | switch (os.errno(rc)) { |
| 412 | os.EBADF => unreachable, |
| 413 | os.EFAULT => unreachable, |
| 414 | os.ENOTDIR => unreachable, |
| 415 | os.EINVAL => unreachable, |
| 416 | else => |err| return os.unexpectedErrno(err), |
| 426 | 417 | } |
| 427 | | self.index = 0; |
| 428 | | self.end_index = @intCast(usize, rc); |
| 429 | | break; |
| 430 | 418 | } |
| 419 | self.index = 0; |
| 420 | self.end_index = @intCast(usize, rc); |
| 431 | 421 | } |
| 432 | 422 | const darwin_entry = @ptrCast(*align(1) os.dirent, &self.buf[self.index]); |
| 433 | 423 | const next_index = self.index + darwin_entry.d_reclen; |
| ... | ... | @@ -460,26 +450,23 @@ pub const Dir = struct { |
| 460 | 450 | fn nextBsd(self: *Self) !?Entry { |
| 461 | 451 | start_over: while (true) { |
| 462 | 452 | if (self.index >= self.end_index) { |
| 463 | | while (true) { |
| 464 | | const rc = os.system.getdirentries( |
| 465 | | self.dir.fd, |
| 466 | | self.buf[0..].ptr, |
| 467 | | self.buf.len, |
| 468 | | &self.seek, |
| 469 | | ); |
| 470 | | switch (os.errno(rc)) { |
| 471 | | 0 => {}, |
| 472 | | os.EBADF => unreachable, |
| 473 | | os.EFAULT => unreachable, |
| 474 | | os.ENOTDIR => unreachable, |
| 475 | | os.EINVAL => unreachable, |
| 476 | | else => |err| return os.unexpectedErrno(err), |
| 477 | | } |
| 478 | | if (rc == 0) return null; |
| 479 | | self.index = 0; |
| 480 | | self.end_index = @intCast(usize, rc); |
| 481 | | break; |
| 453 | const rc = os.system.getdirentries( |
| 454 | self.dir.fd, |
| 455 | self.buf[0..].ptr, |
| 456 | self.buf.len, |
| 457 | &self.seek, |
| 458 | ); |
| 459 | switch (os.errno(rc)) { |
| 460 | 0 => {}, |
| 461 | os.EBADF => unreachable, |
| 462 | os.EFAULT => unreachable, |
| 463 | os.ENOTDIR => unreachable, |
| 464 | os.EINVAL => unreachable, |
| 465 | else => |err| return os.unexpectedErrno(err), |
| 482 | 466 | } |
| 467 | if (rc == 0) return null; |
| 468 | self.index = 0; |
| 469 | self.end_index = @intCast(usize, rc); |
| 483 | 470 | } |
| 484 | 471 | const freebsd_entry = @ptrCast(*align(1) os.dirent, &self.buf[self.index]); |
| 485 | 472 | const next_index = self.index + freebsd_entry.d_reclen; |
| ... | ... | @@ -511,12 +498,10 @@ pub const Dir = struct { |
| 511 | 498 | }, |
| 512 | 499 | .linux => struct { |
| 513 | 500 | dir: Dir, |
| 514 | | buf: [buffer_len]u8, |
| 501 | buf: [8192]u8, // TODO align(@alignOf(os.dirent64)), |
| 515 | 502 | index: usize, |
| 516 | 503 | end_index: usize, |
| 517 | 504 | |
| 518 | | pub const buffer_len = 8192; |
| 519 | | |
| 520 | 505 | const Self = @This(); |
| 521 | 506 | |
| 522 | 507 | /// Memory such as file names referenced in this returned entry becomes invalid |
| ... | ... | @@ -524,21 +509,18 @@ pub const Dir = struct { |
| 524 | 509 | pub fn next(self: *Self) !?Entry { |
| 525 | 510 | start_over: while (true) { |
| 526 | 511 | if (self.index >= self.end_index) { |
| 527 | | while (true) { |
| 528 | | const rc = os.linux.getdents64(self.dir.fd, &self.buf, self.buf.len); |
| 529 | | switch (os.linux.getErrno(rc)) { |
| 530 | | 0 => {}, |
| 531 | | os.EBADF => unreachable, |
| 532 | | os.EFAULT => unreachable, |
| 533 | | os.ENOTDIR => unreachable, |
| 534 | | os.EINVAL => unreachable, |
| 535 | | else => |err| return os.unexpectedErrno(err), |
| 536 | | } |
| 537 | | if (rc == 0) return null; |
| 538 | | self.index = 0; |
| 539 | | self.end_index = rc; |
| 540 | | break; |
| 512 | const rc = os.linux.getdents64(self.dir.fd, &self.buf, self.buf.len); |
| 513 | switch (os.linux.getErrno(rc)) { |
| 514 | 0 => {}, |
| 515 | os.EBADF => unreachable, |
| 516 | os.EFAULT => unreachable, |
| 517 | os.ENOTDIR => unreachable, |
| 518 | os.EINVAL => unreachable, |
| 519 | else => |err| return os.unexpectedErrno(err), |
| 541 | 520 | } |
| 521 | if (rc == 0) return null; |
| 522 | self.index = 0; |
| 523 | self.end_index = rc; |
| 542 | 524 | } |
| 543 | 525 | const linux_entry = @ptrCast(*align(1) os.dirent64, &self.buf[self.index]); |
| 544 | 526 | const next_index = self.index + linux_entry.d_reclen; |
| ... | ... | @@ -570,13 +552,117 @@ pub const Dir = struct { |
| 570 | 552 | }, |
| 571 | 553 | .windows => struct { |
| 572 | 554 | dir: Dir, |
| 573 | | find_file_data: os.windows.WIN32_FIND_DATAW, |
| 555 | buf: [8192]u8 align(@alignOf(os.windows.FILE_BOTH_DIR_INFORMATION)), |
| 556 | index: usize, |
| 557 | end_index: usize, |
| 574 | 558 | first: bool, |
| 575 | 559 | name_data: [256]u8, |
| 560 | |
| 561 | const Self = @This(); |
| 562 | |
| 563 | pub fn next(self: *Self) !?Entry { |
| 564 | start_over: while (true) { |
| 565 | const w = os.windows; |
| 566 | if (self.index >= self.end_index) { |
| 567 | var io: w.IO_STATUS_BLOCK = undefined; |
| 568 | //var mask_buf = [2]u16{ 'a', 0 }; |
| 569 | //var mask = w.UNICODE_STRING{ |
| 570 | // .Length = 2, |
| 571 | // .MaximumLength = 2, |
| 572 | // .Buffer = &mask_buf, |
| 573 | //}; |
| 574 | const rc = w.ntdll.NtQueryDirectoryFile( |
| 575 | self.dir.fd, |
| 576 | null, |
| 577 | null, |
| 578 | null, |
| 579 | &io, |
| 580 | &self.buf, |
| 581 | self.buf.len, |
| 582 | .FileBothDirectoryInformation, |
| 583 | w.FALSE, |
| 584 | null, |
| 585 | if (self.first) w.BOOLEAN(w.TRUE) else w.BOOLEAN(w.FALSE), |
| 586 | ); |
| 587 | self.first = false; |
| 588 | if (io.Information == 0) return null; |
| 589 | self.index = 0; |
| 590 | self.end_index = io.Information; |
| 591 | switch (rc) { |
| 592 | w.STATUS.SUCCESS => {}, |
| 593 | else => return w.unexpectedStatus(rc), |
| 594 | } |
| 595 | } |
| 596 | |
| 597 | const aligned_ptr = @alignCast(@alignOf(w.FILE_BOTH_DIR_INFORMATION), &self.buf[self.index]); |
| 598 | const dir_info = @ptrCast(*w.FILE_BOTH_DIR_INFORMATION, aligned_ptr); |
| 599 | if (dir_info.NextEntryOffset != 0) { |
| 600 | self.index += dir_info.NextEntryOffset; |
| 601 | } else { |
| 602 | self.index = self.buf.len; |
| 603 | } |
| 604 | |
| 605 | const name_utf16le = @ptrCast([*]u16, &dir_info.FileName)[0 .. dir_info.FileNameLength / 2]; |
| 606 | |
| 607 | if (mem.eql(u16, name_utf16le, [_]u16{'.'}) or mem.eql(u16, name_utf16le, [_]u16{ '.', '.' })) |
| 608 | continue; |
| 609 | // Trust that Windows gives us valid UTF-16LE |
| 610 | const name_utf8_len = std.unicode.utf16leToUtf8(self.name_data[0..], name_utf16le) catch unreachable; |
| 611 | const name_utf8 = self.name_data[0..name_utf8_len]; |
| 612 | const kind = blk: { |
| 613 | const attrs = dir_info.FileAttributes; |
| 614 | if (attrs & w.FILE_ATTRIBUTE_DIRECTORY != 0) break :blk Entry.Kind.Directory; |
| 615 | if (attrs & w.FILE_ATTRIBUTE_REPARSE_POINT != 0) break :blk Entry.Kind.SymLink; |
| 616 | break :blk Entry.Kind.File; |
| 617 | }; |
| 618 | return Entry{ |
| 619 | .name = name_utf8, |
| 620 | .kind = kind, |
| 621 | }; |
| 622 | } |
| 623 | } |
| 576 | 624 | }, |
| 577 | 625 | else => @compileError("unimplemented"), |
| 578 | 626 | }; |
| 579 | 627 | |
| 628 | pub fn iterate(self: Dir) Iterator { |
| 629 | switch (builtin.os) { |
| 630 | .macosx, .ios, .freebsd, .netbsd => return Iterator{ |
| 631 | .dir = self, |
| 632 | .seek = 0, |
| 633 | .index = 0, |
| 634 | .end_index = 0, |
| 635 | .buf = undefined, |
| 636 | }, |
| 637 | .linux => return Iterator{ |
| 638 | .dir = self, |
| 639 | .index = 0, |
| 640 | .end_index = 0, |
| 641 | .buf = undefined, |
| 642 | }, |
| 643 | .windows => return Iterator{ |
| 644 | .dir = self, |
| 645 | .index = 0, |
| 646 | .end_index = 0, |
| 647 | .first = true, |
| 648 | .buf = undefined, |
| 649 | .name_data = undefined, |
| 650 | }, |
| 651 | else => @compileError("unimplemented"), |
| 652 | } |
| 653 | } |
| 654 | |
| 655 | /// Returns an open handle to the current working directory. |
| 656 | /// Closing the returned `Dir` is checked illegal behavior. |
| 657 | /// On POSIX targets, this function is comptime-callable. |
| 658 | pub fn cwd() Dir { |
| 659 | if (os.windows.is_the_target) { |
| 660 | return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle }; |
| 661 | } else { |
| 662 | return Dir{ .fd = os.AT_FDCWD }; |
| 663 | } |
| 664 | } |
| 665 | |
| 580 | 666 | pub const OpenError = error{ |
| 581 | 667 | FileNotFound, |
| 582 | 668 | NotDir, |
| ... | ... | @@ -594,18 +680,15 @@ pub const Dir = struct { |
| 594 | 680 | |
| 595 | 681 | /// Call `close` to free the directory handle. |
| 596 | 682 | pub fn open(dir_path: []const u8) OpenError!Dir { |
| 597 | | return posix_cwd.openDir(dir_path); |
| 683 | return cwd().openDir(dir_path); |
| 598 | 684 | } |
| 599 | 685 | |
| 600 | 686 | /// Same as `open` except the parameter is null-terminated. |
| 601 | 687 | pub fn openC(dir_path_c: [*]const u8) OpenError!Dir { |
| 602 | | return posix_cwd.openDirC(dir_path_c); |
| 688 | return cwd().openDirC(dir_path_c); |
| 603 | 689 | } |
| 604 | 690 | |
| 605 | 691 | pub fn close(self: *Dir) void { |
| 606 | | if (os.windows.is_the_target) { |
| 607 | | @panic("TODO"); |
| 608 | | } |
| 609 | 692 | os.close(self.fd); |
| 610 | 693 | self.* = undefined; |
| 611 | 694 | } |
| ... | ... | @@ -625,14 +708,25 @@ pub const Dir = struct { |
| 625 | 708 | |
| 626 | 709 | /// Call `close` on the result when done. |
| 627 | 710 | pub fn openDir(self: Dir, sub_path: []const u8) OpenError!Dir { |
| 711 | std.debug.warn("openDir {}\n", sub_path); |
| 712 | if (os.windows.is_the_target) { |
| 713 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); |
| 714 | return self.openDirW(&sub_path_w); |
| 715 | } |
| 716 | |
| 628 | 717 | const sub_path_c = try os.toPosixPath(sub_path); |
| 629 | 718 | return self.openDirC(&sub_path_c); |
| 630 | 719 | } |
| 631 | 720 | |
| 632 | | /// Call `close` on the result when done. |
| 633 | | pub fn openDirC(self: Dir, sub_path: [*]const u8) OpenError!Dir { |
| 721 | /// Same as `openDir` except the parameter is null-terminated. |
| 722 | pub fn openDirC(self: Dir, sub_path_c: [*]const u8) OpenError!Dir { |
| 723 | if (os.windows.is_the_target) { |
| 724 | const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); |
| 725 | return self.openDirW(&sub_path_w); |
| 726 | } |
| 727 | |
| 634 | 728 | const flags = os.O_RDONLY | os.O_DIRECTORY | os.O_CLOEXEC; |
| 635 | | const fd = os.openatC(self.fd, sub_path, flags, 0) catch |err| switch (err) { |
| 729 | const fd = os.openatC(self.fd, sub_path_c, flags, 0) catch |err| switch (err) { |
| 636 | 730 | error.FileTooBig => unreachable, // can't happen for directories |
| 637 | 731 | error.IsDir => unreachable, // we're providing O_DIRECTORY |
| 638 | 732 | error.NoSpaceLeft => unreachable, // not providing O_CREAT |
| ... | ... | @@ -642,6 +736,79 @@ pub const Dir = struct { |
| 642 | 736 | return Dir{ .fd = fd }; |
| 643 | 737 | } |
| 644 | 738 | |
| 739 | /// Same as `openDir` except the path parameter is UTF16LE, NT-prefixed. |
| 740 | /// This function is Windows-only. |
| 741 | pub fn openDirW(self: Dir, sub_path_w: [*]const u16) OpenError!Dir { |
| 742 | const w = os.windows; |
| 743 | var result = Dir{ |
| 744 | .fd = undefined, |
| 745 | }; |
| 746 | //var mask: ?[*]const u16 = undefined; |
| 747 | //var nt_name: w.UNICODE_STRING = undefined; |
| 748 | //if (w.ntdll.RtlDosPathNameToNtPathName_U(sub_path_w, &nt_name, null, null) == 0) { |
| 749 | // return error.FileNotFound; |
| 750 | //} |
| 751 | //defer w.ntdll.RtlFreeUnicodeString(&nt_name); |
| 752 | //if (mask) |m| { |
| 753 | // if (m[0] == 0) { |
| 754 | // return error.FileNotFound; |
| 755 | // } else { |
| 756 | // nt_name.Length = @intCast(u16, @ptrToInt(mask) - @ptrToInt(nt_name.Buffer)); |
| 757 | // } |
| 758 | //} else { |
| 759 | // return error.FileNotFound; |
| 760 | //} |
| 761 | |
| 762 | const path_len_bytes = @intCast(u16, mem.toSliceConst(u16, sub_path_w).len * 2); |
| 763 | std.debug.warn("path_len_bytes = {}\n", path_len_bytes); |
| 764 | var nt_name = w.UNICODE_STRING{ |
| 765 | .Length = path_len_bytes, |
| 766 | .MaximumLength = path_len_bytes, |
| 767 | .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)), |
| 768 | }; |
| 769 | var attr = w.OBJECT_ATTRIBUTES{ |
| 770 | .Length = @sizeOf(w.OBJECT_ATTRIBUTES), |
| 771 | .RootDirectory = if (path.isAbsoluteW(sub_path_w)) null else self.fd, |
| 772 | .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here. |
| 773 | .ObjectName = &nt_name, |
| 774 | .SecurityDescriptor = null, |
| 775 | .SecurityQualityOfService = null, |
| 776 | }; |
| 777 | std.debug.warn("RootDirectory = {}\n", attr.RootDirectory); |
| 778 | var io: w.IO_STATUS_BLOCK = undefined; |
| 779 | const wide_slice = nt_name.Buffer[0 .. nt_name.Length / 2]; |
| 780 | //const wide_slice2 = std.mem.toSliceConst(u16, mask.?); |
| 781 | var buf: [200]u8 = undefined; |
| 782 | //var buf2: [200]u8 = undefined; |
| 783 | const len = std.unicode.utf16leToUtf8(&buf, wide_slice) catch unreachable; |
| 784 | //const len2 = std.unicode.utf16leToUtf8(&buf2, wide_slice2) catch unreachable; |
| 785 | std.debug.warn("path: {}\n", buf[0..len]); |
| 786 | //std.debug.warn("path: {}\nmask: {}\n", buf[0..len], buf2[0..len2]); |
| 787 | const rc = w.ntdll.NtCreateFile( |
| 788 | &result.fd, |
| 789 | w.GENERIC_READ | w.SYNCHRONIZE, |
| 790 | &attr, |
| 791 | &io, |
| 792 | null, |
| 793 | 0, |
| 794 | w.FILE_SHARE_READ | w.FILE_SHARE_WRITE, |
| 795 | w.FILE_OPEN, |
| 796 | w.FILE_DIRECTORY_FILE | w.FILE_SYNCHRONOUS_IO_NONALERT | w.FILE_OPEN_FOR_BACKUP_INTENT, |
| 797 | null, |
| 798 | 0, |
| 799 | ); |
| 800 | std.debug.warn("result.fd = {}\n", result.fd); |
| 801 | switch (rc) { |
| 802 | w.STATUS.SUCCESS => return result, |
| 803 | w.STATUS.OBJECT_NAME_INVALID => @panic("openDirW invalid object name"), |
| 804 | w.STATUS.OBJECT_NAME_NOT_FOUND => return error.FileNotFound, |
| 805 | w.STATUS.INVALID_PARAMETER => { |
| 806 | @panic("invalid parameter"); |
| 807 | }, |
| 808 | else => return w.unexpectedStatus(rc), |
| 809 | } |
| 810 | } |
| 811 | |
| 645 | 812 | pub const DeleteFileError = os.UnlinkError; |
| 646 | 813 | |
| 647 | 814 | /// Delete a file name and possibly the file it refers to, based on an open directory handle. |
| ... | ... | @@ -677,6 +844,10 @@ pub const Dir = struct { |
| 677 | 844 | /// Returns `error.DirNotEmpty` if the directory is not empty. |
| 678 | 845 | /// To delete a directory recursively, see `deleteTree`. |
| 679 | 846 | pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void { |
| 847 | if (os.windows.is_the_target) { |
| 848 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); |
| 849 | return self.deleteDirW(&sub_path_w); |
| 850 | } |
| 680 | 851 | const sub_path_c = try os.toPosixPath(sub_path); |
| 681 | 852 | return self.deleteDirC(&sub_path_c); |
| 682 | 853 | } |
| ... | ... | @@ -689,24 +860,25 @@ pub const Dir = struct { |
| 689 | 860 | }; |
| 690 | 861 | } |
| 691 | 862 | |
| 692 | | pub fn iterate(self: Dir) Iterator { |
| 693 | | switch (builtin.os) { |
| 694 | | .macosx, .ios, .freebsd, .netbsd => return Iterator{ |
| 695 | | .dir = self, |
| 696 | | .seek = 0, |
| 697 | | .index = 0, |
| 698 | | .end_index = 0, |
| 699 | | .buf = undefined, |
| 700 | | }, |
| 701 | | .linux => return Iterator{ |
| 702 | | .dir = self, |
| 703 | | .index = 0, |
| 704 | | .end_index = 0, |
| 705 | | .buf = undefined, |
| 706 | | }, |
| 707 | | .windows => @panic("TODO"), |
| 708 | | else => @compileError("unimplemented"), |
| 709 | | } |
| 863 | /// Same as `deleteDir` except the parameter is UTF16LE, NT prefixed. |
| 864 | /// This function is Windows-only. |
| 865 | pub fn deleteDirW(self: Dir, sub_path_w: [*]const u16) DeleteDirError!void { |
| 866 | os.unlinkatW(self.fd, sub_path_w, os.AT_REMOVEDIR) catch |err| switch (err) { |
| 867 | error.IsDir => unreachable, // not possible since we pass AT_REMOVEDIR |
| 868 | else => |e| return e, |
| 869 | }; |
| 870 | } |
| 871 | |
| 872 | /// Read value of a symbolic link. |
| 873 | /// The return value is a slice of `buffer`, from index `0`. |
| 874 | pub fn readLink(self: Dir, sub_path: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { |
| 875 | const sub_path_c = try os.toPosixPath(sub_path); |
| 876 | return self.readLinkC(&sub_path_c, buffer); |
| 877 | } |
| 878 | |
| 879 | /// Same as `readLink`, except the `pathname` parameter is null-terminated. |
| 880 | pub fn readLinkC(self: Dir, sub_path_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { |
| 881 | return os.readlinkatC(self.fd, sub_path_c, buffer); |
| 710 | 882 | } |
| 711 | 883 | |
| 712 | 884 | pub const DeleteTreeError = error{ |
| ... | ... | @@ -953,7 +1125,6 @@ pub const Walker = struct { |
| 953 | 1125 | /// Must call `Walker.deinit` when done. |
| 954 | 1126 | /// `dir_path` must not end in a path separator. |
| 955 | 1127 | /// The order of returned file system entries is undefined. |
| 956 | | /// TODO: https://github.com/ziglang/zig/issues/2888 |
| 957 | 1128 | pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { |
| 958 | 1129 | assert(!mem.endsWith(u8, dir_path, path.sep_str)); |
| 959 | 1130 | |
| ... | ... | @@ -978,15 +1149,13 @@ pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { |
| 978 | 1149 | |
| 979 | 1150 | /// Read value of a symbolic link. |
| 980 | 1151 | /// The return value is a slice of buffer, from index `0`. |
| 981 | | /// TODO https://github.com/ziglang/zig/issues/2888 |
| 982 | | pub fn readLink(pathname: []const u8, buffer: *[os.PATH_MAX]u8) ![]u8 { |
| 1152 | pub fn readLink(pathname: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { |
| 983 | 1153 | return os.readlink(pathname, buffer); |
| 984 | 1154 | } |
| 985 | 1155 | |
| 986 | | /// Same as `readLink`, except the `pathname` parameter is null-terminated. |
| 987 | | /// TODO https://github.com/ziglang/zig/issues/2888 |
| 988 | | pub fn readLinkC(pathname: [*]const u8, buffer: *[os.PATH_MAX]u8) ![]u8 { |
| 989 | | return os.readlinkC(pathname, buffer); |
| 1156 | /// Same as `readLink`, except the parameter is null-terminated. |
| 1157 | pub fn readLinkC(pathname_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { |
| 1158 | return os.readlinkC(pathname_c, buffer); |
| 990 | 1159 | } |
| 991 | 1160 | |
| 992 | 1161 | pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfExePathError; |