Upload files to ""
This commit is contained in:
parent
7cfa49c8f5
commit
9a564687ab
560
iobridge.c
Normal file
560
iobridge.c
Normal 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
41
iobridge_test.c
Normal 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
418
iobridge_unix.h
Normal 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
80
v0.1.md
Normal 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.
|
Loading…
Reference in New Issue
Block a user