main
1#ifndef KC_HEADER_IO_FILE_INCLUDED
2#define KC_HEADER_IO_FILE_INCLUDED
3
4#include "./stream.h"
5#include "../types/string.h"
6#include "../memory/arenas.h"
7
8typedef struct _File File;
9
10void File_to_stream_source( File *f, SourceGeneric *stream );
11void File_to_stream_sink( File *f, SinkGeneric *stream );
12
13enum FileOption {
14 FILEOPT_READ = (1<<0),
15 FILEOPT_WRITE = (1<<1),
16 FILEOPT_READWRITE = FILEOPT_READ | FILEOPT_WRITE,
17
18 FILEOPT_DISALLOW_CREATION = (1<<2),
19 FILEOPT_NO_FOLLOW_LINKS = (1<<3),
20
21};
22
23status File_open( File* fout, const string *path, u64 file_options, Arena scratch );
24status File_close( File* f );
25
26status File_read( File *f, u64 *amount, u8 *out);
27status File_write( File *f, u64 *amount, const u8 *in);
28
29#ifdef KC_IMPLEMENT
30
31 void File_to_stream_source( File *f, SourceGeneric *stream ) {
32 stream->self = f;
33 stream->close = (StreamCloseFunction)&File_close;
34 stream->consume = (StreamInteractFunction)&File_read;
35 }
36
37 void File_to_stream_sink( File *f, SinkGeneric *stream ) {
38 stream->self = f;
39 stream->close = (StreamCloseFunction)&File_close;
40 stream->produce = (StreamInteractFunction)&File_write;
41 }
42
43 #if defined(KC_PLATFORM_LINUX)
44 #ifdef KC_USE_PLATFORM_LIBC
45 #include <fcntl.h>
46 #include <unistd.h>
47
48 struct _File {
49 i32 fd;
50 };
51
52 status File_open( File *fout, const string *path, u64 file_options, Arena scratch ) {
53 u8* path_c = 0;
54 PROPAGATE_ERROR( string_to_cstring( path, &scratch, &path_c ) );
55
56 mode_t mode = 0;
57
58 if( file_options & FILEOPT_READ ) {
59 if( file_options & FILEOPT_WRITE ) {
60 mode = O_RDWR;
61 } else {
62 mode = O_RDONLY;
63 }
64 } else if( file_options & FILEOPT_WRITE ) {
65 mode = O_RDWR;
66 } else {
67 return ERROR_INVALID_ARGUMENTS;
68 }
69
70 if( !file_options ) {
71 return ERROR_INVALID_ARGUMENTS;
72 }
73
74 /* Reads shouldn't create files, like ever. This option only makes sense on write. */
75 if( !(file_options & FILEOPT_DISALLOW_CREATION && (file_options & FILEOPT_WRITE) ) ) {
76 mode |= O_CREAT;
77 }
78
79 if( (file_options & FILEOPT_NO_FOLLOW_LINKS) ) {
80 mode |= O_NOFOLLOW;
81 }
82
83 fout->fd = open( (char*)path_c, mode );
84
85 if( fout->fd < 0 ) {
86 return ERROR_PLATFORM_FILE_OPEN_FAILED;
87 }
88
89 return STATUS_SUCCESS;
90 }
91
92 status File_close(File *f) {
93 assert( f->fd != -1 );
94
95 if( close(f->fd) != 0 ) {
96 return ERROR_PLATFORM_FILE_CLOSE_FAILED;
97 }
98
99 f->fd = -1;
100 return STATUS_SUCCESS;
101 }
102
103 status File_read(File *f, u64 *amount, u8 *out) {
104
105 size_t res = read( f->fd, out, *amount );
106
107 if( res == 0 || res < *amount ) {
108 *amount = res;
109 return STATUS_STREAM_ENDED;
110 }
111
112 if( res == (size_t)-1 ) {
113 return ERROR_PLATFORM_FILE_READ_FAILED;
114 }
115
116 return STATUS_SUCCESS;
117 }
118
119 status File_write(File *f, u64 *amount, const u8 *in) {
120
121 size_t res = write( f->fd, (char*)in, *amount );
122
123 if( res != *amount ) {
124 *amount = res;
125 return STATUS_PARTIAL_WRITE;
126 }
127
128 if( res == (size_t)-1 ) {
129 return ERROR_PLATFORM_FILE_WRITE_FAILED;
130 }
131
132 return STATUS_SUCCESS;
133 }
134
135
136 #else
137 #error I/O is not supported without libc for now (due to syscalls missing - after adding syscall wrappers this will be possible)
138 #endif
139
140 #elif defined(KC_PLATFORM_WINDOWS)
141 #error Unsupported platform for I/O
142 #else
143 #error Unsupported platform for I/O
144 #endif
145
146#endif
147
148#endif