| ... | @@ -353,18 +353,13 @@ pub fn deleteTree(full_path: []const u8) !void { | ... | @@ -353,18 +353,13 @@ pub fn deleteTree(full_path: []const u8) !void { |
| 353 | | 353 | |
| 354 | return dir.deleteTree(path.basename(full_path)); | 354 | return dir.deleteTree(path.basename(full_path)); |
| 355 | } else { | 355 | } else { |
| 356 | return Dir.posix_cwd.deleteTree(full_path); | 356 | return Dir.cwd().deleteTree(full_path); |
| 357 | } | 357 | } |
| 358 | } | 358 | } |
| 359 | | 359 | |
| 360 | pub const Dir = struct { | 360 | pub const Dir = struct { |
| 361 | fd: os.fd_t, | 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 | pub const Entry = struct { | 363 | pub const Entry = struct { |
| 369 | name: []const u8, | 364 | name: []const u8, |
| 370 | kind: Kind, | 365 | kind: Kind, |
| ... | @@ -386,12 +381,10 @@ pub const Dir = struct { | ... | @@ -386,12 +381,10 @@ pub const Dir = struct { |
| 386 | .macosx, .ios, .freebsd, .netbsd => struct { | 381 | .macosx, .ios, .freebsd, .netbsd => struct { |
| 387 | dir: Dir, | 382 | dir: Dir, |
| 388 | seek: i64, | 383 | seek: i64, |
| 389 | buf: [buffer_len]u8, | 384 | buf: [8192]u8, // TODO align(@alignOf(os.dirent)), |
| 390 | index: usize, | 385 | index: usize, |
| 391 | end_index: usize, | 386 | end_index: usize, |
| 392 | | 387 | |
| 393 | pub const buffer_len = 8192; | | |
| 394 | | | |
| 395 | const Self = @This(); | 388 | const Self = @This(); |
| 396 | | 389 | |
| 397 | /// Memory such as file names referenced in this returned entry becomes invalid | 390 | /// Memory such as file names referenced in this returned entry becomes invalid |
| ... | @@ -407,27 +400,24 @@ pub const Dir = struct { | ... | @@ -407,27 +400,24 @@ pub const Dir = struct { |
| 407 | fn nextDarwin(self: *Self) !?Entry { | 400 | fn nextDarwin(self: *Self) !?Entry { |
| 408 | start_over: while (true) { | 401 | start_over: while (true) { |
| 409 | if (self.index >= self.end_index) { | 402 | if (self.index >= self.end_index) { |
| 410 | while (true) { | 403 | const rc = os.system.__getdirentries64( |
| 411 | const rc = os.system.__getdirentries64( | 404 | self.dir.fd, |
| 412 | self.dir.fd, | 405 | &self.buf, |
| 413 | &self.buf, | 406 | self.buf.len, |
| 414 | self.buf.len, | 407 | &self.seek, |
| 415 | &self.seek, | 408 | ); |
| 416 | ); | 409 | if (rc == 0) return null; |
| 417 | if (rc == 0) return null; | 410 | if (rc < 0) { |
| 418 | if (rc < 0) { | 411 | switch (os.errno(rc)) { |
| 419 | switch (os.errno(rc)) { | 412 | os.EBADF => unreachable, |
| 420 | os.EBADF => unreachable, | 413 | os.EFAULT => unreachable, |
| 421 | os.EFAULT => unreachable, | 414 | os.ENOTDIR => unreachable, |
| 422 | os.ENOTDIR => unreachable, | 415 | os.EINVAL => unreachable, |
| 423 | os.EINVAL => unreachable, | 416 | else => |err| return os.unexpectedErrno(err), |
| 424 | else => |err| return os.unexpectedErrno(err), | | |
| 425 | } | | |
| 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 | const darwin_entry = @ptrCast(*align(1) os.dirent, &self.buf[self.index]); | 422 | const darwin_entry = @ptrCast(*align(1) os.dirent, &self.buf[self.index]); |
| 433 | const next_index = self.index + darwin_entry.d_reclen; | 423 | const next_index = self.index + darwin_entry.d_reclen; |
| ... | @@ -460,26 +450,23 @@ pub const Dir = struct { | ... | @@ -460,26 +450,23 @@ pub const Dir = struct { |
| 460 | fn nextBsd(self: *Self) !?Entry { | 450 | fn nextBsd(self: *Self) !?Entry { |
| 461 | start_over: while (true) { | 451 | start_over: while (true) { |
| 462 | if (self.index >= self.end_index) { | 452 | if (self.index >= self.end_index) { |
| 463 | while (true) { | 453 | const rc = os.system.getdirentries( |
| 464 | const rc = os.system.getdirentries( | 454 | self.dir.fd, |
| 465 | self.dir.fd, | 455 | self.buf[0..].ptr, |
| 466 | self.buf[0..].ptr, | 456 | self.buf.len, |
| 467 | self.buf.len, | 457 | &self.seek, |
| 468 | &self.seek, | 458 | ); |
| 469 | ); | 459 | switch (os.errno(rc)) { |
| 470 | switch (os.errno(rc)) { | 460 | 0 => {}, |
| 471 | 0 => {}, | 461 | os.EBADF => unreachable, |
| 472 | os.EBADF => unreachable, | 462 | os.EFAULT => unreachable, |
| 473 | os.EFAULT => unreachable, | 463 | os.ENOTDIR => unreachable, |
| 474 | os.ENOTDIR => unreachable, | 464 | os.EINVAL => unreachable, |
| 475 | os.EINVAL => unreachable, | 465 | else => |err| return os.unexpectedErrno(err), |
| 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; | | |
| 482 | } | 466 | } |
| | 467 | if (rc == 0) return null; |
| | 468 | self.index = 0; |
| | 469 | self.end_index = @intCast(usize, rc); |
| 483 | } | 470 | } |
| 484 | const freebsd_entry = @ptrCast(*align(1) os.dirent, &self.buf[self.index]); | 471 | const freebsd_entry = @ptrCast(*align(1) os.dirent, &self.buf[self.index]); |
| 485 | const next_index = self.index + freebsd_entry.d_reclen; | 472 | const next_index = self.index + freebsd_entry.d_reclen; |
| ... | @@ -511,12 +498,10 @@ pub const Dir = struct { | ... | @@ -511,12 +498,10 @@ pub const Dir = struct { |
| 511 | }, | 498 | }, |
| 512 | .linux => struct { | 499 | .linux => struct { |
| 513 | dir: Dir, | 500 | dir: Dir, |
| 514 | buf: [buffer_len]u8, | 501 | buf: [8192]u8, // TODO align(@alignOf(os.dirent64)), |
| 515 | index: usize, | 502 | index: usize, |
| 516 | end_index: usize, | 503 | end_index: usize, |
| 517 | | 504 | |
| 518 | pub const buffer_len = 8192; | | |
| 519 | | | |
| 520 | const Self = @This(); | 505 | const Self = @This(); |
| 521 | | 506 | |
| 522 | /// Memory such as file names referenced in this returned entry becomes invalid | 507 | /// Memory such as file names referenced in this returned entry becomes invalid |
| ... | @@ -524,21 +509,18 @@ pub const Dir = struct { | ... | @@ -524,21 +509,18 @@ pub const Dir = struct { |
| 524 | pub fn next(self: *Self) !?Entry { | 509 | pub fn next(self: *Self) !?Entry { |
| 525 | start_over: while (true) { | 510 | start_over: while (true) { |
| 526 | if (self.index >= self.end_index) { | 511 | if (self.index >= self.end_index) { |
| 527 | while (true) { | 512 | const rc = os.linux.getdents64(self.dir.fd, &self.buf, self.buf.len); |
| 528 | const rc = os.linux.getdents64(self.dir.fd, &self.buf, self.buf.len); | 513 | switch (os.linux.getErrno(rc)) { |
| 529 | switch (os.linux.getErrno(rc)) { | 514 | 0 => {}, |
| 530 | 0 => {}, | 515 | os.EBADF => unreachable, |
| 531 | os.EBADF => unreachable, | 516 | os.EFAULT => unreachable, |
| 532 | os.EFAULT => unreachable, | 517 | os.ENOTDIR => unreachable, |
| 533 | os.ENOTDIR => unreachable, | 518 | os.EINVAL => unreachable, |
| 534 | os.EINVAL => unreachable, | 519 | else => |err| return os.unexpectedErrno(err), |
| 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; | | |
| 541 | } | 520 | } |
| | 521 | if (rc == 0) return null; |
| | 522 | self.index = 0; |
| | 523 | self.end_index = rc; |
| 542 | } | 524 | } |
| 543 | const linux_entry = @ptrCast(*align(1) os.dirent64, &self.buf[self.index]); | 525 | const linux_entry = @ptrCast(*align(1) os.dirent64, &self.buf[self.index]); |
| 544 | const next_index = self.index + linux_entry.d_reclen; | 526 | const next_index = self.index + linux_entry.d_reclen; |
| ... | @@ -570,13 +552,117 @@ pub const Dir = struct { | ... | @@ -570,13 +552,117 @@ pub const Dir = struct { |
| 570 | }, | 552 | }, |
| 571 | .windows => struct { | 553 | .windows => struct { |
| 572 | dir: Dir, | 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 | first: bool, | 558 | first: bool, |
| 575 | name_data: [256]u8, | 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 | else => @compileError("unimplemented"), | 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 | pub const OpenError = error{ | 666 | pub const OpenError = error{ |
| 581 | FileNotFound, | 667 | FileNotFound, |
| 582 | NotDir, | 668 | NotDir, |
| ... | @@ -594,18 +680,15 @@ pub const Dir = struct { | ... | @@ -594,18 +680,15 @@ pub const Dir = struct { |
| 594 | | 680 | |
| 595 | /// Call `close` to free the directory handle. | 681 | /// Call `close` to free the directory handle. |
| 596 | pub fn open(dir_path: []const u8) OpenError!Dir { | 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 | /// Same as `open` except the parameter is null-terminated. | 686 | /// Same as `open` except the parameter is null-terminated. |
| 601 | pub fn openC(dir_path_c: [*]const u8) OpenError!Dir { | 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 | pub fn close(self: *Dir) void { | 691 | pub fn close(self: *Dir) void { |
| 606 | if (os.windows.is_the_target) { | | |
| 607 | @panic("TODO"); | | |
| 608 | } | | |
| 609 | os.close(self.fd); | 692 | os.close(self.fd); |
| 610 | self.* = undefined; | 693 | self.* = undefined; |
| 611 | } | 694 | } |
| ... | @@ -625,14 +708,25 @@ pub const Dir = struct { | ... | @@ -625,14 +708,25 @@ pub const Dir = struct { |
| 625 | | 708 | |
| 626 | /// Call `close` on the result when done. | 709 | /// Call `close` on the result when done. |
| 627 | pub fn openDir(self: Dir, sub_path: []const u8) OpenError!Dir { | 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 | const sub_path_c = try os.toPosixPath(sub_path); | 717 | const sub_path_c = try os.toPosixPath(sub_path); |
| 629 | return self.openDirC(&sub_path_c); | 718 | return self.openDirC(&sub_path_c); |
| 630 | } | 719 | } |
| 631 | | 720 | |
| 632 | /// Call `close` on the result when done. | 721 | /// Same as `openDir` except the parameter is null-terminated. |
| 633 | pub fn openDirC(self: Dir, sub_path: [*]const u8) OpenError!Dir { | 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 | const flags = os.O_RDONLY | os.O_DIRECTORY | os.O_CLOEXEC; | 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 | error.FileTooBig => unreachable, // can't happen for directories | 730 | error.FileTooBig => unreachable, // can't happen for directories |
| 637 | error.IsDir => unreachable, // we're providing O_DIRECTORY | 731 | error.IsDir => unreachable, // we're providing O_DIRECTORY |
| 638 | error.NoSpaceLeft => unreachable, // not providing O_CREAT | 732 | error.NoSpaceLeft => unreachable, // not providing O_CREAT |
| ... | @@ -642,6 +736,79 @@ pub const Dir = struct { | ... | @@ -642,6 +736,79 @@ pub const Dir = struct { |
| 642 | return Dir{ .fd = fd }; | 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 | pub const DeleteFileError = os.UnlinkError; | 812 | pub const DeleteFileError = os.UnlinkError; |
| 646 | | 813 | |
| 647 | /// Delete a file name and possibly the file it refers to, based on an open directory handle. | 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,6 +844,10 @@ pub const Dir = struct { |
| 677 | /// Returns `error.DirNotEmpty` if the directory is not empty. | 844 | /// Returns `error.DirNotEmpty` if the directory is not empty. |
| 678 | /// To delete a directory recursively, see `deleteTree`. | 845 | /// To delete a directory recursively, see `deleteTree`. |
| 679 | pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void { | 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 | const sub_path_c = try os.toPosixPath(sub_path); | 851 | const sub_path_c = try os.toPosixPath(sub_path); |
| 681 | return self.deleteDirC(&sub_path_c); | 852 | return self.deleteDirC(&sub_path_c); |
| 682 | } | 853 | } |
| ... | @@ -689,24 +860,25 @@ pub const Dir = struct { | ... | @@ -689,24 +860,25 @@ pub const Dir = struct { |
| 689 | }; | 860 | }; |
| 690 | } | 861 | } |
| 691 | | 862 | |
| 692 | pub fn iterate(self: Dir) Iterator { | 863 | /// Same as `deleteDir` except the parameter is UTF16LE, NT prefixed. |
| 693 | switch (builtin.os) { | 864 | /// This function is Windows-only. |
| 694 | .macosx, .ios, .freebsd, .netbsd => return Iterator{ | 865 | pub fn deleteDirW(self: Dir, sub_path_w: [*]const u16) DeleteDirError!void { |
| 695 | .dir = self, | 866 | os.unlinkatW(self.fd, sub_path_w, os.AT_REMOVEDIR) catch |err| switch (err) { |
| 696 | .seek = 0, | 867 | error.IsDir => unreachable, // not possible since we pass AT_REMOVEDIR |
| 697 | .index = 0, | 868 | else => |e| return e, |
| 698 | .end_index = 0, | 869 | }; |
| 699 | .buf = undefined, | 870 | } |
| 700 | }, | 871 | |
| 701 | .linux => return Iterator{ | 872 | /// Read value of a symbolic link. |
| 702 | .dir = self, | 873 | /// The return value is a slice of `buffer`, from index `0`. |
| 703 | .index = 0, | 874 | pub fn readLink(self: Dir, sub_path: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { |
| 704 | .end_index = 0, | 875 | const sub_path_c = try os.toPosixPath(sub_path); |
| 705 | .buf = undefined, | 876 | return self.readLinkC(&sub_path_c, buffer); |
| 706 | }, | 877 | } |
| 707 | .windows => @panic("TODO"), | 878 | |
| 708 | else => @compileError("unimplemented"), | 879 | /// Same as `readLink`, except the `pathname` parameter is null-terminated. |
| 709 | } | 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 | pub const DeleteTreeError = error{ | 884 | pub const DeleteTreeError = error{ |
| ... | @@ -953,7 +1125,6 @@ pub const Walker = struct { | ... | @@ -953,7 +1125,6 @@ pub const Walker = struct { |
| 953 | /// Must call `Walker.deinit` when done. | 1125 | /// Must call `Walker.deinit` when done. |
| 954 | /// `dir_path` must not end in a path separator. | 1126 | /// `dir_path` must not end in a path separator. |
| 955 | /// The order of returned file system entries is undefined. | 1127 | /// The order of returned file system entries is undefined. |
| 956 | /// TODO: https://github.com/ziglang/zig/issues/2888 | | |
| 957 | pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { | 1128 | pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { |
| 958 | assert(!mem.endsWith(u8, dir_path, path.sep_str)); | 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,15 +1149,13 @@ pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { |
| 978 | | 1149 | |
| 979 | /// Read value of a symbolic link. | 1150 | /// Read value of a symbolic link. |
| 980 | /// The return value is a slice of buffer, from index `0`. | 1151 | /// The return value is a slice of buffer, from index `0`. |
| 981 | /// TODO https://github.com/ziglang/zig/issues/2888 | 1152 | pub fn readLink(pathname: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { |
| 982 | pub fn readLink(pathname: []const u8, buffer: *[os.PATH_MAX]u8) ![]u8 { | | |
| 983 | return os.readlink(pathname, buffer); | 1153 | return os.readlink(pathname, buffer); |
| 984 | } | 1154 | } |
| 985 | | 1155 | |
| 986 | /// Same as `readLink`, except the `pathname` parameter is null-terminated. | 1156 | /// Same as `readLink`, except the parameter is null-terminated. |
| 987 | /// TODO https://github.com/ziglang/zig/issues/2888 | 1157 | pub fn readLinkC(pathname_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { |
| 988 | pub fn readLinkC(pathname: [*]const u8, buffer: *[os.PATH_MAX]u8) ![]u8 { | 1158 | return os.readlinkC(pathname_c, buffer); |
| 989 | return os.readlinkC(pathname, buffer); | | |
| 990 | } | 1159 | } |
| 991 | | 1160 | |
| 992 | pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfExePathError; | 1161 | pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfExePathError; |