From 90e5c15b02257d50d5d285323dd275bbf5584739 Mon Sep 17 00:00:00 2001 From: dschmenk Date: Wed, 4 Sep 2013 21:44:16 -0700 Subject: [PATCH] Initial FUSE Prodos driver and fix for key repeats --- src/Makefile | 6 + src/a2pid.c | 18 +- src/bload.c | 1 - src/brun.c | 1 - src/dskread.c | 1 - src/dskwrite.c | 1 - src/fusea2pi.c | 780 +++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 799 insertions(+), 9 deletions(-) create mode 100755 src/fusea2pi.c diff --git a/src/Makefile b/src/Makefile index 8de244c..4c1d544 100755 --- a/src/Makefile +++ b/src/Makefile @@ -2,9 +2,15 @@ BIN=a2serclk a2pid a2mon a2term dskread dskwrite bintomon bload brun all: $(BIN) +fusea2pi: fusea2pi.c a2lib.c + $(CC) -I/usr/include/fuse -D_FILE_OFFSET_BITS=64 fusea2pi.c -lfuse -o fusea2pi + clean: rm $(BIN) *~ install: $(BASH) ./install.sh cp $(BIN) /usr/local/bin + +fuse-install: fusea2pi + cp fusea2pi /usr/local/bin \ No newline at end of file diff --git a/src/a2pid.c b/src/a2pid.c index 2f3245a..a2bb87e 100755 --- a/src/a2pid.c +++ b/src/a2pid.c @@ -381,16 +381,16 @@ void sendkeycodeup(int fd, int code) } write(fd, &evsync, sizeof(evsync)); } +static int prevkeycode = -1; void sendkey(int fd, int mod, int key) { - static int prevcode = -1; int code = keycode[(mod & MOD_FN) | (key & KEY_ASCII)] | ((mod << 8) & MOD_ALT); - if (prevcode >= 0) + if (prevkeycode >= 0) { - sendkeycodeup(fd, prevcode); - if (!(key & KEY_PRESS) && ((code & KEY_CODE) != (prevcode & KEY_CODE))) + sendkeycodeup(fd, prevkeycode); + if (!(key & KEY_PRESS) && ((code & KEY_CODE) != (prevkeycode & KEY_CODE))) /* * missed a key down event * synthesize one @@ -408,7 +408,10 @@ void sendkey(int fd, int mod, int key) */ sendkeycodeup(fd, code); } - prevcode = (key & KEY_PRESS) ? code : -1; + prevkeycode = (key & KEY_PRESS) ? code : -1; +} +void flushkey(int fd) +{ } void sendbttn(int fd, int mod, int bttn) { @@ -887,6 +890,11 @@ reset: state = RESET; newtio.c_cc[VMIN] = 3; /* blocking read until 3 chars received */ tcsetattr(a2fd, TCSANOW, &newtio); + if (prevkeycode >= 0) + { + sendkeycodeup(kbdfd, prevkeycode); + prevkeycode = -1; + } } else state = RESET; diff --git a/src/bload.c b/src/bload.c index 693517b..3d83506 100755 --- a/src/bload.c +++ b/src/bload.c @@ -25,7 +25,6 @@ int main(int argc, char **argv) a2close(pifd); exit(EXIT_FAILURE); } - sleep(1); fflush(stdin); if ((binfile = fopen(argv[1], "rb"))) { diff --git a/src/brun.c b/src/brun.c index 93befe1..15aee77 100755 --- a/src/brun.c +++ b/src/brun.c @@ -26,7 +26,6 @@ int main(int argc, char **argv) a2close(pifd); exit(EXIT_FAILURE); } - sleep(1); fflush(stdin); if ((binfile = fopen(argv[1], "rb"))) { diff --git a/src/dskread.c b/src/dskread.c index 83279be..c5f2032 100755 --- a/src/dskread.c +++ b/src/dskread.c @@ -41,7 +41,6 @@ int main(int argc, char **argv) perror("Unable to connect to Apple II Pi"); exit(EXIT_FAILURE); } - sleep(1); a2write(pifd, ORG, sizeof(online), online); a2call(pifd, ORG, &result); a2read(pifd, DATA_BUFFER, 16, volname); diff --git a/src/dskwrite.c b/src/dskwrite.c index 064c0d4..a03bc7b 100755 --- a/src/dskwrite.c +++ b/src/dskwrite.c @@ -46,7 +46,6 @@ int main(int argc, char **argv) perror("Usage: dskwrite [ip address]\n"); exit(EXIT_FAILURE); } - sleep(1); fflush(stdin); a2write(pifd, ORG, sizeof(online), online); a2call(pifd, ORG, &result); diff --git a/src/fusea2pi.c b/src/fusea2pi.c new file mode 100755 index 0000000..ec72996 --- /dev/null +++ b/src/fusea2pi.c @@ -0,0 +1,780 @@ +#define FUSE_USE_VERSION 26 +#include "a2lib.c" +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SETXATTR +#include +#endif + +/* + * ProDOS Commands. + */ +#define PRODOS_CREATE 0xC0 +#define PRODOS_DESTROY 0xC1 +#define PRODOS_RENAME 0xC2 +#define PRODOS_SET_FILE_INFO 0xC3 +#define PRODOS_GET_FILE_INFO 0xC4 +#define PRODOS_ON_LINE 0xC5 +#define PRODOS_SET_PREFIX 0xC6 +#define PRODOS_GET_PREFIX 0xC7 +#define PRODOS_OPEN 0xC8 +#define PRODOS_NEWLINE 0xC9 +#define PRODOS_READ 0xCA +#define PRODOS_WRITE 0xCB +#define PRODOS_CLOSE 0xCC +#define PRODOS_FLUSH 0xCD +#define PRODOS_SET_MARK 0xCE +#define PRODOS_MARK 0xCF +#define PRODOS_SET_EOF 0xD0 +#define PRODOS_GET_EOF 0xD1 +#define PRODOS_SET_BUF 0xD2 +#define PRODOS_GET_BUF 0xD3 +#define PRODOS_READ_BLOCK 0x80 +#define PRODOS_WRITE_BLOCK 0x81 +/* + * ProDOS Errors. + */ +#define PRODOS_OK 0x00 +#define PRODOS_ERR_BAD_CMD 0x01 +#define PRODOS_ERR_BAD_COUNT 0x04 +#define PRODOS_ERR_INT_TBL_FULL 0x25 +#define PRODOS_ERR_IO 0x27 +#define PRODOS_ERR_NO_DEV 0x28 +#define PRODOS_ERR_WR_PROT 0x2B +#define PRODOS_ERR_DSK_SWITCH 0x2E +#define PRODOS_ERR_INVLD_PATH 0x40 +#define PRODOS_ERR_FCB_FULL 0x42 +#define PRODOS_ERR_INVLD_REFNUM 0x43 +#define PRODOS_ERR_PATH_NOT_FND 0x44 +#define PRODOS_ERR_VOL_NOT_FND 0x45 +#define PRODOS_ERR_FILE_NOT_FND 0x46 +#define PRODOS_ERR_DUP_FILENAME 0x47 +#define PRODOS_ERR_OVERRUN 0x48 +#define PRODOS_ERR_VOL_DIR_FULL 0x49 +#define PRODOS_ERR_INCOMPAT_FMT 0x4A +#define PRODOS_ERR_UNSUPP_TYPE 0x4B +#define PRODOS_ERR_EOF 0x4C +#define PRODOS_ERR_POS_RANGE 0x4D +#define PRODOS_ERR_ACCESS 0x4E +#define PRODOS_ERR_FILE_OPEN 0x50 +#define PRODOS_ERR_DIR_COUNT 0x51 +#define PRODOS_ERR_NOT_PRODOS 0x52 +#define PRODOS_ERR_INVLD_PARAM 0x53 +#define PRODOS_ERR_VCB_FULL 0x55 +#define PRODOS_ERR_BAD_BUF_ADDR 0x56 +#define PRODOS_ERR_DUP_VOL 0x57 +#define PRODOS_ERR_BAD_BITMAP 0x5A +#define PRODOS_ERR_UNKNOWN 0x100 +/* + * ProDOS call template. + */ +#define PRODOS_CALL 0x0300 +#define PRODOS_CALL_LEN 0x08 +#define PRODOS_CMD 0x03 +#define PRODOS_PARAMS 0x07 +#define PRODOS_PARAM_CNT 0x07 +#define PRODOS_PARAM_BUFFER (PRODOS_CALL+PRODOS_PARAMS) +#define PRODOS_DATA_BUFFER 0x4000 +#define PRODOS_DATA_BUFFER_LEN 0x2000 +#define PRODOS_IO_BUFFER 0x6000 +#define PRODOS_IO_BUFFER_LEN 0x0400 +#define PRODOS_IO_BUFFER_NUM 8 +static unsigned char prodos[32] = { +// ORG @ $300 + 0x20, 0x00, 0xBF, // JSR $BF00 (PRODOS) + 0x00, // DB CMD + 0x07, 0x03, // DW PARAMS + 0x60, // RTS +// PARAMS @ $307 + 0x00 // PARAM_COUNT +}; +/* + * Apple II Pi connection. + */ +static int pifd = 0; +/* + * ProDOS calls to Apple II Pi. + */ +static int io_buff_mask = 0; +static int prodos_alloc_io_buff(void) +{ + int i; + for (i = 0; i < PRODOS_IO_BUFFER_NUM; i++) + if ((io_buff_mask & (1 << i)) == 0) + { + io_buff_mask |= (1 << i); + return (PRODOS_IO_BUFFER + PRODOS_IO_BUFFER_LEN * i); + } + return 0; +} +static int prodos_free_io_buff(int buf) +{ + if (buf < PRODOS_IO_BUFFER || buf > (PRODOS_IO_BUFFER + PRODOS_IO_BUFFER_LEN * PRODOS_IO_BUFFER_NUM)) + return -1; + int i = (buf - PRODOS_IO_BUFFER) / PRODOS_IO_BUFFER_LEN; + io_buff_mask &= ~(1 << i); + return i; +} +static int prodos_open(const char *path, int *io_buff) +{ + char prodos_path[65], refnum = 0; + int result; + + prodos_path[0] = strlen(path); + if (path[0] > 64) + return -PRODOS_ERR_INVLD_PATH; + strcpy(prodos_path+1, path); + a2write(pifd, PRODOS_DATA_BUFFER, prodos_path[0] + 1, prodos_path); + if (*io_buff == 0) + { + if ((*io_buff = prodos_alloc_io_buff()) == 0) + return -PRODOS_ERR_FCB_FULL; + } + prodos[PRODOS_CMD] = PRODOS_OPEN; + prodos[PRODOS_PARAM_CNT] = 3; + prodos[PRODOS_PARAMS + 1] = (unsigned char) PRODOS_DATA_BUFFER; + prodos[PRODOS_PARAMS + 2] = (unsigned char) (PRODOS_DATA_BUFFER >> 8); + prodos[PRODOS_PARAMS + 3] = (unsigned char) *io_buff; + prodos[PRODOS_PARAMS + 4] = (unsigned char) (*io_buff >> 8); + prodos[PRODOS_PARAMS + 5] = 0; + a2write(pifd, PRODOS_CALL, PRODOS_CALL_LEN + 5, prodos); + if (a2call(pifd, PRODOS_CALL, &result)) + { + if (result == 0) + { + a2read(pifd, PRODOS_PARAM_BUFFER + 5, 1, &refnum); + return refnum; + } + return -result; + } + return -PRODOS_ERR_UNKNOWN; +} +static int prodos_close(int refnum, int *io_buff) +{ + int result; + + if (io_buff && *io_buff != 0) + { + prodos_free_io_buff(*io_buff); + *io_buff = 0; + } + prodos[PRODOS_CMD] = PRODOS_CLOSE; + prodos[PRODOS_PARAM_CNT] = 1; + prodos[PRODOS_PARAMS + 1] = refnum; + a2write(pifd, PRODOS_CALL, PRODOS_CALL_LEN + 1, prodos); + if (a2call(pifd, PRODOS_CALL, &result)) + return -result; + return -PRODOS_ERR_UNKNOWN; +} +static int prodos_read(int refnum, char *data_buff, int req_xfer) +{ + int result, short_req, short_xfer, total_xfer = 0; + + prodos[PRODOS_CMD] = PRODOS_READ; + prodos[PRODOS_PARAM_CNT] = 4; + prodos[PRODOS_PARAMS + 1] = refnum; + while (req_xfer) + { + short_req = (req_xfer > PRODOS_DATA_BUFFER_LEN) ? PRODOS_DATA_BUFFER_LEN : req_xfer; + prodos[PRODOS_PARAMS + 2] = (unsigned char) PRODOS_DATA_BUFFER; + prodos[PRODOS_PARAMS + 3] = (unsigned char) (PRODOS_DATA_BUFFER >> 8); + prodos[PRODOS_PARAMS + 4] = (unsigned char) short_req; + prodos[PRODOS_PARAMS + 5] = (unsigned char) (short_req >> 8); + prodos[PRODOS_PARAMS + 6] = 0; + prodos[PRODOS_PARAMS + 7] = 0; + a2write(pifd, PRODOS_CALL, PRODOS_CALL_LEN + 7, prodos); + if (a2call(pifd, PRODOS_CALL, &result)) + { + if (result == 0) + { + a2read(pifd, PRODOS_PARAM_BUFFER + 6, 2, prodos + PRODOS_PARAMS + 6); + if ((short_xfer = (unsigned char) prodos[PRODOS_PARAMS + 6] + (unsigned char)prodos[PRODOS_PARAMS + 7] * 256) > 0) + a2read(pifd, PRODOS_DATA_BUFFER, short_xfer, data_buff + total_xfer); + req_xfer -= short_xfer; + total_xfer += short_xfer; + } + else + return -result; + } + else + return -PRODOS_ERR_UNKNOWN; + } + return total_xfer; +} +static int prodos_write(int refnum, char *data_buff, int req_xfer) +{ + int result, short_req, short_xfer, total_xfer = 0; + + prodos[PRODOS_CMD] = PRODOS_WRITE; + prodos[PRODOS_PARAM_CNT] = 4; + prodos[PRODOS_PARAMS + 1] = refnum; + while (req_xfer) + { + short_req = (req_xfer > PRODOS_DATA_BUFFER_LEN) ? PRODOS_DATA_BUFFER_LEN : req_xfer; + a2write(pifd, PRODOS_DATA_BUFFER, short_req, data_buff + total_xfer); + prodos[PRODOS_PARAMS + 2] = (unsigned char) PRODOS_DATA_BUFFER; + prodos[PRODOS_PARAMS + 3] = (unsigned char) (PRODOS_DATA_BUFFER >> 8); + prodos[PRODOS_PARAMS + 4] = (unsigned char) short_req; + prodos[PRODOS_PARAMS + 5] = (unsigned char) (short_req >> 8); + prodos[PRODOS_PARAMS + 6] = 0; + prodos[PRODOS_PARAMS + 7] = 0; + a2write(pifd, PRODOS_CALL, PRODOS_CALL_LEN + 7, prodos); + if (a2call(pifd, PRODOS_CALL, &result)) + { + if (result == 0) + { + a2read(pifd, PRODOS_PARAM_BUFFER + 6, 2, prodos + PRODOS_PARAMS + 6); + short_xfer = (unsigned char) prodos[PRODOS_PARAMS + 6] + (unsigned char)prodos[PRODOS_PARAMS + 7] * 256; + req_xfer -= short_xfer; + total_xfer += short_xfer; + } + else + return -result; + } + else + return -PRODOS_ERR_UNKNOWN; + } + return total_xfer; +} +static int prodos_set_mark(int refnum, int position) +{ + int result; + + prodos[PRODOS_CMD] = PRODOS_SET_MARK; + prodos[PRODOS_PARAM_CNT] = 2; + prodos[PRODOS_PARAMS + 1] = (unsigned char) refnum; + prodos[PRODOS_PARAMS + 2] = (unsigned char) position; + prodos[PRODOS_PARAMS + 3] = (unsigned char) (position >> 8); + prodos[PRODOS_PARAMS + 4] = (unsigned char) (position >> 16); + a2write(pifd, PRODOS_CALL, PRODOS_CALL_LEN + 4, prodos); + if (a2call(pifd, PRODOS_CALL, &result)) + return -result; + return -PRODOS_ERR_UNKNOWN; +} +static int prodos_set_eof(int refnum, int position) +{ + int result; + + prodos[PRODOS_CMD] = PRODOS_SET_EOF; + prodos[PRODOS_PARAM_CNT] = 2; + prodos[PRODOS_PARAMS + 1] = (unsigned char) refnum; + prodos[PRODOS_PARAMS + 2] = (unsigned char) position; + prodos[PRODOS_PARAMS + 3] = (unsigned char) (position >> 8); + prodos[PRODOS_PARAMS + 4] = (unsigned char) (position >> 16); + a2write(pifd, PRODOS_CALL, PRODOS_CALL_LEN + 4, prodos); + if (a2call(pifd, PRODOS_CALL, &result)) + return -result; + return -PRODOS_ERR_UNKNOWN; +} +static int prodos_get_eof(int refnum) +{ + int position, result; + + prodos[PRODOS_CMD] = PRODOS_GET_EOF; + prodos[PRODOS_PARAM_CNT] = 2; + prodos[PRODOS_PARAMS + 1] = (unsigned char) refnum; + prodos[PRODOS_PARAMS + 2] = 0; + prodos[PRODOS_PARAMS + 3] = 0; + prodos[PRODOS_PARAMS + 4] = 0; + a2write(pifd, PRODOS_CALL, PRODOS_CALL_LEN + 4, prodos); + if (a2call(pifd, PRODOS_CALL, &result)) + { + if (result == 0) + { + a2read(pifd, PRODOS_PARAM_BUFFER + 2, 3, prodos + PRODOS_PARAMS + 2); + position = prodos[PRODOS_PARAMS + 2] + + (prodos[PRODOS_PARAMS + 3] << 8) + + (prodos[PRODOS_PARAMS + 4] << 16); + return position; + } + return -result; + } + return -PRODOS_ERR_UNKNOWN; +} +static int prodos_on_line(char *data_buff) +{ + int result; + + prodos[PRODOS_CMD] = PRODOS_ON_LINE; + prodos[PRODOS_PARAM_CNT] = 2; + prodos[PRODOS_PARAMS + 1] = 0; + prodos[PRODOS_PARAMS + 2] = (unsigned char) PRODOS_DATA_BUFFER; + prodos[PRODOS_PARAMS + 3] = (unsigned char) (PRODOS_DATA_BUFFER >> 8); + a2write(pifd, PRODOS_CALL, PRODOS_CALL_LEN + 3, prodos); + if (a2call(pifd, PRODOS_CALL, &result)) + { + if (result == 0) + a2read(pifd, PRODOS_DATA_BUFFER, 256, data_buff); + return -result; + } + return -PRODOS_ERR_UNKNOWN; +} +static int prodos_get_file_info(const char *path, int *access, int *type, int *aux, int *storage, int *numblks, int *mod, int *create) +{ + char prodos_path[65]; + int result; + + prodos_path[0] = strlen(path); + if (prodos_path[0] > 64) + return -PRODOS_ERR_INVLD_PATH; + strcpy(prodos_path+1, path); + a2write(pifd, PRODOS_DATA_BUFFER, prodos_path[0] + 1, prodos_path); + prodos[PRODOS_CMD] = PRODOS_GET_FILE_INFO; + prodos[PRODOS_PARAM_CNT] = 10; + prodos[PRODOS_PARAMS + 1] = (unsigned char) PRODOS_DATA_BUFFER; + prodos[PRODOS_PARAMS + 2] = (unsigned char) (PRODOS_DATA_BUFFER >> 8); + prodos[PRODOS_PARAMS + 3] = 0; + prodos[PRODOS_PARAMS + 4] = 0; + prodos[PRODOS_PARAMS + 5] = 0; + prodos[PRODOS_PARAMS + 6] = 0; + prodos[PRODOS_PARAMS + 7] = 0; + prodos[PRODOS_PARAMS + 8] = 0; + prodos[PRODOS_PARAMS + 9] = 0; + prodos[PRODOS_PARAMS + 10] = 0; + prodos[PRODOS_PARAMS + 11] = 0; + prodos[PRODOS_PARAMS + 12] = 0; + prodos[PRODOS_PARAMS + 13] = 0; + prodos[PRODOS_PARAMS + 14] = 0; + prodos[PRODOS_PARAMS + 15] = 0; + prodos[PRODOS_PARAMS + 16] = 0; + prodos[PRODOS_PARAMS + 17] = 0; + a2write(pifd, PRODOS_CALL, PRODOS_CALL_LEN + 17, prodos); + if (a2call(pifd, PRODOS_CALL, &result)) + { + if (result == 0) + { + a2read(pifd, PRODOS_PARAM_BUFFER + 3, 15, prodos + PRODOS_PARAMS + 3); + *access = prodos[PRODOS_PARAMS + 3]; + *type = prodos[PRODOS_PARAMS + 4]; + *aux = prodos[PRODOS_PARAMS + 5] + + (prodos[PRODOS_PARAMS + 6] << 8); + *storage = prodos[PRODOS_PARAMS + 7]; + *numblks = prodos[PRODOS_PARAMS + 8] + + (prodos[PRODOS_PARAMS + 9] << 8); + *mod = prodos[PRODOS_PARAMS + 10] + + (prodos[PRODOS_PARAMS + 11] << 8) + + (prodos[PRODOS_PARAMS + 12] << 16) + + (prodos[PRODOS_PARAMS + 13] << 24); + *create = prodos[PRODOS_PARAMS + 14] + + (prodos[PRODOS_PARAMS + 15] << 8) + + (prodos[PRODOS_PARAMS + 16] << 16) + + (prodos[PRODOS_PARAMS + 17] << 24); + } + return -result; + } + return -PRODOS_ERR_UNKNOWN; +} +static int prodos_rename(const char *filename, const char *new_filename) +{ + char prodos_path[65]; + int result; + + prodos_path[0] = strlen(filename); + if (prodos_path[0] > 64) + return -PRODOS_ERR_INVLD_PATH; + strcpy(prodos_path+1, filename); + a2write(pifd, PRODOS_DATA_BUFFER, prodos_path[0] + 1, prodos_path); + prodos_path[0] = strlen(new_filename); + if (prodos_path[0] > 64) + return -PRODOS_ERR_INVLD_PATH; + strcpy(prodos_path+1, new_filename); + a2write(pifd, PRODOS_DATA_BUFFER+256, prodos_path[0] + 1, prodos_path); + prodos[PRODOS_CMD] = PRODOS_RENAME; + prodos[PRODOS_PARAM_CNT] = 2; + prodos[PRODOS_PARAMS + 1] = (unsigned char) PRODOS_DATA_BUFFER; + prodos[PRODOS_PARAMS + 2] = (unsigned char) (PRODOS_DATA_BUFFER >> 8); + prodos[PRODOS_PARAMS + 3] = (unsigned char) (PRODOS_DATA_BUFFER + 256); + prodos[PRODOS_PARAMS + 4] = (unsigned char) (PRODOS_DATA_BUFFER + 256) >> 8; + a2write(pifd, PRODOS_CALL, PRODOS_CALL_LEN + 4, prodos); + if (a2call(pifd, PRODOS_CALL, &result)) + return -result; + return -PRODOS_ERR_UNKNOWN; +} +static int prodos_destroy(char *path) +{ + char prodos_path[65]; + int result; + + prodos_path[0] = strlen(path); + if (prodos_path[0] > 64) + return -PRODOS_ERR_INVLD_PATH; + strcpy(prodos_path+1, path); + a2write(pifd, PRODOS_DATA_BUFFER, prodos_path[0] + 1, prodos_path); + prodos[PRODOS_CMD] = PRODOS_DESTROY; + prodos[PRODOS_PARAM_CNT] = 1; + prodos[PRODOS_PARAMS + 1] = (unsigned char) PRODOS_DATA_BUFFER; + prodos[PRODOS_PARAMS + 2] = (unsigned char) (PRODOS_DATA_BUFFER >> 8); + a2write(pifd, PRODOS_CALL, PRODOS_CALL_LEN + 2, prodos); + if (a2call(pifd, PRODOS_CALL, &result)) + return -result; + return -PRODOS_ERR_UNKNOWN; +} +static int prodos_create(const char *path, char access, char type, int aux, int create) +{ + char prodos_path[65]; + int result; + + prodos_path[0] = strlen(path); + if (prodos_path[0] > 64) + return -PRODOS_ERR_INVLD_PATH; + strcpy(prodos_path+1, path); + a2write(pifd, PRODOS_DATA_BUFFER, prodos_path[0] + 1, prodos_path); + prodos[PRODOS_CMD] = PRODOS_CREATE; + prodos[PRODOS_PARAM_CNT] = 7; + prodos[PRODOS_PARAMS + 1] = (unsigned char) PRODOS_DATA_BUFFER; + prodos[PRODOS_PARAMS + 2] = (unsigned char) (PRODOS_DATA_BUFFER >> 8); + prodos[PRODOS_PARAMS + 3] = (unsigned char) access; + prodos[PRODOS_PARAMS + 4] = (unsigned char) type; + prodos[PRODOS_PARAMS + 5] = (unsigned char) aux; + prodos[PRODOS_PARAMS + 6] = (unsigned char) (aux >> 8); + prodos[PRODOS_PARAMS + 7] = type == 0x0F ? 0x0D : 0x01; // directory if type == 0x0F + prodos[PRODOS_PARAMS + 8] = (unsigned char) create; + prodos[PRODOS_PARAMS + 9] = (unsigned char) (create >> 8); + prodos[PRODOS_PARAMS + 10] = (unsigned char) (create >> 16); + prodos[PRODOS_PARAMS + 11] = (unsigned char) (create >> 24); + a2write(pifd, PRODOS_CALL, PRODOS_CALL_LEN + 11, prodos); + if (a2call(pifd, PRODOS_CALL, &result)) + return -result; + return -PRODOS_ERR_UNKNOWN; +} +/* + * FUSE functions. + */ +static int basenamelen(const char *path) +{ + int i, l = strlen(path); + for (i = l - 1; i >= 0 && path[i] != '/'; i--); + return l - i - 1; +} +static int a2pi_getattr(const char *path, struct stat *stbuf) +{ + int access, type, aux, storage, numblks, mod, create, refnum, io_buff = 0; + memset(stbuf, 0, sizeof(struct stat)); + if (strcmp(path, "/") == 0) + { + /* + * Root directory of volumes. + */ + stbuf->st_mode = S_IFDIR | 0777; + stbuf->st_nlink = 2; + } + else + { + /* + * Get file info. + */ + if (prodos_get_file_info(path, &access, &type, &aux, &storage, &numblks, &mod, &create) == 0) + { + printf("prodos access = $%02X, type = $%02X, aux = $%04X, storage = $%02X\n", access, type, aux, storage); + if (storage == 0x0F || storage == 0x0D) + { + stbuf->st_mode = (access & 0xC3 == 0xC3) ? S_IFDIR | 0777 : S_IFDIR | 0444; + stbuf->st_nlink = 2; + } + else + { + stbuf->st_mode = (access & 0xC3 == 0xC3) ? S_IFREG | 0666 : S_IFREG | 0444; + stbuf->st_nlink = 1; + stbuf->st_blksize = 512; + stbuf->st_blocks = numblks; + #if 0 + stbuf->st_size = numblks * 512; + #else + if ((refnum = prodos_open(path, &io_buff) > 0)) + { + stbuf->st_size = prodos_get_eof(refnum); + prodos_close(refnum, &io_buff); + } + else + return -PRODOS_ERR_UNKNOWN; +#endif + } + } + else + return -ENOENT; + } + return 0; +} + +static int a2pi_access(const char *path, int mask) +{ + return 0; +} + +static int a2pi_readdir(const char *path, void *buf, fuse_fill_dir_t filler, + off_t offset, struct fuse_file_info *fi) +{ + unsigned char data_buff[512], filename[16], *entry, type; + int i, l, refnum, firstblk, entrylen, entriesblk, filecnt, io_buff = 0; + (void) offset; + (void) fi; + + if (strcmp(path, "/") == 0) + { + /* + * Root directory, fill with volume names. + */ + filler(buf, ".", NULL, 0); + filler(buf, "..", NULL, 0); + if (prodos_on_line(data_buff) == 0) + { + for (i = 0; i < 256; i += 16) + if ((l = data_buff[i] & 0x0F)) + { + strncpy(filename, data_buff + i + 1, l); + filename[l] = '\0'; + filler(buf, filename, NULL, 0); + } + } + else + return -ENOENT; + } + else + { + /* + * Read ProDOS directory. + */ + printf("Read ProDOS directory %s\n", path); + if ((refnum = prodos_open(path, &io_buff)) > 0) + { + firstblk = 1; + do + { + if (prodos_read(refnum, data_buff, 512) == 512) + { + entry = data_buff + 4; + if (firstblk) + { + entrylen = data_buff[0x23]; + entriesblk = data_buff[0x24]; + filecnt = data_buff[0x25] + data_buff[0x26] * 256; + entry = entry + entrylen; + } + for (i = firstblk; i < entriesblk; i++) + { + if ((type = entry[0]) != 0) + { + l = type & 0x0F; + strncpy(filename, entry + 1, l); + filename[l] = '\0'; + filler(buf, filename, NULL, 0); + // if type & $F0 == $D0 ; Is it a directory? + filecnt = filecnt - 1; + entry += entrylen; + } + } + firstblk = 0; + } + else + filecnt = 0; + } while (filecnt != 0); + prodos_close(refnum, &io_buff); + } + else + return -ENOENT; + } + return 0; +} + +static int a2pi_mkdir(const char *path, mode_t mode) +{ + int res; + + res = mkdir(path, mode); + if (res == -1) + return -errno; + + return 0; +} + +static int a2pi_unlink(const char *path) +{ + int res; + + res = unlink(path); + if (res == -1) + return -errno; + + return 0; +} + +static int a2pi_rmdir(const char *path) +{ + int res; + + res = rmdir(path); + if (res == -1) + return -errno; + + return 0; +} + +static int a2pi_rename(const char *from, const char *to) +{ + int res; + + res = rename(from, to); + if (res == -1) + return -errno; + + return 0; +} + +static int a2pi_chmod(const char *path, mode_t mode) +{ + int res; + + res = chmod(path, mode); + if (res == -1) + return -errno; + + return 0; +} + +static int a2pi_truncate(const char *path, off_t size) +{ + int res; + + res = truncate(path, size); + if (res == -1) + return -errno; + + return 0; +} + +static int a2pi_open(const char *path, struct fuse_file_info *fi) +{ + int res; + + res = open(path, fi->flags); + if (res == -1) + return -errno; + + close(res); + return 0; +} + +static int a2pi_read(const char *path, char *buf, size_t size, off_t offset, + struct fuse_file_info *fi) +{ + int fd; + int res; + + (void) fi; + fd = open(path, O_RDONLY); + if (fd == -1) + return -errno; + + res = pread(fd, buf, size, offset); + if (res == -1) + res = -errno; + + close(fd); + return res; +} + +static int a2pi_write(const char *path, const char *buf, size_t size, + off_t offset, struct fuse_file_info *fi) +{ + int fd; + int res; + + (void) fi; + fd = open(path, O_WRONLY); + if (fd == -1) + return -errno; + + res = pwrite(fd, buf, size, offset); + if (res == -1) + res = -errno; + + close(fd); + return res; +} + +static int a2pi_statfs(const char *path, struct statvfs *stbuf) +{ + int res; + + res = statvfs(path, stbuf); + if (res == -1) + return -errno; + + return 0; +} + +#ifdef HAVE_SETXATTR +/* xattr operations are optional and can safely be left unimplemented */ +static int a2pi_setxattr(const char *path, const char *name, const char *value, + size_t size, int flags) +{ + int res = lsetxattr(path, name, value, size, flags); + if (res == -1) + return -errno; + return 0; +} + +static int a2pi_getxattr(const char *path, const char *name, char *value, + size_t size) +{ + int res = lgetxattr(path, name, value, size); + if (res == -1) + return -errno; + return res; +} + +static int a2pi_listxattr(const char *path, char *list, size_t size) +{ + int res = llistxattr(path, list, size); + if (res == -1) + return -errno; + return res; +} + +static int a2pi_removexattr(const char *path, const char *name) +{ + int res = lremovexattr(path, name); + if (res == -1) + return -errno; + return 0; +} +#endif /* HAVE_SETXATTR */ + +static struct fuse_operations a2pi_oper = { + .getattr = a2pi_getattr, + .access = a2pi_access, + .readdir = a2pi_readdir, + .mkdir = a2pi_mkdir, + .unlink = a2pi_unlink, + .rmdir = a2pi_rmdir, + .rename = a2pi_rename, + .chmod = a2pi_chmod, + .truncate = a2pi_truncate, + .open = a2pi_open, + .read = a2pi_read, + .write = a2pi_write, + .statfs = a2pi_statfs, +#ifdef HAVE_SETXATTR + .setxattr = a2pi_setxattr, + .getxattr = a2pi_getxattr, + .listxattr = a2pi_listxattr, + .removexattr = a2pi_removexattr, +#endif +}; + +int main(int argc, char *argv[]) +{ + pifd = a2open("127.0.0.1"); + if (pifd < 0) + { + perror("Unable to connect to Apple II Pi"); + exit(EXIT_FAILURE); + } + prodos_close(0, NULL); + umask(0); + return fuse_main(argc, argv, &a2pi_oper, NULL); +}