From 65ae9be515c74968d8ddf570808932d88627f0b2 Mon Sep 17 00:00:00 2001 From: dschmenk Date: Fri, 6 Sep 2013 19:21:06 -0700 Subject: [PATCH] mostly working --- src/a2mount | 2 +- src/fusea2pi.c | 550 ++++++++++++++++++++++++++++++++----------------- 2 files changed, 358 insertions(+), 194 deletions(-) diff --git a/src/a2mount b/src/a2mount index 962f7b9..24f6c88 100755 --- a/src/a2mount +++ b/src/a2mount @@ -1,2 +1,2 @@ #!/bin/bash -/usr/local/bin/fusea2pi $1 -o uid=`id -u` -o gid=`id -g` +/usr/local/bin/fusea2pi $1 $2 -o uid=`id -u` -o gid=`id -g` diff --git a/src/fusea2pi.c b/src/fusea2pi.c index eeaa87a..fad608d 100755 --- a/src/fusea2pi.c +++ b/src/fusea2pi.c @@ -99,36 +99,114 @@ static int pifd = 0; #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 *unix_name(unsigned char *pname, int type, int aux) +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]; - char extname[8]; + if (uname == NULL) + uname = filename; l = pname[0] & 0x0F; - strncpy(filename, pname + 1, l); -// if (type != 0x0F) /* Directory type */ -// { -// sprintf(extname, "#%02X%04X", type, aux); -// strcpy(filename + l, extname); -// } -// else - filename[l] = '\0'; - return filename; + 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 unsigned char *prodos_name(char *uname, int *type, int *aux) +static int hexval(char h) { - int l; - static unsigned char filename[25]; - if ((l = strlen(uname)) > 15) - l = 15; - strncpy(filename + 1, uname, l); - filename[0] = l; - filename[l + 1] = '\0'; - return filename; + 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) +{ + 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 + 1900; + tm.tm_min = (ptime >> 16) & 0x3F; + tm.tm_hour = (ptime >> 24) & 0x1F; + if (tm.tm_year < 1980) + tm.tm_year += 100; + 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 | 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_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. @@ -153,15 +231,11 @@ static int prodos_free_io_buff(int buf) io_buff_mask &= ~(1 << i); return i; } -static int prodos_open(const char *path, int *io_buff) +static int prodos_open(unsigned char *prodos_path, int *io_buff) { - char prodos_path[65], refnum = 0; + unsigned char refnum; 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) { @@ -329,33 +403,28 @@ static int prodos_get_eof(int refnum) } return -PRODOS_ERR_UNKNOWN; } -static int prodos_on_line(char *data_buff) +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] = 0; + 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, 256, data_buff); + a2read(pifd, PRODOS_DATA_BUFFER, (unit == 0) ? 256 : 16, data_buff); return -result; } return -PRODOS_ERR_UNKNOWN; } -static int prodos_set_file_info(const char *path, int access, int type, int aux, int mod, int create) +static int prodos_set_file_info(unsigned char *prodos_path, int access, int type, int aux, 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_SET_FILE_INFO; prodos[PRODOS_PARAM_CNT] = 7; @@ -377,15 +446,10 @@ static int prodos_set_file_info(const char *path, int access, int type, int aux, 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) +static int prodos_get_file_info(unsigned char *prodos_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; @@ -432,21 +496,12 @@ static int prodos_get_file_info(const char *path, int *access, int *type, int *a } return -PRODOS_ERR_UNKNOWN; } -static int prodos_rename(const char *filename, const char *new_filename) +static int prodos_rename(unsigned char *from, unsigned char *to) { - 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); + 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; @@ -458,15 +513,10 @@ static int prodos_rename(const char *filename, const char *new_filename) return -result; return -PRODOS_ERR_UNKNOWN; } -static int prodos_destroy(const char *path) +static int prodos_destroy(unsigned char *prodos_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; @@ -477,15 +527,10 @@ static int prodos_destroy(const char *path) return -result; return -PRODOS_ERR_UNKNOWN; } -static int prodos_create(const char *path, char access, char type, int aux, int create) +static int prodos_create(unsigned char *prodos_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; @@ -505,6 +550,44 @@ static int prodos_create(const char *path, char access, char type, int aux, int 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; @@ -555,83 +638,21 @@ static int prodos_map_errno(int perr) /* * FUSE functions. */ -struct stat *fillstat(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 | 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_blocks = blocks; - stbuf->st_size = size; - } - return stbuf; -} 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; + unsigned char *entry, prodos_name[65]; int refnum, iblk, entrylen, entriesblk, filecnt, io_buff = 0; int i, dl, l = strlen(path); for (dl = l - 1; dl; dl--) if (path[dl] == '/') break; - strncpy(dirpath, path, dl); - dirpath[dl] = '\0'; - //printf("Match path %s to cached dir %s\n", dirpath, cachepath); - if (strcmp(dirpath, cachepath) == 0) - { - strcpy(filename, path + dl + 1); - l = l - dl - 1; - //printf("Match filename %s len %d\n", filename, l); - iblk = 0; - entrylen = cachedata[0][0x23]; - entriesblk = cachedata[0][0x24]; - filecnt = cachedata[0][0x25] + cachedata[0][0x26] * 256; - entry = &cachedata[0][4] + entrylen; - do - { - 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); - return 0; - } - } - entry += entrylen; - filecnt--; - } - } - if (++iblk > CACHE_BLOCKS_MAX) - break; - entry = &cachedata[iblk][4]; - } while (filecnt != 0); - } if (dl == 0) { + /* + * Volume directory + */ *storage = 0x0F; *type = 0x0F; *access = 0xC3; @@ -641,24 +662,82 @@ static int cache_get_file_info(const char *path, int *access, int *type, int *au *mod = 0; *create = 0; } - else if (prodos_get_file_info(path, 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(path, &io_buff) > 0)) - { - *size = prodos_get_eof(refnum); - prodos_close(refnum, &io_buff); - } - else - return prodos_map_errno(refnum); - } - } else - return -ENOENT; + { + strncpy(dirpath, path, dl); + dirpath[dl] = '\0'; + //printf("Match path %s to cached dir %s\n", dirpath, cachepath); + if (strcmp(dirpath, cachepath) == 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; + entrylen = cachedata[0][0x23]; + entriesblk = cachedata[0][0x24]; + filecnt = cachedata[0][0x25] + cachedata[0][0x26] * 256; + entry = &cachedata[0][4] + entrylen; + //printf("Cached entrylen = %d, filecnt = %d\n", entrylen, filecnt); + do + { + 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); + return 0; + } + } + entry += entrylen; + filecnt--; + } + } + if (++iblk > CACHE_BLOCKS_MAX) + break; + entry = &cachedata[iblk][4]; + } while (filecnt != 0); + } + 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; } @@ -670,7 +749,7 @@ static int a2pi_getattr(const char *path, struct stat *stbuf) /* * Root directory of volumes. */ - fillstat(stbuf, 0x0F, 0xE3, 0, 0, 0, 0); + unix_stat(stbuf, 0x0F, 0xE3, 0, 0, 0, 0); } else { @@ -681,7 +760,7 @@ static int a2pi_getattr(const char *path, struct stat *stbuf) { if (storage == 0x0F || storage == 0x0D) size = 0; - fillstat(stbuf, storage, access, numblks, size, mod, create); + unix_stat(stbuf, storage, access, numblks, size, mod, create); } else return -ENOENT; @@ -689,6 +768,25 @@ static int a2pi_getattr(const char *path, struct stat *stbuf) 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) { @@ -696,6 +794,7 @@ static int a2pi_readdir(const char *path, void *buf, fuse_fill_dir_t filler, 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) @@ -703,21 +802,16 @@ static int a2pi_readdir(const char *path, void *buf, fuse_fill_dir_t filler, /* * Root directory, fill with volume names. */ - fillstat(&stentry, 0x0F, 0xC3, 0, 0, 0, 0); + unix_stat(&stentry, 0x0F, 0xC3, 0, 0, 0, 0); filler(buf, ".", &stentry, 0); filler(buf, "..", &stentry, 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, &stentry, 0); - } - } - else - return -ENOENT; + 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 { @@ -725,9 +819,9 @@ static int a2pi_readdir(const char *path, void *buf, fuse_fill_dir_t filler, * Read ProDOS directory. */ iscached = (strcmp(path, cachepath) == 0); - if (iscached || (refnum = prodos_open(path, &io_buff)) > 0) - { - fillstat(&stentry, 0x0F, 0xC3, 0, 0, 0, 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; @@ -757,7 +851,7 @@ static int a2pi_readdir(const char *path, void *buf, fuse_fill_dir_t filler, | (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), fillstat(&stentry, storage, access, numblks, size, mod, create), 0); + filler(buf, unix_name(entry, type, aux, NULL), unix_stat(&stentry, storage, access, numblks, size, mod, create), 0); entry += entrylen; filecnt--; } @@ -782,20 +876,26 @@ static int a2pi_readdir(const char *path, void *buf, fuse_fill_dir_t filler, 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(path, 0xE3, 0x0F, 0, 0)); + return prodos_map_errno(prodos_create(prodos_path(path, NULL, NULL, NULL), 0xE3, 0x0F, create, create)); } -static int a2pi_destroy(const char *path) +static int a2pi_remove(const char *path) { cachepath[0] = '\0'; - return prodos_map_errno(prodos_destroy(path)); + 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(from, to)); + return prodos_map_errno(prodos_rename(prodos_from, prodos_to)); } static int a2pi_chmod(const char *path, mode_t mode) @@ -807,7 +907,7 @@ static int a2pi_chmod(const char *path, mode_t mode) access = (mode & 0x04) ? 0x01 : 0x00; access |= (mode & 0x02) ? 0xC2 : 0x00; cachepath[0] = '\0'; - return prodos_map_errno(prodos_set_file_info(path, access, type, aux, mod, create)); + return prodos_map_errno(prodos_set_file_info(prodos_path(path, NULL, NULL, NULL), access, type, aux, mod, create)); } return -ENOENT; } @@ -817,7 +917,7 @@ static int a2pi_truncate(const char *path, off_t size) int refnum, io_buff = 0; cachepath[0] = '\0'; - if ((refnum = prodos_open(path, &io_buff)) > 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)); @@ -829,7 +929,7 @@ static int a2pi_open(const char *path, struct fuse_file_info *fi) { int refnum, io_buff = 0; - if ((refnum = prodos_open(path, &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)); } @@ -840,7 +940,7 @@ static int a2pi_read(const char *path, char *buf, size_t size, off_t offset, str { int refnum, io_buff = 0; - if ((refnum = prodos_open(path, &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; @@ -859,7 +959,7 @@ static int a2pi_write(const char *path, const char *buf, size_t size, off_t offs int refnum, io_buff = 0; cachepath[0] = '\0'; - if ((refnum = prodos_open(path, &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; @@ -873,27 +973,90 @@ static int a2pi_write(const char *path, const char *buf, size_t size, off_t offs static int a2pi_create(const char * path, mode_t mode, struct fuse_file_info *fi) { - int refnum, io_buff = 0; + 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(path, &io_buff)) == -PRODOS_ERR_FILE_NOT_FND) - return prodos_map_errno(prodos_create(path, 0xC3, 0x04, 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, - .readdir = a2pi_readdir, - .mkdir = a2pi_mkdir, - .unlink = a2pi_destroy, - .rmdir = a2pi_destroy, - .rename = a2pi_rename, - .chmod = a2pi_chmod, - .truncate = a2pi_truncate, - .open = a2pi_open, - .read = a2pi_read, - .write = a2pi_write, - .create = a2pi_create, + .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[]) @@ -905,6 +1068,7 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } prodos_close(0, NULL); + prodos_on_line(0, volumes); umask(0); return fuse_main(argc, argv, &a2pi_oper, NULL); }