authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-08-31 20:23:47-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-08-31 20:23:47-07:00
log320e26590a31351301992dc7067eb287e4f565f4
treef42869f9dc94e00f01d4adaa81eb974a2d15db08
parent289bfa890b758cdc408b33f4dd601410bebd0a9b

fix std io input to work for non seekable fds


5 files changed, 149 insertions(+), 72 deletions(-)

example/guess_number/main.zig+4-2
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const io = std.io;2const io = std.io;
3const Rand = std.Rand;3const Rand = std.rand.Rand;
4const os = std.os;4const os = std.os;
55
6pub fn main(args: [][]u8) -> %void {6pub fn main(args: [][]u8) -> %void {
...@@ -18,7 +18,9 @@ pub fn main(args: [][]u8) -> %void {...@@ -18,7 +18,9 @@ pub fn main(args: [][]u8) -> %void {
18 var line_buf : [20]u8 = undefined;18 var line_buf : [20]u8 = undefined;
1919
20 const line_len = io.stdin.read(line_buf) %% |err| {20 const line_len = io.stdin.read(line_buf) %% |err| {
21 %%io.stdout.printf("Unable to read from stdin.\n");21 %%io.stdout.printf("Unable to read from stdin: ");
22 %%io.stdout.printf(@errName(err));
23 %%io.stdout.printf("\n");
22 return err;24 return err;
23 };25 };
2426
std/debug.zig+1-1
...@@ -119,7 +119,7 @@ fn arangesOffset(st: &ElfStackTrace, target_address: usize) -> %?u64 {...@@ -119,7 +119,7 @@ fn arangesOffset(st: &ElfStackTrace, target_address: usize) -> %?u64 {
119 unit_index += 1;119 unit_index += 1;
120120
121 const align = segment_size + 2 * address_size;121 const align = segment_size + 2 * address_size;
122 const padding = st.self_exe_stream.offset % align;122 const padding = (%return st.self_exe_stream.getPos()) % align;
123 %return st.self_exe_stream.seekForward(padding);123 %return st.self_exe_stream.seekForward(padding);
124 unit_index += padding;124 unit_index += padding;
125125
std/elf.zig+1-1
...@@ -170,7 +170,7 @@ pub struct Elf {...@@ -170,7 +170,7 @@ pub struct Elf {
170 const ph_byte_count = u64(ph_entry_size) * u64(ph_entry_count);170 const ph_byte_count = u64(ph_entry_size) * u64(ph_entry_count);
171 const end_ph = %return math.addOverflow(u64, elf.program_header_offset, ph_byte_count);171 const end_ph = %return math.addOverflow(u64, elf.program_header_offset, ph_byte_count);
172172
173 const stream_end = %return elf.in_stream.endPos();173 const stream_end = %return elf.in_stream.getEndPos();
174 if (stream_end < end_sh || stream_end < end_ph) {174 if (stream_end < end_sh || stream_end < end_ph) {
175 return error.InvalidFormat;175 return error.InvalidFormat;
176 }176 }
std/index.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1pub const Rand = @import("rand.zig").Rand;1pub const rand = @import("rand.zig");
2pub const io = @import("io.zig");2pub const io = @import("io.zig");
3pub const os = @import("os.zig");3pub const os = @import("os.zig");
4pub const math = @import("math.zig");4pub const math = @import("math.zig");
std/io.zig+142-67
...@@ -11,7 +11,6 @@ pub const stderr_fileno = 2;...@@ -11,7 +11,6 @@ pub const stderr_fileno = 2;
1111
12pub var stdin = InStream {12pub var stdin = InStream {
13 .fd = stdin_fileno,13 .fd = stdin_fileno,
14 .offset = 0,
15};14};
1615
17pub var stdout = OutStream {16pub var stdout = OutStream {
...@@ -37,9 +36,6 @@ pub error Unexpected;...@@ -37,9 +36,6 @@ pub error Unexpected;
3736
38pub error DiskQuota;37pub error DiskQuota;
39pub error FileTooBig;38pub error FileTooBig;
40// TODO hide interrupts at this layer by retrying. Users can use the linux specific APIs if they
41// want to handle interrupts.
42pub error SigInterrupt;
43pub error Io;39pub error Io;
44pub error NoSpaceLeft;40pub error NoSpaceLeft;
45pub error BadPerm;41pub error BadPerm;
...@@ -113,34 +109,42 @@ pub struct OutStream {...@@ -113,34 +109,42 @@ pub struct OutStream {
113 }109 }
114110
115 pub fn flush(os: &OutStream) -> %void {111 pub fn flush(os: &OutStream) -> %void {
116 const write_ret = linux.write(os.fd, &os.buffer[0], os.index);112 while (true) {
117 const write_err = linux.getErrno(write_ret);113 const write_ret = linux.write(os.fd, &os.buffer[0], os.index);
118 if (write_err > 0) {114 const write_err = linux.getErrno(write_ret);
119 return switch (write_err) {115 if (write_err > 0) {
120 errno.EINVAL => unreachable{},116 return switch (write_err) {
121 errno.EDQUOT => error.DiskQuota,117 errno.EINTR => continue,
122 errno.EFBIG => error.FileTooBig,118
123 errno.EINTR => error.SigInterrupt,119 errno.EINVAL => unreachable{},
124 errno.EIO => error.Io,120 errno.EDQUOT => error.DiskQuota,
125 errno.ENOSPC => error.NoSpaceLeft,121 errno.EFBIG => error.FileTooBig,
126 errno.EPERM => error.BadPerm,122 errno.EIO => error.Io,
127 errno.EPIPE => error.PipeFail,123 errno.ENOSPC => error.NoSpaceLeft,
128 else => error.Unexpected,124 errno.EPERM => error.BadPerm,
125 errno.EPIPE => error.PipeFail,
126 else => error.Unexpected,
127 }
129 }128 }
129 os.index = 0;
130 return;
130 }131 }
131 os.index = 0;
132 }132 }
133133
134 pub fn close(os: &OutStream) -> %void {134 pub fn close(os: &OutStream) -> %void {
135 const close_ret = linux.close(os.fd);135 while (true) {
136 const close_err = linux.getErrno(close_ret);136 const close_ret = linux.close(os.fd);
137 if (close_err > 0) {137 const close_err = linux.getErrno(close_ret);
138 return switch (close_err) {138 if (close_err > 0) {
139 errno.EIO => error.Io,139 return switch (close_err) {
140 errno.EBADF => error.BadFd,140 errno.EINTR => continue,
141 errno.EINTR => error.SigInterrupt,141
142 else => error.Unexpected,142 errno.EIO => error.Io,
143 errno.EBADF => error.BadFd,
144 else => error.Unexpected,
145 }
143 }146 }
147 return;
144 }148 }
145 }149 }
146}150}
...@@ -149,47 +153,62 @@ pub struct OutStream {...@@ -149,47 +153,62 @@ pub struct OutStream {
149// BufferedInStream API goes on top of minimal InStream API.153// BufferedInStream API goes on top of minimal InStream API.
150pub struct InStream {154pub struct InStream {
151 fd: i32,155 fd: i32,
152 offset: usize,
153156
154 /// Call close to clean up.157 /// Call close to clean up.
155 pub fn open(is: &InStream, path: []const u8) -> %void {158 pub fn open(is: &InStream, path: []const u8) -> %void {
156 const result = linux.open(path, linux.O_LARGEFILE|linux.O_RDONLY, 0);159 switch (@compileVar("os")) {
157 const err = linux.getErrno(result);160 linux => {
158 if (err > 0) {161 while (true) {
159 return switch (err) {162 const result = linux.open(path, linux.O_LARGEFILE|linux.O_RDONLY, 0);
160 errno.EFAULT => unreachable{},163 const err = linux.getErrno(result);
161 errno.EINVAL => unreachable{},164 if (err > 0) {
162 errno.EACCES => error.BadPerm,165 return switch (err) {
163 errno.EFBIG, errno.EOVERFLOW => error.FileTooBig,166 errno.EINTR => continue,
164 errno.EINTR => error.SigInterrupt,167
165 errno.EISDIR => error.IsDir,168 errno.EFAULT => unreachable{},
166 errno.ELOOP => error.SymLinkLoop,169 errno.EINVAL => unreachable{},
167 errno.EMFILE => error.ProcessFdQuotaExceeded,170 errno.EACCES => error.BadPerm,
168 errno.ENAMETOOLONG => error.NameTooLong,171 errno.EFBIG, errno.EOVERFLOW => error.FileTooBig,
169 errno.ENFILE => error.SystemFdQuotaExceeded,172 errno.EISDIR => error.IsDir,
170 errno.ENODEV => error.NoDevice,173 errno.ELOOP => error.SymLinkLoop,
171 errno.ENOENT => error.PathNotFound,174 errno.EMFILE => error.ProcessFdQuotaExceeded,
172 errno.ENOMEM => error.NoMem,175 errno.ENAMETOOLONG => error.NameTooLong,
173 errno.ENOSPC => error.NoSpaceLeft,176 errno.ENFILE => error.SystemFdQuotaExceeded,
174 errno.ENOTDIR => error.NotDir,177 errno.ENODEV => error.NoDevice,
175 errno.EPERM => error.BadPerm,178 errno.ENOENT => error.PathNotFound,
176 else => error.Unexpected,179 errno.ENOMEM => error.NoMem,
177 }180 errno.ENOSPC => error.NoSpaceLeft,
181 errno.ENOTDIR => error.NotDir,
182 errno.EPERM => error.BadPerm,
183 else => error.Unexpected,
184 }
185 }
186 is.fd = i32(result);
187 return;
188 }
189 },
190 else => @compileErr("unsupported OS"),
178 }191 }
179 is.fd = i32(result);
180 is.offset = 0;
181 }192 }
182193
183 pub fn close(is: &InStream) -> %void {194 pub fn close(is: &InStream) -> %void {
184 const close_ret = linux.close(is.fd);195 switch (@compileVar("os")) {
185 const close_err = linux.getErrno(close_ret);196 linux => {
186 if (close_err > 0) {197 while (true) {
187 return switch (close_err) {198 const close_ret = linux.close(is.fd);
188 errno.EIO => error.Io,199 const close_err = linux.getErrno(close_ret);
189 errno.EBADF => error.BadFd,200 if (close_err > 0) {
190 errno.EINTR => error.SigInterrupt,201 return switch (close_err) {
191 else => error.Unexpected,202 errno.EINTR => continue,
192 }203
204 errno.EIO => error.Io,
205 errno.EBADF => error.BadFd,
206 else => error.Unexpected,
207 }
208 }
209 }
210 },
211 else => @compileErr("unsupported OS"),
193 }212 }
194 }213 }
195214
...@@ -198,12 +217,14 @@ pub struct InStream {...@@ -198,12 +217,14 @@ pub struct InStream {
198 pub fn read(is: &InStream, buf: []u8) -> %usize {217 pub fn read(is: &InStream, buf: []u8) -> %usize {
199 switch (@compileVar("os")) {218 switch (@compileVar("os")) {
200 linux => {219 linux => {
201 while (true) {220 var index: usize = 0;
202 const amt_read = linux.pread(is.fd, buf.ptr, buf.len, is.offset);221 while (index < buf.len) {
222 const amt_read = linux.read(is.fd, &buf[index], buf.len - index);
203 const read_err = linux.getErrno(amt_read);223 const read_err = linux.getErrno(amt_read);
204 if (read_err > 0) {224 if (read_err > 0) {
205 switch (read_err) {225 switch (read_err) {
206 errno.EINTR => continue,226 errno.EINTR => continue,
227
207 errno.EINVAL => unreachable{},228 errno.EINVAL => unreachable{},
208 errno.EFAULT => unreachable{},229 errno.EFAULT => unreachable{},
209 errno.EBADF => return error.BadFd,230 errno.EBADF => return error.BadFd,
...@@ -211,9 +232,10 @@ pub struct InStream {...@@ -211,9 +232,10 @@ pub struct InStream {
211 else => return error.Unexpected,232 else => return error.Unexpected,
212 }233 }
213 }234 }
214 is.offset += amt_read;235 if (amt_read == 0) return index;
215 return amt_read;236 index += amt_read;
216 }237 }
238 return index;
217 },239 },
218 else => @compileErr("unsupported OS"),240 else => @compileErr("unsupported OS"),
219 }241 }
...@@ -261,14 +283,67 @@ pub struct InStream {...@@ -261,14 +283,67 @@ pub struct InStream {
261 }283 }
262284
263 pub fn seekForward(is: &InStream, amount: usize) -> %void {285 pub fn seekForward(is: &InStream, amount: usize) -> %void {
264 is.offset += amount;286 switch (@compileVar("os")) {
287 linux => {
288 const result = linux.lseek(is.fd, amount, linux.SEEK_CUR);
289 const err = linux.getErrno(result);
290 if (err > 0) {
291 return switch (err) {
292 errno.EBADF => error.BadFd,
293 errno.EINVAL => error.Unseekable,
294 errno.EOVERFLOW => error.Unseekable,
295 errno.ESPIPE => error.Unseekable,
296 errno.ENXIO => error.Unseekable,
297 else => error.Unexpected,
298 };
299 }
300 },
301 else => @compileErr("unsupported OS"),
302 }
265 }303 }
266304
267 pub fn seekTo(is: &InStream, pos: usize) -> %void {305 pub fn seekTo(is: &InStream, pos: usize) -> %void {
268 is.offset = pos;306 switch (@compileVar("os")) {
307 linux => {
308 const result = linux.lseek(is.fd, pos, linux.SEEK_SET);
309 const err = linux.getErrno(result);
310 if (err > 0) {
311 return switch (err) {
312 errno.EBADF => error.BadFd,
313 errno.EINVAL => error.Unseekable,
314 errno.EOVERFLOW => error.Unseekable,
315 errno.ESPIPE => error.Unseekable,
316 errno.ENXIO => error.Unseekable,
317 else => error.Unexpected,
318 };
319 }
320 },
321 else => @compileErr("unsupported OS"),
322 }
323 }
324
325 pub fn getPos(is: &InStream) -> %usize {
326 switch (@compileVar("os")) {
327 linux => {
328 const result = linux.lseek(is.fd, 0, linux.SEEK_CUR);
329 const err = linux.getErrno(result);
330 if (err > 0) {
331 return switch (err) {
332 errno.EBADF => error.BadFd,
333 errno.EINVAL => error.Unseekable,
334 errno.EOVERFLOW => error.Unseekable,
335 errno.ESPIPE => error.Unseekable,
336 errno.ENXIO => error.Unseekable,
337 else => error.Unexpected,
338 };
339 }
340 return result;
341 },
342 else => @compileErr("unsupported OS"),
343 }
269 }344 }
270345
271 pub fn endPos(is: &InStream) -> %usize {346 pub fn getEndPos(is: &InStream) -> %usize {
272 var stat: linux.stat = undefined;347 var stat: linux.stat = undefined;
273 const err = linux.getErrno(linux.fstat(is.fd, &stat));348 const err = linux.getErrno(linux.fstat(is.fd, &stat));
274 if (err > 0) {349 if (err > 0) {