Upload files to ""

This commit is contained in:
Kamila Szewczyk 2023-11-10 22:15:31 +00:00
parent 7cfa49c8f5
commit 9a564687ab
4 changed files with 1099 additions and 0 deletions

560
iobridge.c Normal file
View File

@ -0,0 +1,560 @@
#define NEEDS_TYPES
#ifdef IOBRIDGE_UNIX
#include "iobridge_unix.h"
#endif
#undef NEEDS_TYPES
void write_be32(uint32_t value);
uint32_t read_be32();
void startup(char * program, char * args[]);
void child_send(int c);
int child_recv();
ssize_t read_line(char ** buffer, size_t * size);
void child_read(char ** buffer, uint32_t * size);
void child_write(uint8_t * buffer, uint32_t size);
void write_output(uint8_t * buffer, size_t size);
void write_error(uint8_t * buffer, size_t size);
int get_key();
void stdin_read(char ** buffer, uint32_t * size);
void * io_malloc(size_t size);
void io_free(void * ptr);
void * io_realloc(void * ptr, size_t size);
FILE_HANDLE_TYPE io_open(char *f, char *m);
void io_close(FILE_HANDLE_TYPE f);
void io_read_file(FILE_HANDLE_TYPE f, uint8_t ** buf, uint32_t * len);
void io_write_file(FILE_HANDLE_TYPE f, uint8_t * buf, uint32_t len);
uint32_t io_get_file_size(FILE_HANDLE_TYPE f);
enum { IO_SEEK_SET, IO_SEEK_CUR, IO_SEEK_END };
void io_seek_file(FILE_HANDLE_TYPE f, uint32_t off, uint8_t whence);
void io_rename(char * src, char * dst);
void io_delete(char * src);
void io_mkdir(char * src);
void io_rmdir(char * src);
void io_chdir(char * src);
void io_getcwd(char ** buffer);
unsigned long io_time();
void io_localtime(uint32_t * year, uint8_t * month, uint8_t * day, uint8_t * hour, uint8_t * minute, uint8_t * second);
void io_gmtime(uint32_t * year, uint8_t * month, uint8_t * day, uint8_t * hour, uint8_t * minute, uint8_t * second);
void io_sleep(uint32_t time);
void term_cooked();
void term_raw();
void term_flush();
void io_flush(FILE_HANDLE_TYPE f);
uint8_t get_errno();
uint8_t file_exists(char * path);
void term_bounds(uint32_t * width, uint32_t * height);
void io_handle_packet_0x25();
#define vector(type) type *
#define _internal_veccap(vec, size) \
do { \
if (vec) { \
((size_t *)(vec))[-1] = (size); \
} \
} while (0)
#define _internal_vecsiz(vec, size) \
do { \
if (vec) { \
((size_t *)(vec))[-2] = (size); \
} \
} while (0)
#define vector_capacity(vec) \
((vec) ? ((size_t *)(vec))[-1] : (size_t)0)
#define vector_size(vec) \
((vec) ? ((size_t *)(vec))[-2] : (size_t)0)
#define vector_empty(vec) \
(vector_size(vec) == 0)
#define vector_grow(vec, count) \
do { \
const size_t cv_sz = (count) * sizeof(*(vec)) + (sizeof(size_t) * 2); \
if (!(vec)) { \
size_t *cv_p = io_malloc(cv_sz); \
assert(cv_p); \
(vec) = (void *)(&cv_p[2]); \
_internal_veccap((vec), (count)); \
_internal_vecsiz((vec), 0); \
} else { \
size_t *cv_p1 = &((size_t *)(vec))[-2]; \
size_t *cv_p2 = io_realloc(cv_p1, (cv_sz)); \
assert(cv_p2); \
(vec) = (void *)(&cv_p2[2]); \
_internal_veccap((vec), (count)); \
} \
} while (0)
#define vector_pop_back(vec) \
do { \
_internal_vecsiz((vec), vector_size(vec) - 1); \
} while (0)
#define vector_erase(vec, i) \
do { \
if (vec) { \
const size_t cv_sz = vector_size(vec); \
if ((i) < cv_sz) { \
_internal_vecsiz((vec), cv_sz - 1); \
size_t cv_x; \
for (cv_x = (i); cv_x < (cv_sz - 1); ++cv_x) { \
(vec)[cv_x] = (vec)[cv_x + 1]; \
} \
} \
} \
} while (0)
#define vector_free(vec) \
do { \
if (vec) { \
size_t *p1 = &((size_t *)(vec))[-2]; \
io_free(p1); \
} \
} while (0)
#define vector_begin(vec) \
(vec)
#define vector_end(vec) \
((vec) ? &((vec)[vector_size(vec)]) : NULL)
#define vector_push_back(vec, value) \
do { \
size_t cv_cap = vector_capacity(vec); \
if (cv_cap <= vector_size(vec)) { \
vector_grow((vec), cv_cap + 16); \
} \
(vec)[vector_size(vec)] = (value); \
_internal_vecsiz((vec), vector_size(vec) + 1); \
} while (0)
vector(FILE_HANDLE_TYPE) files;
vector(uint8_t *) buffers;
vector(uint32_t) buffer_bounds;
// Packet implementations
void packet_0x01() {
// Read a line of stdin of arbitary size.
char * line = NULL; size_t size;
if (!read_line(&line, &size)) {
child_send(0x01);
write_be32(0);
return;
} else {
child_send(0x01);
write_be32(strlen(line) + 1);
child_write(line, strlen(line) + 1);
}
}
void packet_0x02() {
uint32_t len = read_be32();
uint8_t * data;
child_read((char **) &data, &len);
write_output(data, len);
io_free(data);
}
void packet_0x03() {
uint32_t len = read_be32();
uint8_t * data;
child_read((char **) &data, &len);
write_error(data, len);
io_free(data);
}
void packet_0x04() {
int16_t byte = get_key();
if (byte == -1) {
uint8_t b[] = { 0x04, 0xff, 0xff };
child_write(b, 3);
} else {
uint8_t b[] = { 0x04, (uint8_t) byte, (uint8_t) (byte >> 8) };
child_write(b, 3);
}
}
void packet_0x05() {
uint8_t byte = child_recv();
write_output((char *) &byte, 1);
}
void packet_0x06() {
uint8_t byte = child_recv();
write_error((char *) &byte, 1);
}
void packet_0x07() {
uint32_t len = read_be32();
uint8_t * data;
stdin_read((char **) &data, &len);
write_be32(len);
child_write((char *) data, len);
io_free(data);
}
void packet_0x08() {
uint32_t len = read_be32();
uint8_t * data = (uint8_t *) io_malloc(len);
if (data == NULL) {
child_send(0x08);
write_be32(0);
return;
}
// linearly search buffers to see if there's a tombstone anywhere.
for (uint32_t i = 0; i < vector_size(buffers); i++) {
if (buffers[i] == NULL) {
buffers[i] = data;
buffer_bounds[i] = len;
child_send(0x08);
write_be32(i);
return;
}
}
vector_push_back(buffer_bounds, len);
vector_push_back(buffers, data);
child_send(0x08);
write_be32(vector_size(buffers) - 1);
}
void packet_0x09() {
uint32_t ptr = read_be32();
if (ptr > vector_size(buffers))
return;
io_free(buffers[ptr]);
buffers[ptr] = NULL;
buffer_bounds[ptr] = 0;
}
void packet_0x0A() {
uint32_t ptr = read_be32();
uint32_t off = read_be32();
uint32_t len = read_be32();
if (ptr > vector_size(buffers) || off > buffer_bounds[ptr] || buffers[ptr] == NULL) {
child_send(0x0A);
write_be32(0);
return;
}
len = len < buffer_bounds[ptr] - off ? len : buffer_bounds[ptr] - off;
child_send(0x0A);
write_be32(len);
child_write((char *) buffers[ptr] + off, len);
}
void packet_0x0B() {
uint32_t ptr = read_be32();
uint32_t off = read_be32();
uint32_t len = read_be32();
uint8_t * data;
child_read((char **) &data, &len);
if (ptr > vector_size(buffers))
return;
if (off > buffer_bounds[ptr])
return;
if (buffers[ptr] == NULL)
return;
len = len < buffer_bounds[ptr] - off ? len : buffer_bounds[ptr] - off;
memcpy(buffers[ptr] + off, data, len);
io_free(data);
}
void packet_0x0C() {
uint32_t ptr = read_be32();
if (ptr > vector_size(buffers)|| buffers[ptr] == NULL) {
child_send(0x0C);
write_be32(0);
return;
}
child_send(0x0C);
write_be32(buffer_bounds[ptr]);
}
void packet_0x0D() {
uint32_t ptr = read_be32();
uint32_t new_len = read_be32();
if (ptr > vector_size(buffers) || buffers[ptr] == NULL)
return;
uint8_t * new_buffer = (uint8_t *) io_realloc(buffers[ptr], new_len);
buffers[ptr] = new_buffer;
buffer_bounds[ptr] = new_len;
}
void packet_0x0E() {
uint32_t len = read_be32();
uint32_t mode = read_be32();
uint8_t * data;
child_read((char **) &data, &len);
char mode_str[6]; int mode_ptr = 0;
while (mode != 0) {
if ((mode & 0xFF) != 0)
mode_str[mode_ptr++] = mode & 0xFF;
mode >>= 8;
}
mode_str[mode_ptr] = 0;
if(data[len - 1] == 0) data[len - 1] = 0x00;
FILE_HANDLE_TYPE file = io_open((char *) data, mode_str);
if (file == NULL) {
child_send(0x0E);
write_be32(0);
io_free(data);
return;
}
// linearly search files to see if there's a tombstone anywhere.
for (uint32_t i = 0; i < vector_size(buffers); i++) {
if (files[i] == NULL) {
files[i] = file;
child_send(0x0E);
write_be32(i);
io_free(data);
return;
}
}
vector_push_back(files, file);
child_send(0x0E);
write_be32(vector_size(files) - 1);
io_free(data);
}
void packet_0x0F() {
uint32_t ptr = read_be32();
if (ptr > vector_size(files) || files[ptr] == NULL)
return;
io_close(files[ptr]);
files[ptr] = NULL;
}
void packet_0x10() {
uint32_t ptr = read_be32();
uint32_t len = read_be32();
if (ptr > vector_size(files) || files[ptr] == NULL) {
child_send(0x10);
write_be32(0);
return;
}
uint8_t * data;
io_read_file(files[ptr], &data, &len);
child_send(0x10);
write_be32(len);
child_write((char *) data, len);
io_free(data);
}
void packet_0x11() {
uint32_t ptr = read_be32();
uint32_t len = read_be32();
uint8_t * data;
child_read((char **) &data, &len);
if (ptr > vector_size(files) || files[ptr] == NULL)
return;
io_write_file(files[ptr], data, len);
io_free(data);
}
void packet_0x12() {
uint32_t ptr = read_be32();
if (ptr > vector_size(files) || files[ptr] == NULL) {
child_send(0x12);
write_be32(0);
return;
}
child_send(0x12);
write_be32(io_get_file_size(files[ptr]));
}
void packet_0x13() {
uint32_t ptr = read_be32();
uint32_t off = read_be32();
uint8_t whence = child_recv();
if (ptr > vector_size(files) || files[ptr] == NULL)
return;
switch(whence) {
case 0: io_seek_file(files[ptr], (long)off, IO_SEEK_CUR); break;
case 1: io_seek_file(files[ptr], -(long)off, IO_SEEK_CUR); break;
case 2: io_seek_file(files[ptr], off, IO_SEEK_SET); break;
case 3: io_seek_file(files[ptr], -off, IO_SEEK_END); break;
}
}
void packet_0x14() {
uint32_t len1 = read_be32();
uint32_t len2 = read_be32();
uint8_t * data1; child_read((char **) &data1, &len1);
uint8_t * data2; child_read((char **) &data2, &len2);
if(data1[len1 - 1] == 0) data1[len1 - 1] = 0x00;
if(data2[len2 - 1] == 0) data2[len2 - 1] = 0x00;
io_rename((char *) data1, (char *) data2);
io_free(data1);
io_free(data2);
}
void packet_0x15() {
uint32_t len = read_be32();
uint8_t * data; child_read((char **) &data, &len);
if(data[len - 1] == 0) data[len - 1] = 0x00;
io_delete((char *) data);
io_free(data);
}
void packet_0x16() {
uint32_t len = read_be32();
uint8_t * data; child_read((char **) &data, &len);
if(data[len - 1] == 0) data[len - 1] = 0x00;
io_mkdir((char *) data);
io_free(data);
}
void packet_0x17() {
uint32_t len = read_be32();
uint8_t * data; child_read((char **) &data, &len);
if(data[len - 1] == 0) data[len - 1] = 0x00;
io_rmdir((char *) data);
io_free(data);
}
void packet_0x18() {
uint32_t len = read_be32();
uint8_t * data; child_read((char **) &data, &len);
if(data[len - 1] == 0) data[len - 1] = 0x00;
io_chdir((char *) data);
io_free(data);
}
void packet_0x19() {
char * cwd; io_getcwd(&cwd);
if (cwd == NULL) {
child_send(0x19);
write_be32(0);
return;
}
child_send(0x19);
write_be32(strlen(cwd) + 1);
child_write(cwd, strlen(cwd) + 1);
io_free(cwd);
}
void packet_0x1A() {
child_send(0x1A);
unsigned long t = io_time();
write_be32(t >> 32);
write_be32(t & 0xFFFFFFFF);
}
void packet_0x1B() {
child_send(0x1B);
uint32_t year; uint8_t month, day, hour, minute, second;
io_localtime(&year, &month, &day, &hour, &minute, &second);
write_be32(year);
child_send(month);
child_send(day);
child_send(hour);
child_send(minute);
child_send(second);
}
void packet_0x1C() {
child_send(0x1C);
uint32_t year; uint8_t month, day, hour, minute, second;
io_gmtime(&year, &month, &day, &hour, &minute, &second);
write_be32(year);
child_send(month);
child_send(day);
child_send(hour);
child_send(minute);
child_send(second);
}
void packet_0x1D() {
uint32_t time = read_be32();
io_sleep(time);
}
void packet_0x1E() {
term_raw();
}
void packet_0x1F() {
term_cooked();
}
void packet_0x20() {
uint32_t width, height;
term_bounds(&width, &height);
write_be32(width);
write_be32(height);
}
void packet_0x21() {
uint32_t ptr = read_be32();
if (ptr > vector_size(files) || files[ptr] == NULL)
return;
io_flush(files[ptr]);
}
void packet_0x22() {
term_flush();
}
void packet_0x23() {
child_send(0x23);
child_send(get_errno());
}
void packet_0x24() {
uint32_t len = read_be32();
uint8_t * data; child_read((char **) &data, &len);
if(data[len - 1] == 0) data[len - 1] = 0x00;
if(file_exists((char *) data) == 0) {
child_send(0x24);
child_send(1);
} else {
child_send(0x24);
child_send(0);
}
io_free(data);
}
void packet_0x25() {
io_handle_packet_0x25();
}
void packet_0x26() {
child_send(0x26);
child_send(0); // Version major.
child_send(1); // Version minor.
}
void packet_0x27() {
child_send(0x27);
write_be32(strlen(host) + 1);
child_write(host, strlen(host) + 1);
}
#ifdef IOBRIDGE_UNIX
#include "iobridge_unix.h"
#endif

