From f902991dada2b342b984e096594ab6ecb433c9fc Mon Sep 17 00:00:00 2001 From: dschmenk Date: Sat, 7 Sep 2013 11:11:08 -0700 Subject: [PATCH] Fix date formats --- src/fusea2pi | Bin 0 -> 26157 bytes src/fusea2pi.c | 8 +- src/fusea2pi.c~ | 1110 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1116 insertions(+), 2 deletions(-) create mode 100755 src/fusea2pi create mode 100755 src/fusea2pi.c~ diff --git a/src/fusea2pi b/src/fusea2pi new file mode 100755 index 0000000000000000000000000000000000000000..882ffab8a117ed5fed47c8f1a77002df0467de53 GIT binary patch literal 26157 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
CwADX7C~?s@ zJp}RBGs?@X{#kA`0wP?w>Wz_Wkjgn!I5|zr*JJf1^7T0Fb8ZPP^6hiVZ$UZr%YOQx zU#2pCXi2SdaCj#zFJpLfO;(==Ah_^9>Xefo{iM03tNR_?2YX?Oj4vaDCoLrt_Lt?e zM)eWY?H|wN|3#@ZS(keb&iedr*<3}6exA686eoA8XOZ%mkK-WyCvL7Q6hmD;uWm-l za*EQ=a?jxZNc=Ov_5W9>e+J%+#S>@2!TKg^e|!{p0_CEg=%1lbUz61tq&&NZmQMbZ zqtPk6J;Lv`oha1TWQA|i6we{41upzvcgl-VPJAEAS^qlV+rET3 zf>ikR?=svtA4162=O;M)hMn@8P)>Ze5CkE9q5V2 zk&1jhUrDFm?%*AuBYp}bLSO&q>GX{b&IeQC!w&!2htug-JNN^jBYwo8FW8$-U+Um{ zKu6q_XV@v{c%O6d{h%lA(jVhs>C5QzRR{kL=!xUmWVFA-kEGKp221*ytX={g@$*PT zKWCkC%5&bq{|WTOw>$hdCqSexBhR*kMPV;Ppd)_FvCqX{8!IRORSwPxPQ1|JU;lVI zeWQa<0$<|CK_c>po=B&!a_~~n6L;l5H0orG{6`%8L!c+lc_jRgem$N4aR*-jdg8A9 zr}n4QpLXy&Ku^3GiV*&#f0<5S`qyK4J?QIzpBV4ZKQmSiHfrp-eX@#!o_L)jfAhD} z>G`Z}uE}Z(=!u_02IbiSoX_V+$2sjC8lz`>+!rv{Wc5|h6F-Iw>5q1rn!xCndkE&5 zteyZp@ioX0`ZZ2D`O7{7{m;{&C%(y{KaoK%`w^sn4)nxxo&KNtzGf@*iGS9}fN&=(+C^ zbmR>lHq=7TJrQ%6_@&Ol*&o?2A-&I!`G@jGm)}cc^?7y#_chsHt~#vGb2QCm`0sac zmh+5Fx4e*xpuS9hcowJNnehtyFYzLG)GkN+g8P88T;ds?#(XWx1!sIS7x-8_GF>eK zF7YEyURBG0yYa=RNpIJCAEGD9FYzy*aM_*?LYM+)dG7rh(Rdv7*&pUlgFbtJOF5(6 zuK<^L(1ZRS11|AP5b?@Wz=M__>7NH)>frwf+&$wMhYYI4%~~o%n{SM~0o>(x4!C>9 zasYx!{5TEq;bh=${bJzNPJ15)?w*N!6Y$ke`5nL+Ptjknzn=tN`heLhA^vIL(%&HZ zyB>JdslN?)yMsRhTrLm50pJp!PR%J&-v#cTDg8s>jJH{BDl~8cfO|&t5OCUmHOeW^ zuYuDZ>n%P3e(C@=7ZzLjrvpzo@>~m?`-qHhSbrXHS6?@Ec=bSHO=uL-$AG(M zh^w-wDvKx_Ki%w{m#rE);+^pg>(*5?;0)@eH7mo*m)yCEr)Y3}ZvGW24ghn&Ie%mX?jE;$UI!jHZ*~ zpzg@L_9lqaj!n|GPSxJDE()m|8e{E|c%y;zw&y)<%^O;hCZ!~1 zpP1%413~j8wEA*vIL{3;kD@Ss7zYm^sJUhdl)CAx3-yq38y#8 zkz^LPqm@P?4GnnvWneZCZL$R|>qo(kSWDYIF`>~Ts_Qm1wzNe}cD!RlYXjc98BA+i zlW6s7$SBv;L#~kGkofpI+diswz#ea1xp2iT;ahHBtgW6?K;Sg%jH>YBKe~P4iX}Cu zlDYmKrmF+ELa%xM(*4TNdT5b6W(T@rKVy_*9w z!KwFdPGp|dx=}RTh1-*i!|dIPqbK0InVCoUhohZs;l@a7v^k~^X6*MC{Syn%MP>AySRW 99) + year -= 100; + month += 1; return (day & 0x1F) | ((month & 0x0F) << 5) | ((year & 0x7F) << 9) | ((minute & 0x3F) << 16) | ((hour & 0x1F) << 24); } @@ -182,11 +185,12 @@ static time_t unix_time(unsigned int ptime) memset(&tm, 0, sizeof(struct tm)); tm.tm_mday = ptime & 0x1F; tm.tm_mon = (ptime >> 5) & 0x0F; - tm.tm_year = (ptime >> 9) & 0x7F + 1900; + tm.tm_year = (ptime >> 9) & 0x7F; tm.tm_min = (ptime >> 16) & 0x3F; tm.tm_hour = (ptime >> 24) & 0x1F; - if (tm.tm_year < 1980) + if (tm.tm_year < 80) tm.tm_year += 100; + tm.tm_mon -= 1; return mktime(&tm); } struct stat *unix_stat(struct stat *stbuf, int storage, int access, int blocks, int size, int mod, int create) diff --git a/src/fusea2pi.c~ b/src/fusea2pi.c~ new file mode 100755 index 0000000..4c04685 --- /dev/null +++ b/src/fusea2pi.c~ @@ -0,0 +1,1110 @@ +#define FUSE_USE_VERSION 26 +#include "a2lib.c" +#include +#include +#include +#include +#include +#include + +/* + * 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; +/* + * Cached directory blocks. + */ +#define CACHE_BLOCKS_MAX 16 +static char cachepath[128] = ""; +static unsigned char cachedata[512][CACHE_BLOCKS_MAX]; /* !!! Is this enough !!! */ +static unsigned char volumes[256]; +/* + * Filename & date/time conversion routines. + */ +static char hexchar(int h) +{ + h &= 0x0F; + if (h > 9) + h += 'A' - 10; + else + h += '0'; + return (char) h; +} +static char *unix_name(unsigned char *pname, int type, int aux, char *uname) +{ + int l; + static char filename[24]; + if (uname == NULL) + uname = filename; + l = pname[0] & 0x0F; + strncpy(uname, pname + 1, l); + if (type != 0x0F) /* Directory type */ + { + uname[l + 0] = '#'; + uname[l + 1] = hexchar(type >> 4); + uname[l + 2] = hexchar(type); + uname[l + 3] = hexchar(aux >> 12); + uname[l + 4] = hexchar(aux >> 8); + uname[l + 5] = hexchar(aux >> 4); + uname[l + 6] = hexchar(aux); + uname[l + 7] = '\0'; + } + else + uname[l] = '\0'; + return uname; +} +static int hexval(char h) +{ + if (h >= 'a') + h -= 'a' - 10; + else if (h >= 'A') + h -= 'A' - 10; + else + h -= '0'; + return h; +} +static unsigned char *prodos_path(const char *uname, int *type, int *aux, unsigned char *pname) +{ + static unsigned char filename[72]; + int l = strlen(uname); + if (type) + *type = 0; + if (aux) + *aux = 0; + if (pname == NULL) + pname = filename; + if (l > 7 && uname[l - 7] == '#') + { + if (type) + *type = hexval(uname[l - 6]) * 16 + hexval(uname[l - 5]); + if (aux) + *aux = hexval(uname[l - 4]) * 4096 + hexval(uname[l - 3]) * 256 + + hexval(uname[l - 2]) * 16 + hexval(uname[l - 1]); + l -= 7; + } + if (l > 64) + l = 64; + strncpy(pname + 1, uname, l); + pname[0] = l; + pname[l + 1] = '\0'; + return pname; +} +static unsigned int prodos_time(int year, int month, int day, int hour, int minute) +{ + year -= 1900; + if (year > 99) + year -= 100; + month += 1; + return (day & 0x1F) | ((month & 0x0F) << 5) | ((year & 0x7F) << 9) + | ((minute & 0x3F) << 16) | ((hour & 0x1F) << 24); +} +static time_t unix_time(unsigned int ptime) +{ + struct tm tm; + memset(&tm, 0, sizeof(struct tm)); + tm.tm_mday = ptime & 0x1F; + tm.tm_mon = (ptime >> 5) & 0x0F; + tm.tm_year = (ptime >> 9) & 0x7F; + tm.tm_min = (ptime >> 16) & 0x3F; + tm.tm_hour = (ptime >> 24) & 0x1F; + if (tm.tm_year < 80) + tm.tm_year += 100; + tm.tm_mon -= 1; + return mktime(&tm); +} +struct stat *unix_stat(struct stat *stbuf, int storage, int access, int blocks, int size, int mod, int create) +{ + memset(stbuf, 0, sizeof(struct stat)); + if (storage == 0x0F || storage == 0x0D) + { + stbuf->st_mode = (access & 0xC3 == 0xC3) ? S_IFDIR | 0755 : S_IFDIR | 0544; + stbuf->st_nlink = 2; + } + else + { + stbuf->st_mode = (access & 0xC3 == 0xC3) ? S_IFREG | 0666 : S_IFREG | 0444; + stbuf->st_nlink = 1; + stbuf->st_blocks = blocks; + stbuf->st_size = size; + } + stbuf->st_atime = stbuf->st_mtime = unix_time(mod); + stbuf->st_ctime = unix_time(create); + return stbuf; +} +/* + * 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(unsigned char *prodos_path, int *io_buff) +{ + unsigned char refnum; + int result; + + 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 == PRODOS_ERR_EOF || total_xfer) ? total_xfer : -result; + } + else + return -PRODOS_ERR_UNKNOWN; + } + return total_xfer; +} +static int prodos_write(int refnum, const 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, (char *)(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(int unit, char *data_buff) +{ + int result; + + prodos[PRODOS_CMD] = PRODOS_ON_LINE; + prodos[PRODOS_PARAM_CNT] = 2; + prodos[PRODOS_PARAMS + 1] = (unsigned char) unit; + 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, (unit == 0) ? 256 : 16, data_buff); + return -result; + } + return -PRODOS_ERR_UNKNOWN; +} +static int prodos_set_file_info(unsigned char *prodos_path, int access, int type, int aux, int mod, int create) +{ + int result; + + a2write(pifd, PRODOS_DATA_BUFFER, prodos_path[0] + 1, prodos_path); + prodos[PRODOS_CMD] = PRODOS_SET_FILE_INFO; + 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] = access; + prodos[PRODOS_PARAMS + 4] = type; + prodos[PRODOS_PARAMS + 5] = (unsigned char) aux; + prodos[PRODOS_PARAMS + 6] = (unsigned char) (aux >> 8); + prodos[PRODOS_PARAMS + 7] = 0; + prodos[PRODOS_PARAMS + 8] = 0; + prodos[PRODOS_PARAMS + 9] = 0; + prodos[PRODOS_PARAMS + 10] = (unsigned char) mod; + prodos[PRODOS_PARAMS + 11] = (unsigned char) (mod >> 8); + prodos[PRODOS_PARAMS + 12] = (unsigned char) create; + prodos[PRODOS_PARAMS + 13] = (unsigned char) (create >> 8); + a2write(pifd, PRODOS_CALL, PRODOS_CALL_LEN + 13, prodos); + if (a2call(pifd, PRODOS_CALL, &result)) + return -result; + return -PRODOS_ERR_UNKNOWN; +} +static int prodos_get_file_info(unsigned char *prodos_path, int *access, int *type, int *aux, int *storage, int *numblks, int *mod, int *create) +{ + int result; + + 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(unsigned char *from, unsigned char *to) +{ + int result; + + a2write(pifd, PRODOS_DATA_BUFFER, from[0] + 1, from); + a2write(pifd, PRODOS_DATA_BUFFER + 256, to[0] + 1, to); + 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(unsigned char *prodos_path) +{ + int result; + + 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(unsigned char *prodos_path, char access, char type, int aux, int create) +{ + int result; + + 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; +} +static int prodos_read_block(int unit, char *data_buff, int block_num) +{ + int result; + + prodos[PRODOS_CMD] = PRODOS_READ_BLOCK; + prodos[PRODOS_PARAM_CNT] = 3; + prodos[PRODOS_PARAMS + 1] = (unsigned char) unit; + 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) block_num; + prodos[PRODOS_PARAMS + 5] = (unsigned char) (block_num >> 8); + a2write(pifd, PRODOS_CALL, PRODOS_CALL_LEN + 5, prodos); + if (a2call(pifd, PRODOS_CALL, &result)) + { + if (result == 0) + a2read(pifd, PRODOS_DATA_BUFFER, 512, data_buff); + return -result; + } + return -PRODOS_ERR_UNKNOWN; +} +static int prodos_write_block(int unit, char *data_buff, int block_num) +{ + int result; + + if (a2write(pifd, PRODOS_DATA_BUFFER, 512, data_buff) != 0) + return -PRODOS_ERR_UNKNOWN; + prodos[PRODOS_CMD] = PRODOS_WRITE_BLOCK; + prodos[PRODOS_PARAM_CNT] = 3; + prodos[PRODOS_PARAMS + 1] = (unsigned char) unit; + 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) block_num; + prodos[PRODOS_PARAMS + 5] = (unsigned char) (block_num >> 8); + a2write(pifd, PRODOS_CALL, PRODOS_CALL_LEN + 5, prodos); + if (a2call(pifd, PRODOS_CALL, &result)) + return -result; + return -PRODOS_ERR_UNKNOWN; +} +static int prodos_map_errno(int perr) +{ + int uerr = 0; + if (perr) + { + switch (perr) /* Map ProDOS error to unix errno */ + { + case -PRODOS_ERR_INVLD_PATH: + case -PRODOS_ERR_PATH_NOT_FND: + case -PRODOS_ERR_VOL_NOT_FND: + case -PRODOS_ERR_FILE_NOT_FND: + case -PRODOS_ERR_DUP_FILENAME: + case -PRODOS_ERR_UNSUPP_TYPE: + case -PRODOS_ERR_EOF: + uerr = -ENOENT; + break; + case -PRODOS_ERR_WR_PROT: + case -PRODOS_ERR_DSK_SWITCH: + case -PRODOS_ERR_ACCESS: + case -PRODOS_ERR_FILE_OPEN: + case -PRODOS_ERR_DUP_VOL: + uerr = -EACCES; + break; + case -PRODOS_ERR_BAD_CMD: + case -PRODOS_ERR_BAD_COUNT: + case -PRODOS_ERR_INT_TBL_FULL: + case -PRODOS_ERR_IO: + case -PRODOS_ERR_INVLD_REFNUM: + case -PRODOS_ERR_NO_DEV: + case -PRODOS_ERR_INCOMPAT_FMT: + case -PRODOS_ERR_OVERRUN: + case -PRODOS_ERR_DIR_COUNT: + case -PRODOS_ERR_NOT_PRODOS: + case -PRODOS_ERR_INVLD_PARAM: + case -PRODOS_ERR_BAD_BITMAP: + case -PRODOS_ERR_BAD_BUF_ADDR: + case -PRODOS_ERR_UNKNOWN: + + case -PRODOS_ERR_FCB_FULL: + case -PRODOS_ERR_VOL_DIR_FULL: + case -PRODOS_ERR_VCB_FULL: + case -PRODOS_ERR_POS_RANGE: + uerr = -1; + } + } + return uerr; +} +/* + * FUSE functions. + */ +static int cache_get_file_info(const char *path, int *access, int *type, int *aux, int *storage, int *numblks, int *size, int *mod, int *create) +{ + char dirpath[128], filename[32]; + unsigned char *entry, prodos_name[65], data_buff[512]; + int refnum, iblk, entrylen, entriesblk, filecnt, io_buff = 0; + int iscached, i, dl, l = strlen(path); + + for (dl = l - 1; dl; dl--) + if (path[dl] == '/') + break; + if (dl == 0) + { + /* + * Volume directory + */ + *storage = 0x0F; + *type = 0x0F; + *access = 0xC3; + *aux = 0; + *numblks = 0; + *size = 0; + *mod = 0; + *create = 0; + } + else + { + strncpy(dirpath, path, dl); + dirpath[dl] = '\0'; + //printf("Match path %s to cached dir %s\n", dirpath, cachepath); + iscached = (strcmp(dirpath, cachepath) == 0); + if (iscached || (refnum = prodos_open(prodos_path(dirpath, NULL, NULL, NULL), &io_buff)) > 0) + { + strcpy(filename, path + dl + 1); + l = l - dl - 1; + if (l > 7 && filename[l - 7] == '#') + { + l -= 7; + filename[l] = '\0'; + } + //printf("Match filename %s len %d\n", filename, l); + iblk = 0; + //printf("Cached entrylen = %d, filecnt = %d\n", entrylen, filecnt); + do + { + if (iscached || prodos_read(refnum, data_buff, 512) == 512) + { + if (iscached) + { + if (iblk == 0) + { + entrylen = cachedata[0][0x23]; + entriesblk = cachedata[0][0x24]; + filecnt = cachedata[0][0x25] + cachedata[0][0x26] * 256; + entry = &cachedata[0][4] + entrylen; + } + else + entry = &cachedata[0][4]; + } + else + { + if (iblk == 0) + { + entrylen = data_buff[0x23]; + entriesblk = data_buff[0x24]; + filecnt = data_buff[0x25] + data_buff[0x26] * 256; + entry = &data_buff[4] + entrylen; + } + else + entry = &data_buff[4]; + } + for (i = (iblk == 0) ? 1 : 0; i < entriesblk && filecnt; i++) + { + if (entry[0]) + { + //entry[(entry[0] & 0x0F) + 1] = 0; + //printf("Searching directory entry: %s len %d\n", entry + 1, entry[0] & 0x0F); + if ((entry[0] & 0x0F) == l) + { + //printf("Compare %s with %s\n", entry + 1, filename); + if (strncmp(entry + 1, filename, l) == 0) + { + *storage = entry[0x00] >> 4; + *type = entry[0x10]; + *access = entry[0x1E]; + *aux = entry[0x1F] + entry[0x20] * 256; + *numblks = entry[0x13] + entry[0x14] * 256; + *size = entry[0x15] + entry[0x16] * 256 + entry[0x17] * 65536; + *mod = entry[0x21] | (entry[0x22] << 8) + | (entry[0x23] << 16) | (entry[0x24] << 24); + *create = entry[0x18] | (entry[0x19] << 8) + | (entry[0x1A] << 16) | (entry[0x1B] << 24); + //printf("Cache hit: %s access = $%02X, type = $%02X, aux = $%04X, storage = $%02X, size = %d\n", filename, *access, *type, *aux, *storage, *size); + if (!iscached) + prodos_close(refnum, &io_buff); + return 0; + } + } + entry += entrylen; + filecnt--; + } + } + } + else + filecnt = 0; + iblk++; + } while (filecnt != 0); + if (!iscached) + prodos_close(refnum, &io_buff); + } + if (prodos_get_file_info(prodos_path(path, NULL, NULL, prodos_name), access, type, aux, storage, numblks, mod, create) == 0) + { + //printf("prodos: %s access = $%02X, type = $%02X, aux = $%04X, storage = $%02X\n", path, *access, *type, *aux, *storage); + if (*storage == 0x0F || *storage == 0x0D) + *size = 0; + else + { + if ((refnum = prodos_open(prodos_name, &io_buff) > 0)) + { + *size = prodos_get_eof(refnum); + prodos_close(refnum, &io_buff); + } + else + return prodos_map_errno(refnum); + } + } + else + return -ENOENT; + } + return 0; +} + +static int a2pi_getattr(const char *path, struct stat *stbuf) +{ + int access, type, aux, storage, size, numblks, mod, create, refnum, io_buff = 0; + if (strcmp(path, "/") == 0 || strcmp(path, ".") == 0 || strcmp(path, "..") == 0) + { + /* + * Root directory of volumes. + */ + unix_stat(stbuf, 0x0F, 0x01, 0, 0, 0, 0); + } + else + { + /* + * Get file info. + */ + if (cache_get_file_info(path, &access, &type, &aux, &storage, &numblks, &size, &mod, &create) == 0) + { + if (storage == 0x0F || storage == 0x0D) + size = 0; + unix_stat(stbuf, storage, access, numblks, size, mod, create); + } + else + return -ENOENT; + } + return 0; +} + +static int a2pi_access(const char *path, int mask) +{ + int storage, access, type, numblks, size, aux, mod, create, access_ok = 0; + + if (cache_get_file_info(path, &access, &type, &aux, &storage, &numblks, &size, &mod, &create) == 0) + { + //printf("Check access bits $%02X to mask 0x%02X\n", access, mask); + if ((mask & R_OK) && !(access & 0x01)) + access_ok = -1; + if ((mask & W_OK) && ((access & 0xC2) != 0xC2)) + access_ok = -1; + if ((mask & X_OK) && (type != 0x0F)) + access_ok = -1; + } + else + access_ok = -1; + return access_ok; +} + +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; + int storage, access, type, numblks, size, aux, mod, create; + int i, l, iscached, refnum, iblk, entrylen, entriesblk, filecnt, io_buff = 0; + struct stat stentry; + + (void) offset; + (void) fi; + if (strcmp(path, "/") == 0) + { + /* + * Root directory, fill with volume names. + */ + unix_stat(&stentry, 0x0F, 0xC3, 0, 0, 0, 0); + filler(buf, ".", &stentry, 0); + filler(buf, "..", &stentry, 0); + for (i = 0; i < 256; i += 16) + if ((l = volumes[i] & 0x0F)) + { + strncpy(filename, volumes + i + 1, l); + filename[l] = '\0'; + filler(buf, filename, &stentry, 0); + } + } + else + { + /* + * Read ProDOS directory. + */ + iscached = (strcmp(path, cachepath) == 0); + if (iscached || (refnum = prodos_open(prodos_path(path, NULL, NULL, NULL), &io_buff)) > 0) + { + unix_stat(&stentry, 0x0F, 0xC3, 0, 0, 0, 0); + filler(buf, ".", &stentry, 0); + filler(buf, "..", &stentry, 0); + iblk = 0; + do + { + if (iscached || prodos_read(refnum, cachedata[iblk], 512) == 512) + { + entry = &cachedata[iblk][4]; + if (iblk == 0) + { + entrylen = cachedata[0][0x23]; + entriesblk = cachedata[0][0x24]; + filecnt = cachedata[0][0x25] + cachedata[0][0x26] * 256; + entry = entry + entrylen; + } + for (i = (iblk == 0) ? 1 : 0; i < entriesblk && filecnt; i++) + { + if ((l = entry[0x00] & 0x0F) != 0) + { + storage = entry[0x00] >> 4; + type = entry[0x10]; + access = entry[0x1E]; + aux = entry[0x1F] + entry[0x20] * 256; + numblks = entry[0x13] + entry[0x14] * 256; + size = entry[0x15] + entry[0x16] * 256 + entry[0x17] * 65536; + mod = entry[0x21] | (entry[0x22] << 8) + | (entry[0x23] << 16) | (entry[0x24] << 24); + create = entry[0x18] | (entry[0x19] << 8) + | (entry[0x1A] << 16) | (entry[0x1B] << 24); + filler(buf, unix_name(entry, type, aux, NULL), unix_stat(&stentry, storage, access, numblks, size, mod, create), 0); + entry += entrylen; + filecnt--; + } + } + if (++iblk > CACHE_BLOCKS_MAX) + { + cachepath[0] == '\0'; + iblk = 1; + } + } + else + filecnt = 0; + } while (filecnt != 0); + if (!iscached) + { + prodos_close(refnum, &io_buff); + strcpy(cachepath, path); + } + } + else + return -ENOENT; + } + return 0; +} + +static int a2pi_mkdir(const char *path, mode_t mode) +{ + time_t now = time(NULL); + struct tm *tm = localtime(&now); + int create = prodos_time(tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min); + cachepath[0] = '\0'; + return prodos_map_errno(prodos_create(prodos_path(path, NULL, NULL, NULL), 0xE3, 0x0F, create, create)); +} + +static int a2pi_remove(const char *path) +{ + cachepath[0] = '\0'; + return prodos_map_errno(prodos_destroy(prodos_path(path, NULL, NULL, NULL))); +} + +static int a2pi_rename(const char *from, const char *to) +{ + unsigned char prodos_from[65], prodos_to[65]; + prodos_path(from, NULL, NULL, prodos_from); + prodos_path(to, NULL, NULL, prodos_to); + cachepath[0] = '\0'; + return prodos_map_errno(prodos_rename(prodos_from, prodos_to)); +} + +static int a2pi_chmod(const char *path, mode_t mode) +{ + int access, type, aux, storage, size, numblks, mod, create; + + if (cache_get_file_info(path, &access, &type, &aux, &storage, &numblks, &size, &mod, &create) == 0) + { + access = (mode & 0x04) ? 0x01 : 0x00; + access |= (mode & 0x02) ? 0xC2 : 0x00; + cachepath[0] = '\0'; + return prodos_map_errno(prodos_set_file_info(prodos_path(path, NULL, NULL, NULL), access, type, aux, mod, create)); + } + return -ENOENT; +} + +static int a2pi_truncate(const char *path, off_t size) +{ + int refnum, io_buff = 0; + + cachepath[0] = '\0'; + if ((refnum = prodos_open(prodos_path(path, NULL, NULL, NULL), &io_buff)) > 0) + { + prodos_set_eof(refnum, size); + return prodos_map_errno(prodos_close(refnum, &io_buff)); + } + return prodos_map_errno(refnum); +} + +static int a2pi_open(const char *path, struct fuse_file_info *fi) +{ + int refnum, io_buff = 0; + + if ((refnum = prodos_open(prodos_path(path, NULL, NULL, NULL), &io_buff)) > 0) + { + return prodos_map_errno(prodos_close(refnum, &io_buff)); + } + return prodos_map_errno(refnum); +} + +static int a2pi_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) +{ + int refnum, io_buff = 0; + + if ((refnum = prodos_open(prodos_path(path, NULL, NULL, NULL), &io_buff)) > 0) + { + if (offset && prodos_set_mark(refnum, offset) == -PRODOS_ERR_EOF) + size = 0; + if (size) + size = prodos_read(refnum, buf, size); + if (size == -PRODOS_ERR_EOF) + size = 0; + prodos_close(refnum, &io_buff); + return size; + } + return prodos_map_errno(refnum); +} + +static int a2pi_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) +{ + int refnum, io_buff = 0; + cachepath[0] = '\0'; + + if ((refnum = prodos_open(prodos_path(path, NULL, NULL, NULL), &io_buff)) > 0) + { + if (offset && prodos_set_mark(refnum, offset) == -PRODOS_ERR_EOF) + size = 0; + if (size) + size = prodos_write(refnum, buf, size); + prodos_close(refnum, &io_buff); + return size; + } + return prodos_map_errno(refnum); +} + +static int a2pi_create(const char * path, mode_t mode, struct fuse_file_info *fi) +{ + unsigned char prodos_name[65]; + int refnum, type, aux, io_buff = 0; + time_t now = time(NULL); + struct tm *tm = localtime(&now); + int create = prodos_time(tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min); + cachepath[0] = '\0'; + if ((refnum = prodos_open(prodos_path(path, &type, &aux, prodos_name), &io_buff)) == -PRODOS_ERR_FILE_NOT_FND) + return prodos_map_errno(prodos_create(prodos_name, 0xC3, type, aux, create)); + return prodos_map_errno(refnum); +} + +int a2pi_ftruncate(const char *path, off_t offset, struct fuse_file_info *fi) +{ + cachepath[0] = '\0'; + return a2pi_truncate(path, offset); +} + +int a2pi_fgetattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi) +{ + return a2pi_getattr(path, stbuf); +} + +static int a2pi_statfs(const char *path, struct statvfs *stbuf) +{ + unsigned char voldir[16], voldata[512]; + int i, storage, access, type, numblks, aux, mod, create; + + memset(stbuf, 0, sizeof(struct statvfs)); + /* + * Copy first element of path = volume directory. + */ + voldir[1] = '/'; + for (i = 1; path[i] && path[i] != '/'; i++) + voldir[i + 1] = path[i]; + voldir[0] = i; + if ((prodos_get_file_info(voldir, &access, &type, &aux, &storage, &numblks, &mod, &create)) > 0) + { + stbuf->f_bsize = 512; + stbuf->f_fsid = 0xa2; +// stbuf->f_namelen = 22; /* include space for #typeattrib */ + stbuf->f_blocks = aux; + stbuf->f_bfree = + stbuf->f_bavail = aux - numblks; + return 0; + } + return -1; +} + +int a2pi_utimens(const char *path, const struct timespec tv[2]) +{ + int access, type, aux, storage, size, numblks, mod, create, refnum, io_buff = 0; + struct tm *tm = localtime(&tv[0].tv_sec); + cachepath[0] = '\0'; + /* + * Get file info. + */ + if (cache_get_file_info(path, &access, &type, &aux, &storage, &numblks, &size, &mod, &create) == 0) + return prodos_map_errno(prodos_set_file_info(prodos_path(path, NULL, NULL, NULL), + access, + type, + aux, + prodos_time(tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min), + create)); + return -ENOENT; +} + +static struct fuse_operations a2pi_oper = { + .getattr = a2pi_getattr, + .access = a2pi_access, + .readdir = a2pi_readdir, + .mkdir = a2pi_mkdir, + .unlink = a2pi_remove, + .rmdir = a2pi_remove, + .rename = a2pi_rename, + .chmod = a2pi_chmod, + .truncate = a2pi_truncate, + .open = a2pi_open, + .read = a2pi_read, + .write = a2pi_write, + .create = a2pi_create, + .ftruncate = a2pi_ftruncate, + .fgetattr = a2pi_fgetattr, + .statfs = a2pi_statfs, + .utimens = a2pi_utimens, +}; + +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); + prodos_on_line(0, volumes); + umask(0); + return fuse_main(argc, argv, &a2pi_oper, NULL); +}