Files

158 lines
2.6 KiB
C

#include "file.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
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;
}