| author | |
| committer | |
| log | e6334fe46d29f3f9d488b80453cc5bd12ffb97ea |
| tree | 58dd5a7bd39dffaaa80a21379054d7354ffb6066 |
| parent | 055b856f13ce527a92b2b28760daabce41edd440 |
See #3023 files changed, 82 insertions(+), 10 deletions(-)
std/io.zig+32-8| ... | @@ -242,9 +242,15 @@ pub const InStream = struct { | ... | @@ -242,9 +242,15 @@ pub const InStream = struct { |
| 242 | .handle = {}, | 242 | .handle = {}, |
| 243 | }; | 243 | }; |
| 244 | } else if (is_windows) { | 244 | } else if (is_windows) { |
| 245 | @compileError("TODO windows InStream.open"); | 245 | const handle = %return os.windowsOpen(path, system.GENERIC_READ, system.FILE_SHARE_READ, |
| 246 | system.OPEN_EXISTING, system.FILE_ATTRIBUTE_NORMAL, allocator); | ||
| 247 | return InStream { | ||
| 248 | .fd = {}, | ||
| 249 | .handle_id = undefined, | ||
| 250 | .handle = handle, | ||
| 251 | }; | ||
| 246 | } else { | 252 | } else { |
| 247 | @compileError("Unsupported OS"); | 253 | unreachable; |
| 248 | } | 254 | } |
| 249 | } | 255 | } |
| 250 | 256 | ||
| ... | @@ -253,18 +259,20 @@ pub const InStream = struct { | ... | @@ -253,18 +259,20 @@ pub const InStream = struct { |
| 253 | pub fn close(self: &InStream) { | 259 | pub fn close(self: &InStream) { |
| 254 | if (is_posix) { | 260 | if (is_posix) { |
| 255 | os.posixClose(self.fd); | 261 | os.posixClose(self.fd); |
| 262 | } else if (is_windows) { | ||
| 263 | os.windowsClose(%%self.getHandle()); | ||
| 256 | } else { | 264 | } else { |
| 257 | @compileError("Unsupported OS"); | 265 | unreachable; |
| 258 | } | 266 | } |
| 259 | } | 267 | } |
| 260 | 268 | ||
| 261 | /// Returns the number of bytes read. If the number read is smaller than buf.len, then | 269 | /// Returns the number of bytes read. If the number read is smaller than buf.len, then |
| 262 | /// the stream reached End Of File. | 270 | /// the stream reached End Of File. |
| 263 | pub fn read(is: &InStream, buf: []u8) -> %usize { | 271 | pub fn read(self: &InStream, buf: []u8) -> %usize { |
| 264 | if (is_posix) { | 272 | if (is_posix) { |
| 265 | var index: usize = 0; | 273 | var index: usize = 0; |
| 266 | while (index < buf.len) { | 274 | while (index < buf.len) { |
| 267 | const amt_read = system.read(is.fd, &buf[index], buf.len - index); | 275 | const amt_read = system.read(self.fd, &buf[index], buf.len - index); |
| 268 | const read_err = system.getErrno(amt_read); | 276 | const read_err = system.getErrno(amt_read); |
| 269 | if (read_err > 0) { | 277 | if (read_err > 0) { |
| 270 | switch (read_err) { | 278 | switch (read_err) { |
| ... | @@ -273,7 +281,7 @@ pub const InStream = struct { | ... | @@ -273,7 +281,7 @@ pub const InStream = struct { |
| 273 | system.EFAULT => unreachable, | 281 | system.EFAULT => unreachable, |
| 274 | system.EBADF => return error.BadFd, | 282 | system.EBADF => return error.BadFd, |
| 275 | system.EIO => return error.Io, | 283 | system.EIO => return error.Io, |
| 276 | else => return error.Unexpected, | 284 | else => return error.Unexpected, |
| 277 | } | 285 | } |
| 278 | } | 286 | } |
| 279 | if (amt_read == 0) return index; | 287 | if (amt_read == 0) return index; |
| ... | @@ -281,9 +289,25 @@ pub const InStream = struct { | ... | @@ -281,9 +289,25 @@ pub const InStream = struct { |
| 281 | } | 289 | } |
| 282 | return index; | 290 | return index; |
| 283 | } else if (is_windows) { | 291 | } else if (is_windows) { |
| 284 | @compileError("TODO windows read impl"); | 292 | const handle = %return self.getHandle(); |
| 293 | var index: usize = 0; | ||
| 294 | while (index < buf.len) { | ||
| 295 | const want_read_count = system.DWORD(math.min(system.DWORD(@maxValue(system.DWORD)), buf.len - index)); | ||
| 296 | var amt_read: system.DWORD = undefined; | ||
| 297 | if (!system.ReadFile(handle, @ptrCast(&c_void, &buf[index]), want_read_count, &amt_read, null)) { | ||
| 298 | const err = system.GetLastError(); | ||
| 299 | return switch (err) { | ||
| 300 | system.ERROR.OPERATION_ABORTED => continue, | ||
| 301 | system.ERROR.BROKEN_PIPE => error.PipeFail, | ||
| 302 | else => error.Unexpected, | ||
| 303 | }; | ||
| 304 | } | ||
| 305 | if (amt_read == 0) return index; | ||
| 306 | index += amt_read; | ||
| 307 | } | ||
| 308 | return index; | ||
| 285 | } else { | 309 | } else { |
| 286 | @compileError("Unsupported OS"); | 310 | unreachable; |
| 287 | } | 311 | } |
| 288 | } | 312 | } |
| 289 | 313 |
std/os/index.zig+50| ... | @@ -151,6 +151,10 @@ pub fn posixClose(fd: i32) { | ... | @@ -151,6 +151,10 @@ pub fn posixClose(fd: i32) { |
| 151 | } | 151 | } |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | pub fn windowsClose(handle: windows.HANDLE) { | ||
| 155 | assert(windows.CloseHandle(handle)); | ||
| 156 | } | ||
| 157 | |||
| 154 | /// Calls POSIX read, and keeps trying if it gets interrupted. | 158 | /// Calls POSIX read, and keeps trying if it gets interrupted. |
| 155 | pub fn posixRead(fd: i32, buf: []u8) -> %void { | 159 | pub fn posixRead(fd: i32, buf: []u8) -> %void { |
| 156 | var index: usize = 0; | 160 | var index: usize = 0; |
| ... | @@ -299,6 +303,7 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al | ... | @@ -299,6 +303,7 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al |
| 299 | posix.ENOSPC => error.NoSpaceLeft, | 303 | posix.ENOSPC => error.NoSpaceLeft, |
| 300 | posix.ENOTDIR => error.NotDir, | 304 | posix.ENOTDIR => error.NotDir, |
| 301 | posix.EPERM => error.AccessDenied, | 305 | posix.EPERM => error.AccessDenied, |
| 306 | posix.EEXIST => error.PathAlreadyExists, | ||
| 302 | else => error.Unexpected, | 307 | else => error.Unexpected, |
| 303 | } | 308 | } |
| 304 | } | 309 | } |
| ... | @@ -306,6 +311,51 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al | ... | @@ -306,6 +311,51 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al |
| 306 | } | 311 | } |
| 307 | } | 312 | } |
| 308 | 313 | ||
| 314 | |||
| 315 | error SharingViolation; | ||
| 316 | error PipeBusy; | ||
| 317 | |||
| 318 | /// `file_path` may need to be copied in memory to add a null terminating byte. In this case | ||
| 319 | /// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed | ||
| 320 | /// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned. | ||
| 321 | /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory. | ||
| 322 | pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_mode: windows.DWORD, | ||
| 323 | creation_disposition: windows.DWORD, flags_and_attrs: windows.DWORD, allocator: ?&Allocator) -> %windows.HANDLE | ||
| 324 | { | ||
| 325 | var stack_buf: [max_noalloc_path_len]u8 = undefined; | ||
| 326 | var path0: []u8 = undefined; | ||
| 327 | var need_free = false; | ||
| 328 | defer if (need_free) (??allocator).free(path0); | ||
| 329 | |||
| 330 | if (file_path.len < stack_buf.len) { | ||
| 331 | path0 = stack_buf[0..file_path.len + 1]; | ||
| 332 | } else if (allocator) |a| { | ||
| 333 | path0 = %return a.alloc(u8, file_path.len + 1); | ||
| 334 | need_free = true; | ||
| 335 | } else { | ||
| 336 | return error.NameTooLong; | ||
| 337 | } | ||
| 338 | mem.copy(u8, path0, file_path); | ||
| 339 | path0[file_path.len] = 0; | ||
| 340 | |||
| 341 | const result = windows.CreateFileA(path0.ptr, desired_access, share_mode, null, creation_disposition, | ||
| 342 | flags_and_attrs, null); | ||
| 343 | |||
| 344 | if (result == windows.INVALID_HANDLE_VALUE) { | ||
| 345 | const err = windows.GetLastError(); | ||
| 346 | return switch (err) { | ||
| 347 | windows.ERROR.SHARING_VIOLATION => error.SharingViolation, | ||
| 348 | windows.ERROR.ALREADY_EXISTS, windows.ERROR.FILE_EXISTS => error.PathAlreadyExists, | ||
| 349 | windows.ERROR.FILE_NOT_FOUND => error.FileNotFound, | ||
| 350 | windows.ERROR.ACCESS_DENIED => error.AccessDenied, | ||
| 351 | windows.ERROR.PIPE_BUSY => error.PipeBusy, | ||
| 352 | else => error.Unexpected, | ||
| 353 | }; | ||
| 354 | } | ||
| 355 | |||
| 356 | return result; | ||
| 357 | } | ||
| 358 | |||
| 309 | pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void { | 359 | pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void { |
| 310 | while (true) { | 360 | while (true) { |
| 311 | const err = posix.getErrno(posix.dup2(old_fd, new_fd)); | 361 | const err = posix.getErrno(posix.dup2(old_fd, new_fd)); |
std/os/windows/index.zig-2| ... | @@ -38,8 +38,6 @@ pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(hFile: HANDLE, lpsz | ... | @@ -38,8 +38,6 @@ pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(hFile: HANDLE, lpsz |
| 38 | /// Retrieves a handle to the specified standard device (standard input, standard output, or standard error). | 38 | /// Retrieves a handle to the specified standard device (standard input, standard output, or standard error). |
| 39 | pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) -> ?HANDLE; | 39 | pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) -> ?HANDLE; |
| 40 | 40 | ||
| 41 | /// Reads data from the specified file or input/output (I/O) device. Reads occur at the position specified by the file pointer if supported by the device. | ||
| 42 | /// This function is designed for both synchronous and asynchronous operations. For a similar function designed solely for asynchronous operation, see ReadFileEx. | ||
| 43 | pub extern "kernel32" stdcallcc fn ReadFile(in_hFile: HANDLE, out_lpBuffer: LPVOID, | 41 | pub extern "kernel32" stdcallcc fn ReadFile(in_hFile: HANDLE, out_lpBuffer: LPVOID, |
| 44 | in_nNumberOfBytesToRead: DWORD, out_lpNumberOfBytesRead: &DWORD, | 42 | in_nNumberOfBytesToRead: DWORD, out_lpNumberOfBytesRead: &DWORD, |
| 45 | in_out_lpOverlapped: ?&OVERLAPPED) -> BOOL; | 43 | in_out_lpOverlapped: ?&OVERLAPPED) -> BOOL; |