Skip to content

Commit a6a8f30

Browse files
committed
Add checks for incorrect usage of File handles
1 parent de9119e commit a6a8f30

File tree

3 files changed

+43
-29
lines changed

3 files changed

+43
-29
lines changed

std/fs/file.zig

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const maxInt = std.math.maxInt;
1212
pub const File = struct {
1313
/// The OS-specific file descriptor or file handle.
1414
handle: os.fd_t,
15+
openMode: OpenMode,
1516

1617
pub const Mode = switch (builtin.os) {
1718
Os.windows => void,
@@ -25,34 +26,41 @@ pub const File = struct {
2526

2627
pub const OpenError = windows.CreateFileError || os.OpenError;
2728

29+
const OpenMode = packed struct {
30+
read: bool,
31+
write: bool,
32+
clobber: bool,
33+
_:u5//Pad out to a full byte
34+
};
2835

2936
pub const READ = 1;
3037
pub const WRITE = 2;
3138
pub const CLOBBER = 4;
3239

33-
pub fn openW(path: [*]const u16, comptime flags: u32) OpenError!File{
40+
pub fn openW(path: [*]const u16, comptime flags: u8) OpenError!File{
3441
assert(windows.is_the_target);
3542

43+
const openMode: OpenMode = @bitCast(OpenMode, flags);
3644
comptime var desiredAccess: u32 = 0;
3745
comptime var creationDisposition: u32 = windows.OPEN_EXISTING;
3846

3947
comptime {
40-
if((flags & CLOBBER) > 0 and !((flags & WRITE) > 0)) {
41-
@compileError("Cannot clobber a read only file! Did you forget to add '| WRITE'?");
48+
if(openMode.clobber and !openMode.write) {
49+
@compileError("Cannot clobber a read only file! Did you forget to add '| File.WRITE'?");
4250
}
4351

44-
if(flags & READ > 0) {
52+
if(openMode.read) {
4553
desiredAccess |= windows.GENERIC_READ;
4654
}
47-
if(flags & WRITE > 0) {
55+
if(openMode.write) {
4856
desiredAccess |= windows.GENERIC_WRITE;
4957
}
5058

51-
if(flags & CLOBBER > 0) {
59+
if(openMode.clobber) {
5260
creationDisposition = windows.CREATE_ALWAYS;
5361
}
5462

55-
if(flags & WRITE > 0) {
63+
if(openMode.write) {
5664
creationDisposition = windows.OPEN_ALWAYS;
5765
}
5866
}
@@ -67,51 +75,49 @@ pub const File = struct {
6775
null
6876
);
6977

70-
return openHandle(handle);
78+
return openHandle(handle, flags);
7179
}
7280

73-
pub fn openC(path: []const u8, comptime flags: u32) OpenError!File {
81+
pub fn openC(path: []const u8, comptime flags: u8) OpenError!File {
7482
if (windows.is_the_target) {
7583
const path_w = try windows.cStrToPrefixedFileW(path);
7684
return openW(&path_w, flags);
7785
}
7886

87+
const openMode = @bitCast(flags, OpenMode);
7988
comptime var posixFlags: u32 = O_LARGEFILE;
8089

8190
comptime {
82-
if((flags & CLOBBER) > 0 and !((flags & WRITE) > 0)) {
83-
@compileError("Cannot clobber a read only file! Did you forget to add '| WRITE'?");
91+
if(openMode.clobber and !openMode.write) {
92+
@compileError("Cannot clobber a read only file! Did you forget to add '| File.WRITE'?");
8493
}
8594

86-
if(flags & READ > 0) {
87-
if(flags & WRITE > 0) {
95+
if(openMode.read) {
96+
if(openMode.write) {
8897
posixFlags |= O_RDWR;
8998
}
9099
else {
91100
posixFlags |= O_RDONLY;
92101
}
93102
}
94-
else if (flags & WRITE > 0) {
103+
else if (openMode.write) {
95104
posixFlags |= O_WRONLY;
96105
}
97-
else {
98-
assert(true);
99-
}
100106

101-
if(flags & WRITE > 0) {
107+
if(openMode.write) {
102108
posixFlags |= O_CREAT;
103109
}
104110

105-
if(flags & CLOBBER > 0) {
111+
if(openMode.clobber) {
106112
posixFlags |= O_TRUNC;
107113
}
108114
}
109115

110116
const fd = try os.openC(path, posixFlags, 0);
111-
return openHandle(fd);
117+
return openHandle(fd, flags);
112118
}
113119

114-
pub fn open(path: []const u8, comptime flags: u32) OpenError!File {
120+
pub fn open(path: []const u8, comptime flags: u8) OpenError!File {
115121
if (windows.is_the_target) {
116122
const path_w = try windows.sliceToPrefixedFileW(path);
117123
return openW(&path_w, flags);
@@ -120,8 +126,8 @@ pub const File = struct {
120126
return openC(&path_c, flags);
121127
}
122128

123-
pub fn openHandle(handle: os.fd_t) File {
124-
return File{ .handle = handle };
129+
pub fn openHandle(handle: os.fd_t, flags: u8) File {
130+
return File{ .handle = handle, .openMode = @bitCast(OpenMode, flags)};
125131
}
126132

127133
/// Test for the existence of `path`.
@@ -276,12 +282,18 @@ pub const File = struct {
276282
pub const ReadError = os.ReadError;
277283

278284
pub fn read(self: File, buffer: []u8) ReadError!usize {
285+
if(!self.openMode.read) {
286+
return ReadError.IncorrectOpenMode;
287+
}
279288
return os.read(self.handle, buffer);
280289
}
281290

282291
pub const WriteError = os.WriteError;
283292

284293
pub fn write(self: File, bytes: []const u8) WriteError!void {
294+
if(!self.openMode.write) {
295+
return WriteError.IncorrectOpenMode;
296+
}
285297
return os.write(self.handle, bytes);
286298
}
287299

std/io.zig

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,25 +20,25 @@ pub const GetStdIoError = os.windows.GetStdHandleError;
2020
pub fn getStdOut() GetStdIoError!File {
2121
if (os.windows.is_the_target) {
2222
const handle = try os.windows.GetStdHandle(os.windows.STD_OUTPUT_HANDLE);
23-
return File.openHandle(handle);
23+
return File.openHandle(handle, File.WRITE);
2424
}
25-
return File.openHandle(os.STDOUT_FILENO);
25+
return File.openHandle(os.STDOUT_FILENO, File.WRITE);
2626
}
2727

2828
pub fn getStdErr() GetStdIoError!File {
2929
if (os.windows.is_the_target) {
3030
const handle = try os.windows.GetStdHandle(os.windows.STD_ERROR_HANDLE);
31-
return File.openHandle(handle);
31+
return File.openHandle(handle, File.WRITE);
3232
}
33-
return File.openHandle(os.STDERR_FILENO);
33+
return File.openHandle(os.STDERR_FILENO, File.WRITE);
3434
}
3535

3636
pub fn getStdIn() GetStdIoError!File {
3737
if (os.windows.is_the_target) {
3838
const handle = try os.windows.GetStdHandle(os.windows.STD_INPUT_HANDLE);
39-
return File.openHandle(handle);
39+
return File.openHandle(handle, File.READ);
4040
}
41-
return File.openHandle(os.STDIN_FILENO);
41+
return File.openHandle(os.STDIN_FILENO, File.READ);
4242
}
4343

4444
pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;

std/os.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ pub const ReadError = error{
256256
OperationAborted,
257257
BrokenPipe,
258258
Unexpected,
259+
IncorrectOpenMode
259260
};
260261

261262
/// Returns the number of bytes that were read, which can be less than
@@ -384,6 +385,7 @@ pub const WriteError = error{
384385
SystemResources,
385386
OperationAborted,
386387
Unexpected,
388+
IncorrectOpenMode,
387389
};
388390

389391
/// Write to a file descriptor. Keeps trying if it gets interrupted.

0 commit comments

Comments
 (0)