backported more fixes from 256boss
[bootcensus] / src / libc / file.c
diff --git a/src/libc/file.c b/src/libc/file.c
new file mode 100644 (file)
index 0000000..cc73f71
--- /dev/null
@@ -0,0 +1,216 @@
+#ifndef FILE_H_
+#define FILE_H_
+
+#include <stdio.h>
+#include <errno.h>
+#include "fs.h"
+#include "panic.h"
+
+enum {
+       MODE_READ = 1,
+       MODE_WRITE = 2,
+       MODE_APPEND = 4,
+       MODE_CREATE = 8,
+       MODE_TRUNCATE = 16
+};
+
+enum {
+       STATUS_EOF      = 1,
+       STATUS_ERR      = 2
+};
+
+struct FILE {
+       unsigned int mode;
+       unsigned int status;
+       struct fs_node *fsn;
+};
+
+FILE *fopen(const char *path, const char *mode)
+{
+       FILE *fp;
+       struct fs_node *node;
+       unsigned int mflags = 0;
+
+       while(*mode) {
+               int c = *mode++;
+               switch(c) {
+               case 'r':
+                       mflags |= MODE_READ;
+                       if(*mode == '+') {
+                               mflags |= MODE_WRITE;
+                               mode++;
+                       }
+                       break;
+               case 'w':
+                       mflags |= MODE_WRITE | MODE_TRUNCATE;
+                       if(*mode == '+') {
+                               mflags |= MODE_READ | MODE_CREATE;
+                               mode++;
+                       }
+                       break;
+               case 'a':
+                       mflags |= MODE_WRITE | MODE_APPEND;
+                       if(*mode == '+') {
+                               mflags |= MODE_READ | MODE_CREATE;
+                               mode++;
+                       }
+                       break;
+               case 'b':
+                       break;
+               default:
+                       errno = EINVAL;
+                       return 0;
+               }
+       }
+
+       if(!(node = fs_open(path, 0))) {
+               /* TODO: create */
+               errno = ENOENT; /* TODO */
+               return 0;
+       }
+       if(node->type != FSNODE_FILE) {
+               errno = EISDIR;
+               return 0;
+       }
+
+       if(!(fp = malloc(sizeof *fp))) {
+               errno = ENOMEM;
+               return 0;
+       }
+       fp->fsn = node;
+       fp->mode = mflags;
+       fp->status = 0;
+
+       return fp;
+}
+
+int fclose(FILE *fp)
+{
+       if(!fp) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       fs_close(fp->fsn);
+       free(fp);
+       return 0;
+}
+
+long filesize(FILE *fp)
+{
+       return fs_filesize(fp->fsn);
+}
+
+int fseek(FILE *fp, long offset, int from)
+{
+       if(!fp) {
+               errno = EINVAL;
+               return -1;
+       }
+       if(from < 0 || from > 2) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       fs_seek(fp->fsn, offset, from);
+       fp->status &= ~STATUS_EOF;
+       return 0;
+}
+
+void rewind(FILE *fp)
+{
+       fseek(fp, 0, SEEK_SET);
+}
+
+long ftell(FILE *fp)
+{
+       if(!fp) {
+               errno = EINVAL;
+               return -1;
+       }
+       return fs_tell(fp->fsn);
+}
+
+size_t fread(void *buf, size_t size, size_t count, FILE *fp)
+{
+       int res;
+       if(!fp) return 0;
+       if((res = fs_read(fp->fsn, buf, size * count)) == -1) {
+               fp->status |= STATUS_EOF;
+               return 0;
+       }
+       return res / size;
+}
+
+size_t fwrite(const void *buf, size_t size, size_t count, FILE *fp)
+{
+       int res;
+       if(!fp) return 0;
+       if(!(fp->mode & MODE_WRITE)) {
+               fp->status |= STATUS_ERR;
+               return 0;
+       }
+       if((res = fs_write(fp->fsn, (void*)buf, size * count)) == -1) {
+               return 0;
+       }
+       return res / size;
+}
+
+int fgetc(FILE *fp)
+{
+       unsigned char c;
+       if(fread(&c, 1, 1, fp) < 1) {
+               return -1;
+       }
+       return c;
+}
+
+char *fgets(char *buf, int size, FILE *fp)
+{
+       int c;
+       char *s = buf;
+
+       while(--size > 0 && (c = fgetc(fp)) >= 0) {
+               *s++ = c;
+               if(c == '\n') break;
+       }
+       *s = 0;
+       return s > buf ? buf : 0;
+}
+
+int fputc(int c, FILE *fp)
+{
+       if(fp == stdout || fp == stderr) {
+               return putchar(c);
+       }
+
+       panic("fputc on anything other than stdout/stderr not implemented yet\n");
+       return -1;
+}
+
+int fflush(FILE *fp)
+{
+       if(fp == stdout || fp == stderr) {
+               return 0;       /* do nothing */
+       }
+
+       panic("fflush on anything other than stdout/stderr not implemented yet\n");
+       return -1;
+}
+
+int feof(FILE *fp)
+{
+       return (fp->status & STATUS_EOF) != 0;
+}
+
+int ferror(FILE *fp)
+{
+       return (fp->status & STATUS_ERR) != 0;
+}
+
+void clearerr(FILE *fp)
+{
+       fp->status = 0;
+}
+
+#endif /* FILE_H_ */