#include "file.h" #include #include #include #include #include #include enum mode { MODE_R = 0x01u, MODE_W = 0x02u, MODE_A = 0x04u, MODE_B = 0x08u, MODE_X = 0x10u, MODE_PLUS = 0x20u, }; static int flags_from_mode( const char *mode_string, int *out_sysflags, enum file_flags *out_fflags) { enum mode mode = 0; int sysflags = 0; enum file_flags fflags = 0; for (int i = 0; mode_string[i]; i++) { switch (mode_string[i]) { case 'r': if (mode & (MODE_R | MODE_W | MODE_A | MODE_X)) { return -1; } mode |= MODE_R; break; case 'w': if (mode & (MODE_R | MODE_W | MODE_A)) { return -1; } mode |= MODE_W; break; case 'a': if (mode & (MODE_R | MODE_W | MODE_A | MODE_X)) { return -1; } break; case '+': if (mode & MODE_PLUS) { return -1; } mode |= MODE_PLUS; break; case 'b': if (mode & MODE_B) { return -1; } mode |= MODE_B; break; case 'x': if (mode & (MODE_R | MODE_A | MODE_X)) { return -1; } mode |= MODE_X; break; default: return -1; } } switch ((int)mode) { case MODE_R | MODE_B: fflags = FILE_BIN; case MODE_R: sysflags = O_RDONLY; break; case MODE_W | MODE_B: fflags = FILE_BIN; case MODE_W: sysflags = O_WRONLY | O_TRUNC | O_CREAT; break; case MODE_A | MODE_B: fflags = FILE_BIN; case MODE_A: sysflags = O_WRONLY | O_APPEND | O_CREAT; break; case MODE_R | MODE_PLUS | MODE_B: fflags = FILE_BIN; case MODE_R | MODE_PLUS: sysflags = O_RDWR; break; case MODE_W | MODE_PLUS | MODE_B: fflags = FILE_BIN; case MODE_W | MODE_PLUS: sysflags = O_RDWR | O_TRUNC | O_CREAT; break; case MODE_W | MODE_PLUS | MODE_X | MODE_B: fflags = FILE_BIN; case MODE_W | MODE_PLUS | MODE_X: sysflags = O_RDWR | O_TRUNC | O_CREAT | O_EXCL; break; case MODE_A | MODE_PLUS | MODE_B: fflags = FILE_BIN; case MODE_A | MODE_PLUS: sysflags = O_RDWR | O_APPEND | O_CREAT; break; default: return -1; } return 0; } struct __opaque_file *fopen(const char *path, const char *mode) { int sysflags = 0; enum file_flags fflags = 0; if (flags_from_mode(mode, &sysflags, &fflags) != 0) { __set_errno(EINVAL); return NULL; } struct __opaque_file *out = malloc(sizeof *out); if (!out) { __set_errno(ENOMEM); return NULL; } memset(out, 0x0, sizeof *out); int fd = open(path, sysflags); if (fd < 0) { free(out); __set_errno(-fd); return NULL; } if (fflags & FILE_BIN) { out->f_buffer_mode = _IOFBF; } else { out->f_buffer_mode = _IOLBF; } out->f_fd = fd; out->f_flags = fflags; __set_errno(SUCCESS); return out; }