#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