Skip to content

Commit d36bc79

Browse files
committed
std.Io.Threaded: implement fileStat for Windows
1 parent 22de9fd commit d36bc79

File tree

2 files changed

+62
-66
lines changed

2 files changed

+62
-66
lines changed

lib/std/Io/Threaded.zig

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,7 +1033,7 @@ fn dirMakePathPosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mo
10331033
_ = dir;
10341034
_ = sub_path;
10351035
_ = mode;
1036-
@panic("TODO");
1036+
@panic("TODO implement dirMakePathPosix");
10371037
}
10381038

10391039
fn dirMakePathWindows(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {
@@ -1042,7 +1042,7 @@ fn dirMakePathWindows(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8,
10421042
_ = dir;
10431043
_ = sub_path;
10441044
_ = mode;
1045-
@panic("TODO");
1045+
@panic("TODO implement dirMakePathWindows");
10461046
}
10471047

10481048
fn dirMakeOpenPathPosix(
@@ -1176,15 +1176,15 @@ fn dirMakeOpenPathWasi(
11761176
_ = dir;
11771177
_ = sub_path;
11781178
_ = mode;
1179-
@panic("TODO");
1179+
@panic("TODO implement dirMakeOpenPathWindows");
11801180
}
11811181

11821182
fn dirStat(userdata: ?*anyopaque, dir: Io.Dir) Io.Dir.StatError!Io.Dir.Stat {
11831183
const t: *Threaded = @ptrCast(@alignCast(userdata));
11841184
try t.checkCancel();
11851185

11861186
_ = dir;
1187-
@panic("TODO");
1187+
@panic("TODO implement dirStat");
11881188
}
11891189

11901190
fn dirStatPathLinux(
@@ -1375,8 +1375,48 @@ fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File
13751375
fn fileStatWindows(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
13761376
const t: *Threaded = @ptrCast(@alignCast(userdata));
13771377
try t.checkCancel();
1378-
_ = file;
1379-
@panic("TODO");
1378+
1379+
var io_status_block: windows.IO_STATUS_BLOCK = undefined;
1380+
var info: windows.FILE_ALL_INFORMATION = undefined;
1381+
const rc = windows.ntdll.NtQueryInformationFile(file.handle, &io_status_block, &info, @sizeOf(windows.FILE_ALL_INFORMATION), .FileAllInformation);
1382+
switch (rc) {
1383+
.SUCCESS => {},
1384+
// Buffer overflow here indicates that there is more information available than was able to be stored in the buffer
1385+
// size provided. This is treated as success because the type of variable-length information that this would be relevant for
1386+
// (name, volume name, etc) we don't care about.
1387+
.BUFFER_OVERFLOW => {},
1388+
.INVALID_PARAMETER => unreachable,
1389+
.ACCESS_DENIED => return error.AccessDenied,
1390+
else => return windows.unexpectedStatus(rc),
1391+
}
1392+
return .{
1393+
.inode = info.InternalInformation.IndexNumber,
1394+
.size = @as(u64, @bitCast(info.StandardInformation.EndOfFile)),
1395+
.mode = 0,
1396+
.kind = if (info.BasicInformation.FileAttributes & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) reparse_point: {
1397+
var tag_info: windows.FILE_ATTRIBUTE_TAG_INFO = undefined;
1398+
const tag_rc = windows.ntdll.NtQueryInformationFile(file.handle, &io_status_block, &tag_info, @sizeOf(windows.FILE_ATTRIBUTE_TAG_INFO), .FileAttributeTagInformation);
1399+
switch (tag_rc) {
1400+
.SUCCESS => {},
1401+
// INFO_LENGTH_MISMATCH and ACCESS_DENIED are the only documented possible errors
1402+
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/d295752f-ce89-4b98-8553-266d37c84f0e
1403+
.INFO_LENGTH_MISMATCH => unreachable,
1404+
.ACCESS_DENIED => return error.AccessDenied,
1405+
else => return windows.unexpectedStatus(rc),
1406+
}
1407+
if (tag_info.ReparseTag & windows.reparse_tag_name_surrogate_bit != 0) {
1408+
break :reparse_point .sym_link;
1409+
}
1410+
// Unknown reparse point
1411+
break :reparse_point .unknown;
1412+
} else if (info.BasicInformation.FileAttributes & windows.FILE_ATTRIBUTE_DIRECTORY != 0)
1413+
.directory
1414+
else
1415+
.file,
1416+
.atime = windows.fromSysTime(info.BasicInformation.LastAccessTime),
1417+
.mtime = windows.fromSysTime(info.BasicInformation.LastWriteTime),
1418+
.ctime = windows.fromSysTime(info.BasicInformation.ChangeTime),
1419+
};
13801420
}
13811421

13821422
fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
@@ -2490,7 +2530,7 @@ fn fileSeekBy(userdata: ?*anyopaque, file: Io.File, offset: i64) Io.File.SeekErr
24902530

24912531
_ = file;
24922532
_ = offset;
2493-
@panic("TODO");
2533+
@panic("TODO implement fileSeekBy");
24942534
}
24952535

24962536
fn fileSeekTo(userdata: ?*anyopaque, file: Io.File, offset: u64) Io.File.SeekError!void {
@@ -2571,7 +2611,7 @@ fn openSelfExe(userdata: ?*anyopaque, flags: Io.File.OpenFlags) Io.File.OpenSelf
25712611

25722612
return dirOpenFileWindowsInner(t, .{ .handle = cwd_handle }, image_path_name, flags);
25732613
}
2574-
@panic("TODO");
2614+
@panic("TODO implement openSelfExe");
25752615
}
25762616

25772617
fn fileWritePositional(
@@ -2586,7 +2626,7 @@ fn fileWritePositional(
25862626
_ = file;
25872627
_ = buffer;
25882628
_ = offset;
2589-
@panic("TODO");
2629+
@panic("TODO implement fileWritePositional");
25902630
}
25912631
}
25922632

@@ -2596,7 +2636,7 @@ fn fileWriteStreaming(userdata: ?*anyopaque, file: Io.File, buffer: [][]const u8
25962636
try t.checkCancel();
25972637
_ = file;
25982638
_ = buffer;
2599-
@panic("TODO");
2639+
@panic("TODO implement fileWriteStreaming");
26002640
}
26012641
}
26022642

@@ -2922,7 +2962,7 @@ fn netListenUnixWindows(
29222962
try t.checkCancel();
29232963
_ = address;
29242964
_ = options;
2925-
@panic("TODO");
2965+
@panic("TODO implement netListenUnixWindows");
29262966
}
29272967

29282968
fn posixBindUnix(t: *Threaded, fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {
@@ -3122,7 +3162,7 @@ fn netConnectIpPosix(
31223162
options: IpAddress.ConnectOptions,
31233163
) IpAddress.ConnectError!net.Stream {
31243164
if (!have_networking) return error.NetworkDown;
3125-
if (options.timeout != .none) @panic("TODO");
3165+
if (options.timeout != .none) @panic("TODO implement netConnectIpPosix with timeout");
31263166
const t: *Threaded = @ptrCast(@alignCast(userdata));
31273167
const family = posixAddressFamily(address);
31283168
const socket_fd = try openSocketPosix(t, family, .{
@@ -3146,7 +3186,7 @@ fn netConnectIpWindows(
31463186
options: IpAddress.ConnectOptions,
31473187
) IpAddress.ConnectError!net.Stream {
31483188
if (!have_networking) return error.NetworkDown;
3149-
if (options.timeout != .none) @panic("TODO");
3189+
if (options.timeout != .none) @panic("TODO implement netConnectIpWindows with timeout");
31503190
const t: *Threaded = @ptrCast(@alignCast(userdata));
31513191
const family = posixAddressFamily(address);
31523192
const socket_handle = try openSocketWsa(t, family, .{
@@ -3220,7 +3260,7 @@ fn netConnectUnixWindows(
32203260
const t: *Threaded = @ptrCast(@alignCast(userdata));
32213261
try t.checkCancel();
32223262
_ = address;
3223-
@panic("TODO");
3263+
@panic("TODO implement netConnectUnixWindows");
32243264
}
32253265

32263266
fn netBindIpPosix(
@@ -3525,7 +3565,7 @@ fn netReadWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, data: [][]u8
35253565
_ = t;
35263566
_ = handle;
35273567
_ = data;
3528-
@panic("TODO");
3568+
@panic("TODO implement netReadWindows");
35293569
}
35303570

35313571
fn netSendPosix(
@@ -3569,7 +3609,7 @@ fn netSendWindows(
35693609
_ = handle;
35703610
_ = messages;
35713611
_ = flags;
3572-
@panic("TODO");
3612+
@panic("TODO netSendWindows");
35733613
}
35743614

35753615
fn netSendOne(
@@ -3872,7 +3912,7 @@ fn netReceiveWindows(
38723912
_ = data_buffer;
38733913
_ = flags;
38743914
_ = timeout;
3875-
@panic("TODO");
3915+
@panic("TODO implement netReceiveWindows");
38763916
}
38773917

38783918
fn netWritePosix(
@@ -3970,7 +4010,7 @@ fn netWriteWindows(
39704010
_ = header;
39714011
_ = data;
39724012
_ = splat;
3973-
@panic("TODO");
4013+
@panic("TODO implement netWriteWindows");
39744014
}
39754015

39764016
fn addBuf(v: []posix.iovec_const, i: *@FieldType(posix.msghdr_const, "iovlen"), bytes: []const u8) void {
@@ -4036,7 +4076,7 @@ fn netInterfaceNameResolve(
40364076

40374077
if (native_os == .windows) {
40384078
try t.checkCancel();
4039-
@panic("TODO");
4079+
@panic("TODO implement netInterfaceNameResolve for Windows");
40404080
}
40414081

40424082
if (builtin.link_libc) {
@@ -4055,15 +4095,15 @@ fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interfa
40554095

40564096
if (native_os == .linux) {
40574097
_ = interface;
4058-
@panic("TODO");
4098+
@panic("TODO implement netInterfaceName for linux");
40594099
}
40604100

40614101
if (native_os == .windows) {
4062-
@panic("TODO");
4102+
@panic("TODO implement netInterfaceName for windows");
40634103
}
40644104

40654105
if (builtin.link_libc) {
4066-
@panic("TODO");
4106+
@panic("TODO implement netInterfaceName for libc");
40674107
}
40684108

40694109
@panic("unimplemented");

lib/std/fs/File.zig

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -312,50 +312,6 @@ pub const StatError = posix.FStatError;
312312

313313
/// Returns `Stat` containing basic information about the `File`.
314314
pub fn stat(self: File) StatError!Stat {
315-
if (builtin.os.tag == .windows) {
316-
var io_status_block: windows.IO_STATUS_BLOCK = undefined;
317-
var info: windows.FILE_ALL_INFORMATION = undefined;
318-
const rc = windows.ntdll.NtQueryInformationFile(self.handle, &io_status_block, &info, @sizeOf(windows.FILE_ALL_INFORMATION), .FileAllInformation);
319-
switch (rc) {
320-
.SUCCESS => {},
321-
// Buffer overflow here indicates that there is more information available than was able to be stored in the buffer
322-
// size provided. This is treated as success because the type of variable-length information that this would be relevant for
323-
// (name, volume name, etc) we don't care about.
324-
.BUFFER_OVERFLOW => {},
325-
.INVALID_PARAMETER => unreachable,
326-
.ACCESS_DENIED => return error.AccessDenied,
327-
else => return windows.unexpectedStatus(rc),
328-
}
329-
return .{
330-
.inode = info.InternalInformation.IndexNumber,
331-
.size = @as(u64, @bitCast(info.StandardInformation.EndOfFile)),
332-
.mode = 0,
333-
.kind = if (info.BasicInformation.FileAttributes & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) reparse_point: {
334-
var tag_info: windows.FILE_ATTRIBUTE_TAG_INFO = undefined;
335-
const tag_rc = windows.ntdll.NtQueryInformationFile(self.handle, &io_status_block, &tag_info, @sizeOf(windows.FILE_ATTRIBUTE_TAG_INFO), .FileAttributeTagInformation);
336-
switch (tag_rc) {
337-
.SUCCESS => {},
338-
// INFO_LENGTH_MISMATCH and ACCESS_DENIED are the only documented possible errors
339-
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/d295752f-ce89-4b98-8553-266d37c84f0e
340-
.INFO_LENGTH_MISMATCH => unreachable,
341-
.ACCESS_DENIED => return error.AccessDenied,
342-
else => return windows.unexpectedStatus(rc),
343-
}
344-
if (tag_info.ReparseTag & windows.reparse_tag_name_surrogate_bit != 0) {
345-
break :reparse_point .sym_link;
346-
}
347-
// Unknown reparse point
348-
break :reparse_point .unknown;
349-
} else if (info.BasicInformation.FileAttributes & windows.FILE_ATTRIBUTE_DIRECTORY != 0)
350-
.directory
351-
else
352-
.file,
353-
.atime = windows.fromSysTime(info.BasicInformation.LastAccessTime),
354-
.mtime = windows.fromSysTime(info.BasicInformation.LastWriteTime),
355-
.ctime = windows.fromSysTime(info.BasicInformation.ChangeTime),
356-
};
357-
}
358-
359315
var threaded: Io.Threaded = .init_single_threaded;
360316
const io = threaded.io();
361317
return Io.File.stat(.{ .handle = self.handle }, io);

0 commit comments

Comments
 (0)