| ... | ... | @@ -11,7 +11,6 @@ pub const stderr_fileno = 2; |
| 11 | 11 | |
| 12 | 12 | pub var stdin = InStream { |
| 13 | 13 | .fd = stdin_fileno, |
| 14 | | .offset = 0, |
| 15 | 14 | }; |
| 16 | 15 | |
| 17 | 16 | pub var stdout = OutStream { |
| ... | ... | @@ -37,9 +36,6 @@ pub error Unexpected; |
| 37 | 36 | |
| 38 | 37 | pub error DiskQuota; |
| 39 | 38 | pub 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. |
| 42 | | pub error SigInterrupt; |
| 43 | 39 | pub error Io; |
| 44 | 40 | pub error NoSpaceLeft; |
| 45 | 41 | pub error BadPerm; |
| ... | ... | @@ -113,34 +109,42 @@ pub struct OutStream { |
| 113 | 109 | } |
| 114 | 110 | |
| 115 | 111 | pub fn flush(os: &OutStream) -> %void { |
| 116 | | const write_ret = linux.write(os.fd, &os.buffer[0], os.index); |
| 117 | | const write_err = linux.getErrno(write_ret); |
| 118 | | if (write_err > 0) { |
| 119 | | return switch (write_err) { |
| 120 | | errno.EINVAL => unreachable{}, |
| 121 | | errno.EDQUOT => error.DiskQuota, |
| 122 | | errno.EFBIG => error.FileTooBig, |
| 123 | | errno.EINTR => error.SigInterrupt, |
| 124 | | errno.EIO => error.Io, |
| 125 | | errno.ENOSPC => error.NoSpaceLeft, |
| 126 | | errno.EPERM => error.BadPerm, |
| 127 | | errno.EPIPE => error.PipeFail, |
| 128 | | else => error.Unexpected, |
| 112 | while (true) { |
| 113 | const write_ret = linux.write(os.fd, &os.buffer[0], os.index); |
| 114 | const write_err = linux.getErrno(write_ret); |
| 115 | if (write_err > 0) { |
| 116 | return switch (write_err) { |
| 117 | errno.EINTR => continue, |
| 118 | |
| 119 | errno.EINVAL => unreachable{}, |
| 120 | errno.EDQUOT => error.DiskQuota, |
| 121 | errno.EFBIG => error.FileTooBig, |
| 122 | errno.EIO => error.Io, |
| 123 | errno.ENOSPC => error.NoSpaceLeft, |
| 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 | } |
| 133 | 133 | |
| 134 | 134 | pub fn close(os: &OutStream) -> %void { |
| 135 | | const close_ret = linux.close(os.fd); |
| 136 | | const close_err = linux.getErrno(close_ret); |
| 137 | | if (close_err > 0) { |
| 138 | | return switch (close_err) { |
| 139 | | errno.EIO => error.Io, |
| 140 | | errno.EBADF => error.BadFd, |
| 141 | | errno.EINTR => error.SigInterrupt, |
| 142 | | else => error.Unexpected, |
| 135 | while (true) { |
| 136 | const close_ret = linux.close(os.fd); |
| 137 | const close_err = linux.getErrno(close_ret); |
| 138 | if (close_err > 0) { |
| 139 | return switch (close_err) { |
| 140 | errno.EINTR => continue, |
| 141 | |
| 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 | 153 | // BufferedInStream API goes on top of minimal InStream API. |
| 150 | 154 | pub struct InStream { |
| 151 | 155 | fd: i32, |
| 152 | | offset: usize, |
| 153 | 156 | |
| 154 | 157 | /// Call close to clean up. |
| 155 | 158 | pub fn open(is: &InStream, path: []const u8) -> %void { |
| 156 | | const result = linux.open(path, linux.O_LARGEFILE|linux.O_RDONLY, 0); |
| 157 | | const err = linux.getErrno(result); |
| 158 | | if (err > 0) { |
| 159 | | return switch (err) { |
| 160 | | errno.EFAULT => unreachable{}, |
| 161 | | errno.EINVAL => unreachable{}, |
| 162 | | errno.EACCES => error.BadPerm, |
| 163 | | errno.EFBIG, errno.EOVERFLOW => error.FileTooBig, |
| 164 | | errno.EINTR => error.SigInterrupt, |
| 165 | | errno.EISDIR => error.IsDir, |
| 166 | | errno.ELOOP => error.SymLinkLoop, |
| 167 | | errno.EMFILE => error.ProcessFdQuotaExceeded, |
| 168 | | errno.ENAMETOOLONG => error.NameTooLong, |
| 169 | | errno.ENFILE => error.SystemFdQuotaExceeded, |
| 170 | | errno.ENODEV => error.NoDevice, |
| 171 | | errno.ENOENT => error.PathNotFound, |
| 172 | | errno.ENOMEM => error.NoMem, |
| 173 | | errno.ENOSPC => error.NoSpaceLeft, |
| 174 | | errno.ENOTDIR => error.NotDir, |
| 175 | | errno.EPERM => error.BadPerm, |
| 176 | | else => error.Unexpected, |
| 177 | | } |
| 159 | switch (@compileVar("os")) { |
| 160 | linux => { |
| 161 | while (true) { |
| 162 | const result = linux.open(path, linux.O_LARGEFILE|linux.O_RDONLY, 0); |
| 163 | const err = linux.getErrno(result); |
| 164 | if (err > 0) { |
| 165 | return switch (err) { |
| 166 | errno.EINTR => continue, |
| 167 | |
| 168 | errno.EFAULT => unreachable{}, |
| 169 | errno.EINVAL => unreachable{}, |
| 170 | errno.EACCES => error.BadPerm, |
| 171 | errno.EFBIG, errno.EOVERFLOW => error.FileTooBig, |
| 172 | errno.EISDIR => error.IsDir, |
| 173 | errno.ELOOP => error.SymLinkLoop, |
| 174 | errno.EMFILE => error.ProcessFdQuotaExceeded, |
| 175 | errno.ENAMETOOLONG => error.NameTooLong, |
| 176 | errno.ENFILE => error.SystemFdQuotaExceeded, |
| 177 | errno.ENODEV => error.NoDevice, |
| 178 | errno.ENOENT => error.PathNotFound, |
| 179 | errno.ENOMEM => error.NoMem, |
| 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 | } |
| 182 | 193 | |
| 183 | 194 | pub fn close(is: &InStream) -> %void { |
| 184 | | const close_ret = linux.close(is.fd); |
| 185 | | const close_err = linux.getErrno(close_ret); |
| 186 | | if (close_err > 0) { |
| 187 | | return switch (close_err) { |
| 188 | | errno.EIO => error.Io, |
| 189 | | errno.EBADF => error.BadFd, |
| 190 | | errno.EINTR => error.SigInterrupt, |
| 191 | | else => error.Unexpected, |
| 192 | | } |
| 195 | switch (@compileVar("os")) { |
| 196 | linux => { |
| 197 | while (true) { |
| 198 | const close_ret = linux.close(is.fd); |
| 199 | const close_err = linux.getErrno(close_ret); |
| 200 | if (close_err > 0) { |
| 201 | return switch (close_err) { |
| 202 | errno.EINTR => continue, |
| 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 | } |
| 195 | 214 | |
| ... | ... | @@ -198,12 +217,14 @@ pub struct InStream { |
| 198 | 217 | pub fn read(is: &InStream, buf: []u8) -> %usize { |
| 199 | 218 | switch (@compileVar("os")) { |
| 200 | 219 | linux => { |
| 201 | | while (true) { |
| 202 | | const amt_read = linux.pread(is.fd, buf.ptr, buf.len, is.offset); |
| 220 | var index: usize = 0; |
| 221 | while (index < buf.len) { |
| 222 | const amt_read = linux.read(is.fd, &buf[index], buf.len - index); |
| 203 | 223 | const read_err = linux.getErrno(amt_read); |
| 204 | 224 | if (read_err > 0) { |
| 205 | 225 | switch (read_err) { |
| 206 | 226 | errno.EINTR => continue, |
| 227 | |
| 207 | 228 | errno.EINVAL => unreachable{}, |
| 208 | 229 | errno.EFAULT => unreachable{}, |
| 209 | 230 | errno.EBADF => return error.BadFd, |
| ... | ... | @@ -211,9 +232,10 @@ pub struct InStream { |
| 211 | 232 | else => return error.Unexpected, |
| 212 | 233 | } |
| 213 | 234 | } |
| 214 | | is.offset += amt_read; |
| 215 | | return amt_read; |
| 235 | if (amt_read == 0) return index; |
| 236 | index += amt_read; |
| 216 | 237 | } |
| 238 | return index; |
| 217 | 239 | }, |
| 218 | 240 | else => @compileErr("unsupported OS"), |
| 219 | 241 | } |
| ... | ... | @@ -261,14 +283,67 @@ pub struct InStream { |
| 261 | 283 | } |
| 262 | 284 | |
| 263 | 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 | } |
| 266 | 304 | |
| 267 | 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 | } |
| 270 | 345 | |
| 271 | | pub fn endPos(is: &InStream) -> %usize { |
| 346 | pub fn getEndPos(is: &InStream) -> %usize { |
| 272 | 347 | var stat: linux.stat = undefined; |
| 273 | 348 | const err = linux.getErrno(linux.fstat(is.fd, &stat)); |
| 274 | 349 | if (err > 0) { |