41
iobridge_test.c Normal file
View File

@ -0,0 +1,41 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
uint32_t read_be32(void) {
uint32_t x = getchar();
x = (x << 8) | getchar();
x = (x << 8) | getchar();
x = (x << 8) | getchar();
return x;
}
int main(void) {
// Test 0x02:
putchar(0x02); putchar(0); putchar(0); putchar(0); putchar(46);
printf("Hello World! Type the following string: 12345\n");
// Test 0x01:
putchar(0x01); if(getchar() != 0x1) exit(1);
uint32_t x = read_be32();
if(x != 0x0000005) exit(1);
char buf[5]; fread(buf, 1, 5, stdin);
if(buf[0] != '1' || buf[1] != '2' || buf[2] != '3' || buf[3] != '4' || buf[4] != '5') exit(1);
// Test 0x03:
putchar(0x03); putchar(0); putchar(0); putchar(0); putchar(7);
printf("stderr\n");
// Test 0x04, 0x05, 0x06:
putchar(0x04); if (getchar() != 0x4) exit(1);
int c = getchar();
putchar(0x05); putchar(c); putchar(0x06); putchar(c);
// Test 0x07:
putchar(0x07); putchar(0); putchar(0); putchar(0); putchar(10); if (getchar() != 0x7) exit(1);
x = read_be32();
if(x != 0x000000a) exit(1);
// Parrot it:
char b2[10]; fread(b2, 1, 10, stdin);
putchar(0x02); putchar(0); putchar(0); putchar(0); putchar(10);
fwrite(b2, 1, 10, stdout);
// Test 0x08:
}

