backported more fixes from 256boss
[bootcensus] / src / libc / file.c
1 #ifndef FILE_H_
2 #define FILE_H_
3
4 #include <stdio.h>
5 #include <errno.h>
6 #include "fs.h"
7 #include "panic.h"
8
9 enum {
10         MODE_READ = 1,
11         MODE_WRITE = 2,
12         MODE_APPEND = 4,
13         MODE_CREATE = 8,
14         MODE_TRUNCATE = 16
15 };
16
17 enum {
18         STATUS_EOF      = 1,
19         STATUS_ERR      = 2
20 };
21
22 struct FILE {
23         unsigned int mode;
24         unsigned int status;
25         struct fs_node *fsn;
26 };
27
28 FILE *fopen(const char *path, const char *mode)
29 {
30         FILE *fp;
31         struct fs_node *node;
32         unsigned int mflags = 0;
33
34         while(*mode) {
35                 int c = *mode++;
36                 switch(c) {
37                 case 'r':
38                         mflags |= MODE_READ;
39                         if(*mode == '+') {
40                                 mflags |= MODE_WRITE;
41                                 mode++;
42                         }
43                         break;
44                 case 'w':
45                         mflags |= MODE_WRITE | MODE_TRUNCATE;
46                         if(*mode == '+') {
47                                 mflags |= MODE_READ | MODE_CREATE;
48                                 mode++;
49                         }
50                         break;
51                 case 'a':
52                         mflags |= MODE_WRITE | MODE_APPEND;
53                         if(*mode == '+') {
54                                 mflags |= MODE_READ | MODE_CREATE;
55                                 mode++;
56                         }
57                         break;
58                 case 'b':
59                         break;
60                 default:
61                         errno = EINVAL;
62                         return 0;
63                 }
64         }
65
66         if(!(node = fs_open(path, 0))) {
67                 /* TODO: create */
68                 errno = ENOENT; /* TODO */
69                 return 0;
70         }
71         if(node->type != FSNODE_FILE) {
72                 errno = EISDIR;
73                 return 0;
74         }
75
76         if(!(fp = malloc(sizeof *fp))) {
77                 errno = ENOMEM;
78                 return 0;
79         }
80         fp->fsn = node;
81         fp->mode = mflags;
82         fp->status = 0;
83
84         return fp;
85 }
86
87 int fclose(FILE *fp)
88 {
89         if(!fp) {
90                 errno = EINVAL;
91                 return -1;
92         }
93
94         fs_close(fp->fsn);
95         free(fp);
96         return 0;
97 }
98
99 long filesize(FILE *fp)
100 {
101         return fs_filesize(fp->fsn);
102 }
103
104 int fseek(FILE *fp, long offset, int from)
105 {
106         if(!fp) {
107                 errno = EINVAL;
108                 return -1;
109         }
110         if(from < 0 || from > 2) {
111                 errno = EINVAL;
112                 return -1;
113         }
114
115         fs_seek(fp->fsn, offset, from);
116         fp->status &= ~STATUS_EOF;
117         return 0;
118 }
119
120 void rewind(FILE *fp)
121 {
122         fseek(fp, 0, SEEK_SET);
123 }
124
125 long ftell(FILE *fp)
126 {
127         if(!fp) {
128                 errno = EINVAL;
129                 return -1;
130         }
131         return fs_tell(fp->fsn);
132 }
133
134 size_t fread(void *buf, size_t size, size_t count, FILE *fp)
135 {
136         int res;
137         if(!fp) return 0;
138         if((res = fs_read(fp->fsn, buf, size * count)) == -1) {
139                 fp->status |= STATUS_EOF;
140                 return 0;
141         }
142         return res / size;
143 }
144
145 size_t fwrite(const void *buf, size_t size, size_t count, FILE *fp)
146 {
147         int res;
148         if(!fp) return 0;
149         if(!(fp->mode & MODE_WRITE)) {
150                 fp->status |= STATUS_ERR;
151                 return 0;
152         }
153         if((res = fs_write(fp->fsn, (void*)buf, size * count)) == -1) {
154                 return 0;
155         }
156         return res / size;
157 }
158
159 int fgetc(FILE *fp)
160 {
161         unsigned char c;
162         if(fread(&c, 1, 1, fp) < 1) {
163                 return -1;
164         }
165         return c;
166 }
167
168 char *fgets(char *buf, int size, FILE *fp)
169 {
170         int c;
171         char *s = buf;
172
173         while(--size > 0 && (c = fgetc(fp)) >= 0) {
174                 *s++ = c;
175                 if(c == '\n') break;
176         }
177         *s = 0;
178         return s > buf ? buf : 0;
179 }
180
181 int fputc(int c, FILE *fp)
182 {
183         if(fp == stdout || fp == stderr) {
184                 return putchar(c);
185         }
186
187         panic("fputc on anything other than stdout/stderr not implemented yet\n");
188         return -1;
189 }
190
191 int fflush(FILE *fp)
192 {
193         if(fp == stdout || fp == stderr) {
194                 return 0;       /* do nothing */
195         }
196
197         panic("fflush on anything other than stdout/stderr not implemented yet\n");
198         return -1;
199 }
200
201 int feof(FILE *fp)
202 {
203         return (fp->status & STATUS_EOF) != 0;
204 }
205
206 int ferror(FILE *fp)
207 {
208         return (fp->status & STATUS_ERR) != 0;
209 }
210
211 void clearerr(FILE *fp)
212 {
213         fp->status = 0;
214 }
215
216 #endif  /* FILE_H_ */