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