418
iobridge_unix.h Normal file
View File

@ -0,0 +1,418 @@
#ifdef NEEDS_TYPES
#include <unistd.h>
#include <sched.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <limits.h>
#include <dirent.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <time.h>
#include <assert.h>
#define FILE_HANDLE_TYPE FILE *
char host[] = "UNIX";
#else
struct files_t {
FILE *in;
FILE *out;
};
struct files_t *popen2(char * program, char * args[]);
int pclose2(struct files_t *fp);
#define CLEANUP_PIPE(pipe) close((pipe)[0]); close((pipe)[1])
typedef struct files_t files_t;
struct files_chain_t {
files_t files;
pid_t pid;
struct files_chain_t *next;
};
typedef struct files_chain_t files_chain_t;
static files_chain_t *files_chain;
static files_t * root_handle;
static int _do_popen2(files_chain_t *link, char * program, char * args[]) {
int child_in[2];
int child_out[2];
if (0 != pipe(child_in)) {
return -1;
}
if (0 != pipe(child_out)) {
CLEANUP_PIPE(child_in);
return -1;
}
pid_t cpid = link->pid = fork();
if (0 > cpid) {
CLEANUP_PIPE(child_in);
CLEANUP_PIPE(child_out);
return -1;
}
if (0 == cpid) {
if (0 > dup2(child_in[0], 0) || 0 > dup2(child_out[1], 1)) {
exit(1);
}
CLEANUP_PIPE(child_in);
CLEANUP_PIPE(child_out);
for (files_chain_t *p = files_chain; p; p = p->next) {
int fd_in = fileno(p->files.in);
if (fd_in != 0) {
close(fd_in);
}
int fd_out = fileno(p->files.out);
if (fd_out != 1) {
close(fd_out);
}
}
execv(program, args);
exit(1);
}
close(child_in[0]);
close(child_out[1]);
link->files.in = fdopen(child_in[1], "w");
link->files.out = fdopen(child_out[0], "r");
return 0;
}
files_t *popen2(char * program, char * args[]) {
files_chain_t *link = (files_chain_t *) malloc(sizeof (files_chain_t));
if (NULL == link) {
return NULL;
}
if (0 > _do_popen2(link, program, args)) {
free(link);
return NULL;
}
link->next = files_chain;
files_chain = link;
return (files_t *) link;
}
int pclose2(files_t *fp) {
files_chain_t **p = &files_chain;
int found = 0;
while (*p) {
if (*p == (files_chain_t *) fp) {
*p = (*p)->next;
found = 1;
break;
}
p = &(*p)->next;
}
if (!found) {
return -1;
}
if (0 > fclose(fp->in) || 0 > fclose(fp->out)) {
free((files_chain_t *) fp);
return -1;
}
int status = -1;
pid_t wait_pid;
do {
wait_pid = waitpid(((files_chain_t *) fp)->pid, &status, 0);
} while (-1 == wait_pid && EINTR == errno);
free((files_chain_t *) fp);
if (wait_pid == -1) {
return -1;
}
return status;
}
void write_be32(uint32_t value) {
fputc(value >> 24, root_handle->in);
fputc(value >> 16, root_handle->in);
fputc(value >> 8, root_handle->in);
fputc(value, root_handle->in);
}
uint32_t read_be32() {
uint32_t value = fgetc(root_handle->out) << 24;
value |= fgetc(root_handle->out) << 16;
value |= fgetc(root_handle->out) << 8;
value |= fgetc(root_handle->out);
return value;
}
int main(int argc, char * argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: %s <command> [args...]\n", argv[0]);
exit(1);
}
if (!(root_handle = popen2(argv[1], argv + 2))) {
fprintf(stderr, "Failed to run %s.\n", argv[1]);
exit(1);
}
while(!feof(root_handle->out)) {
int packet_code = fgetc(root_handle->out);
switch(packet_code) {
case 0x01: packet_0x01(); break;
case 0x02: packet_0x02(); break;
case 0x03: packet_0x03(); break;
case 0x04: packet_0x04(); break;
case 0x05: packet_0x05(); break;
case 0x06: packet_0x06(); break;
case 0x07: packet_0x07(); break;
case 0x08: packet_0x08(); break;
case 0x09: packet_0x09(); break;
case 0x0A: packet_0x0A(); break;
case 0x0B: packet_0x0B(); break;
case 0x0C: packet_0x0C(); break;
case 0x0D: packet_0x0D(); break;
case 0x0E: packet_0x0E(); break;
case 0x0F: packet_0x0F(); break;
case 0x10: packet_0x10(); break;
case 0x11: packet_0x11(); break;
case 0x12: packet_0x12(); break;
case 0x13: packet_0x13(); break;
case 0x14: packet_0x14(); break;
case 0x15: packet_0x15(); break;
case 0x16: packet_0x16(); break;
case 0x17: packet_0x17(); break;
case 0x18: packet_0x18(); break;
case 0x19: packet_0x19(); break;
case 0x1A: packet_0x1A(); break;
case 0x1B: packet_0x1B(); break;
case 0x1C: packet_0x1C(); break;
case 0x1D: packet_0x1D(); break;
case 0x1E: packet_0x1E(); break;
case 0x1F: packet_0x1F(); break;
case 0x20: packet_0x20(); break;
case 0x21: packet_0x21(); break;
case 0x22: packet_0x22(); break;
case 0x23: packet_0x23(); break;
case 0x24: packet_0x24(); break;
case 0x25: packet_0x25(); break;
case 0x26: packet_0x26(); break;
case 0x27: packet_0x27(); break;
default: fprintf(stderr, "[IOBridge] Unknown packet code: 0x%02X\n", packet_code); exit(1);
}
}
pclose2(root_handle);
}
void child_send(int c) {
fputc(c, root_handle->in);
}
int child_recv() {
int c = fgetc(root_handle->out);
return c == EOF ? -1 : c;
}
void child_read(char ** buffer, uint32_t * size) {
*buffer = (char *) malloc(*size);
if (!*buffer) {
fprintf(stderr, "Failed to allocate %u bytes.\n", *size);
exit(1);
}
*size = fread(buffer, 1, *size, root_handle->out);
}
void stdin_read(char ** buffer, uint32_t * size) {
*buffer = (char *) malloc(*size);
if (!*buffer) {
fprintf(stderr, "Failed to allocate %u bytes.\n", *size);
exit(1);
}
*size = fread(buffer, 1, *size, stdin);
}
void child_write(uint8_t * buffer, uint32_t size) {
fwrite(buffer, 1, size, root_handle->in);
}
ssize_t read_line(char ** buffer, size_t * size) {
return getline(buffer, size, root_handle->out) != -1;
}
void write_output(uint8_t * buffer, size_t size) {
fwrite(buffer, 1, size, stdout);
}
void write_error(uint8_t * buffer, size_t size) {
fwrite(buffer, 1, size, stderr);
}
int get_key() {
int x = fgetc(stdin);
if (x == EOF) return -1;
else return x;
}
void * io_malloc(size_t size) {
return malloc(size);
}
void io_free(void * ptr) {
free(ptr);
}
void * io_realloc(void * ptr, size_t size) {
return realloc(ptr, size);
}
FILE *io_open(char *f, char *m) {
return fopen(f, m);
}
void io_close(FILE *f) {
fclose(f);
}
void io_read_file(FILE * f, uint8_t ** buf, uint32_t * len) {
*buf = (uint8_t *) malloc(*len);
*len = fread(*buf, 1, *len, f);
}
void io_write_file(FILE * f, uint8_t * buf, uint32_t len) {
fwrite(buf, 1, len, f);
}
uint32_t io_get_file_size(FILE * f) {
long pos = ftell(f);
fseek(f, 0, SEEK_END);
uint32_t size = ftell(f);
fseek(f, pos, SEEK_SET);
return size;
}
void io_seek_file(FILE_HANDLE_TYPE f, uint32_t off, uint8_t whence) {
switch (whence) {
case 0: fseek(f, off, SEEK_SET); break;
case 1: fseek(f, off, SEEK_CUR); break;
case 2: fseek(f, off, SEEK_END); break;
}
}
void io_rename(char * src, char * dst) {
rename(src, dst);
}
void io_delete(char * f) {
unlink(f);
}
void io_mkdir(char * src) {
mkdir(src, 0777);
}
void io_rmdir(char * src) {
rmdir(src);
}
void io_chdir(char * src) {
chdir(src);
}
void io_getcwd(char ** buffer) {
uint32_t size = PATH_MAX;
*buffer = (char *) malloc(size);
if (!getcwd(*buffer, size)) {
free(*buffer);
*buffer = NULL;
}
}
unsigned long io_time() {
return time(NULL);
}
void io_localtime(uint32_t * year, uint8_t * month, uint8_t * day, uint8_t * hour, uint8_t * minute, uint8_t * second) {
struct tm * timeinfo;
time_t rawtime;
time(&rawtime);
timeinfo = localtime(&rawtime);
*year = timeinfo->tm_year + 1900;
*month = timeinfo->tm_mon + 1;
*day = timeinfo->tm_mday;
*hour = timeinfo->tm_hour;
*minute = timeinfo->tm_min;
*second = timeinfo->tm_sec;
}
void io_gmtime(uint32_t * year, uint8_t * month, uint8_t * day, uint8_t * hour, uint8_t * minute, uint8_t * second) {
struct tm * timeinfo;
time_t rawtime;
time(&rawtime);
timeinfo = gmtime(&rawtime);
*year = timeinfo->tm_year + 1900;
*month = timeinfo->tm_mon + 1;
*day = timeinfo->tm_mday;
*hour = timeinfo->tm_hour;
*minute = timeinfo->tm_min;
*second = timeinfo->tm_sec;
}
void io_sleep(uint32_t time) {
usleep(time * 1000);
}
void term_cooked() {
struct termios cooked;
tcgetattr(STDIN_FILENO, &cooked);
cooked.c_lflag |= (ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &cooked);
}
void term_raw() {
struct termios raw;
tcgetattr(STDIN_FILENO, &raw);
raw.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &raw);
}
void term_bounds(uint32_t * width, uint32_t * height) {
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
*width = w.ws_col;
*height = w.ws_row;
}
void term_flush() { fflush(stdout); }
void io_flush(FILE_HANDLE_TYPE f) { fflush(f); }
uint8_t get_errno() { return errno; }
uint8_t file_exists(char * path) {
struct stat st;
return stat(path, &st) == 0;
}
void io_handle_packet_0x25() {
uint32_t len = read_be32();
uint8_t * data; child_read((char **) &data, &len);
if(data[len - 1] == 0) data[len - 1] = 0x00;
DIR * dir = opendir((char *) data);
if(dir == NULL) {
child_send(0x25);
write_be32(0);
io_free(data);
return;
}
struct dirent * ent;
vector(uint8_t) buffer = NULL;
while((ent = readdir(dir)) != NULL) {
uint32_t len = strlen(ent->d_name) + 1;
vector_push_back(buffer, (len >> 8) & 0xff);
vector_push_back(buffer, len & 0xff);
for (int i = 0; i < len; i++) {
vector_push_back(buffer, ent->d_name[i]);
}
vector_push_back(buffer, ent->d_type);
}
closedir(dir);
child_send(0x25);
write_be32(vector_size(buffer));
child_write(buffer, vector_size(buffer));
vector_free(data);
}
#endif

80
v0.1.md Normal file
View File

@ -0,0 +1,80 @@
Numbers: Big Endian.
Input strings not null terminated unless explicitly stated.
Outgoing API:
0x00 - reserved
0x01 - read line from stdin; returns a 0x01 packet.
0x02 [len: u32, data: u8[]] - write to stdout
0x03 [len: u32, data: u8[]] - write to stderr
0x04 - read a byte from stdin; returns a 0x04 packet.
0x05 [byte: u8] - write a byte to stdout
0x06 [byte: u8] - write a byte to stderr
0x07 [len: u32] - read from stdin. returns a 0x07 packet.
0x08 [len: u32] - allocate a buffer of len bytes. returns a 0x08 packet.
0x09 [ptr: u32] - free a buffer allocated at ptr.
0x0A [ptr: u32, off: u32, len: u32] - read len bytes from ptr + off. returns a 0x0A packet.
0x0B [ptr: u32, off: u32, len: u32, data: u8[]] - write len bytes to ptr + off.
0x0C [ptr: u32] - query the size of the buffer allocated at ptr. returns a 0x0C packet.
0x0D [ptr: u32, new_len: u32] - resize the buffer allocated at ptr to new_len bytes.
Expect null-terminated data:
* 0x0E [len: u32, mode: u32, data: u8[]] - open a file (fopen). returns a 0x0E packet.
0x0F [ptr: u32] - close a file (fclose).
0x10 [ptr: u32, len: u32] - read len bytes from file. returns a 0x10 packet.
0x11 [ptr: u32, len: u32] - write len bytes to file.
0x12 [ptr: u32] - query the size of the file. returns a 0x12 packet.
0x13 [ptr: u32, off: u32, whence: u8]: seek to off bytes from whence
(0-backwards,1-forwards,2-from beginning,3-from end).
Expect null-terminated data:
* 0x14 [len: u32, len2: u32, data1: u8[], data2: u8[]] - rename.
* 0x15 [len: u32, data: u8[]] - unlink.
* 0x16 [len: u32, data: u8[]] - mkdir.
* 0x17 [len: u32, data: u8[]] - rmdir.
* 0x18 [len: u32, data: u8[]] - chdir.
0x19 - getcwd, returns a 0x19 packet.
0x1A - UNIX time, returns a 0x1A packet.
0x1B - local time, returns a 0x1B packet.
0x1C - GMT, returns a 0x1C packet.
0x1D [time: u32] - sleep for n ms.
0x1E - put terminal in raw mode (if platform supports that).
0x1F - put terminal in cooked mode (if platform supports that).
0x20 - get terminal size, returns a 0x20 packet.
0x21 [ptr: u32] - flush file.
0x22 - flush stdout.
0x23 - get errno state. returns a 0x23 packet.
Expect null-terminated data:
* 0x24 [len: u32, data: u8[]] - file exists? returns a 0x24 packet.
* 0x25 [len: u32, data: u8[]] - list directory entries. returns a 0x25 packet.
0x26 - API version. returns a 0x26 packet.
0x27 - Host environment. returns a 0x27 packet.
Incoming API:
0x01 [len: u32] [data: u8[]] - line read from stdin.
0x04 [byte: u16] - byte read from stdin.
0x07 [len: u32] [data: u8[]] - data read from stdin.
0x08 [ptr: u32] - buffer allocated at ptr (ptr = 0 if unable to allocate).
0x0A [len: u32] [data: u8[]] - data read from ptr + off.
0x0C [len: u32] - size of the buffer allocated at ptr.
0x0E [ptr: u32] - file opened at ptr (ptr = 0 if unable to open).
0x10 [len: u32] [data: u8[]] - data read from file.
0x12 [len: u32] - size of the file.
0x19 [len: u32] [data: u8[]] - current working directory (len = 0 if unable to determine).
0x1A [time: u64] - UNIX time.
0x1B [year: u32, month: u8, day: u8, hour: u8, minute: u8, second: u8] - local time.
0x1C [year: u32, month: u8, day: u8, hour: u8, minute: u8, second: u8] - GMT.
0x20 [width: u16, height: u16] - terminal size (or 0 if unknown).
0x23 [error: u8] - error state.
0x24 [exists: u8] - exists?
0x25 [no: u32, (len: u32, path: u8[], size: u32, type: u8)[]] - list directory entries.
0x26 [major: u8, minor: u8] - API version (0, 1).
0x27 [len: u32, data: u8[]] - Host environment.