This is fsdevice.c in view mode; [Download] [Up]
/* * fsdevice.c - File system device. * * Written by * Teemu Rantanen (tvr@cs.hut.fi) * Jarkko Sonninen (sonninen@lut.fi) * Jouko Valta (jopi@stekt.oulu.fi) * Olaf Seibert (rhialto@mbfys.kun.nl) * André Fachat (a.fachat@physik.tu-chemnitz.de) * Ettore Perazzoli (ettore@comm2000.it) * Martin Pottendorfer (Martin.Pottendorfer@aut.alcatel.at) * Andreas Boose (boose@unixserv.rz.fh-hannover.de) * * Patches by * Dan Miner (dminer@nyx10.cs.du.edu) * Germano Caronni (caronni@tik.ethz.ch) * Daniel Fandrich (dan@fch.wimsey.bc.ca) /DF/ * * This file is part of VICE, the Versatile Commodore Emulator. * See README for copyright notice. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA. * */ /*#define DEBUG_FS*/ /*#define DEBUG_FSDRIVE*/ #include "vice.h" #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> #include <fcntl.h> #include <unistd.h> #include <memory.h> #include <assert.h> #include <errno.h> #include "resources.h" #include "drive.h" #include "file.h" #include "charsets.h" #include "tape.h" #include "utils.h" #include "cmdline.h" #include "fsdevice.h" enum fsmode { Write, Read, Append, Directory }; struct fs_buffer_info { FILE *fd; DIR *dp; enum fsmode mode; char dir[MAXPATHLEN]; BYTE name[MAXPATHLEN + 5]; int buflen; BYTE *bufp; int eof; int dirmpos; int reclen; int type; } fs_info[16]; /* this should somehow go into the fs_info struct... */ static char fs_errorl[MAXPATHLEN]; static unsigned int fs_elen, fs_eptr; static char fs_cmdbuf[MAXPATHLEN]; static unsigned int fs_cptr = 0; static char fs_dirmask[MAXPATHLEN]; static FILE *fs_find_pc64_name(void *flp, char *name, int length, char *pname); static void fs_test_pc64_name(void *flp, char *rname, int secondary); static int fsdevice_compare_wildcards(char *name, char *p00name); static void fsdevice_compare_file_name(void *flp, char *fsname2, char *fsname, int secondary); static int fsdevice_create_file_p00(void *flp, char *name, int length, char *fsname, int secondary); static int fsdevice_reduce_filename_p00(char *filename, int len); static int fsdevice_eliminate_char_p00(char *filename, int pos); static int fsdevice_evaluate_name_p00(char *name, int length, char *filename); /* FIXME: ugly. */ extern errortext_t floppy_error_messages; /* ------------------------------------------------------------------------- */ static int fsdevice_convert_p00_enabled[4]; static int fsdevice_save_p00_enabled[4]; static int fsdevice_hide_cbm_files_enabled[4]; static char *fsdevice_8_dir; static char *fsdevice_9_dir; static char *fsdevice_10_dir; static char *fsdevice_11_dir; static int set_fsdevice_8_convert_p00(resource_value_t v) { fsdevice_convert_p00_enabled[0] = (int) v; return 0; } static int set_fsdevice_9_convert_p00(resource_value_t v) { fsdevice_convert_p00_enabled[1] = (int) v; return 0; } static int set_fsdevice_10_convert_p00(resource_value_t v) { fsdevice_convert_p00_enabled[2] = (int) v; return 0; } static int set_fsdevice_11_convert_p00(resource_value_t v) { fsdevice_convert_p00_enabled[3] = (int) v; return 0; } static int set_fsdevice_8_dir(resource_value_t v) { const char *name = (const char *) v; if (fsdevice_8_dir != NULL && name != NULL && strcmp(name, fsdevice_8_dir) == 0) return 0; string_set(&fsdevice_8_dir, name); return 0; } static int set_fsdevice_9_dir(resource_value_t v) { const char *name = (const char *) v; if (fsdevice_9_dir != NULL && name != NULL && strcmp(name, fsdevice_9_dir) == 0) return 0; string_set(&fsdevice_9_dir, name); return 0; } static int set_fsdevice_10_dir(resource_value_t v) { const char *name = (const char *) v; if (fsdevice_10_dir != NULL && name != NULL && strcmp(name, fsdevice_10_dir) == 0) return 0; string_set(&fsdevice_10_dir, name); return 0; } static int set_fsdevice_11_dir(resource_value_t v) { const char *name = (const char *) v; if (fsdevice_11_dir != NULL && name != NULL && strcmp(name, fsdevice_11_dir) == 0) return 0; string_set(&fsdevice_11_dir, name); return 0; } static int set_fsdevice_8_save_p00(resource_value_t v) { fsdevice_save_p00_enabled[0] = (int) v; return 0; } static int set_fsdevice_9_save_p00(resource_value_t v) { fsdevice_save_p00_enabled[1] = (int) v; return 0; } static int set_fsdevice_10_save_p00(resource_value_t v) { fsdevice_save_p00_enabled[2] = (int) v; return 0; } static int set_fsdevice_11_save_p00(resource_value_t v) { fsdevice_save_p00_enabled[3] = (int) v; return 0; } static int set_fsdevice_8_hide_cbm_files(resource_value_t v) { if (!fsdevice_convert_p00_enabled[0]) return -1; fsdevice_hide_cbm_files_enabled[0] = (int) v; return 0; } static int set_fsdevice_9_hide_cbm_files(resource_value_t v) { if (!fsdevice_convert_p00_enabled[1]) return -1; fsdevice_hide_cbm_files_enabled[1] = (int) v; return 0; } static int set_fsdevice_10_hide_cbm_files(resource_value_t v) { if (!fsdevice_convert_p00_enabled[2]) return -1; fsdevice_hide_cbm_files_enabled[2] = (int) v; return 0; } static int set_fsdevice_11_hide_cbm_files(resource_value_t v) { if (!fsdevice_convert_p00_enabled[3]) return -1; fsdevice_hide_cbm_files_enabled[3] = (int) v; return 0; } static resource_t resources[] = { { "FSDevice8ConvertP00", RES_INTEGER, (resource_value_t) 1, (resource_value_t *) &fsdevice_convert_p00_enabled[0], set_fsdevice_8_convert_p00 }, { "FSDevice9ConvertP00", RES_INTEGER, (resource_value_t) 1, (resource_value_t *) &fsdevice_convert_p00_enabled[1], set_fsdevice_9_convert_p00 }, { "FSDevice10ConvertP00", RES_INTEGER, (resource_value_t) 1, (resource_value_t *) &fsdevice_convert_p00_enabled[2], set_fsdevice_10_convert_p00 }, { "FSDevice11ConvertP00", RES_INTEGER, (resource_value_t) 1, (resource_value_t *) &fsdevice_convert_p00_enabled[3], set_fsdevice_11_convert_p00 }, { "FSDevice8Dir", RES_STRING, (resource_value_t) ".", (resource_value_t *) &fsdevice_8_dir, set_fsdevice_8_dir }, { "FSDevice9Dir", RES_STRING, (resource_value_t) ".", (resource_value_t *) &fsdevice_9_dir, set_fsdevice_9_dir }, { "FSDevice10Dir", RES_STRING, (resource_value_t) ".", (resource_value_t *) &fsdevice_10_dir, set_fsdevice_10_dir }, { "FSDevice11Dir", RES_STRING, (resource_value_t) ".", (resource_value_t *) &fsdevice_11_dir, set_fsdevice_11_dir }, { "FSDevice8SaveP00", RES_INTEGER, (resource_value_t) 1, (resource_value_t *) &fsdevice_save_p00_enabled[0], set_fsdevice_8_save_p00 }, { "FSDevice9SaveP00", RES_INTEGER, (resource_value_t) 1, (resource_value_t *) &fsdevice_save_p00_enabled[1], set_fsdevice_9_save_p00 }, { "FSDevice10SaveP00", RES_INTEGER, (resource_value_t) 1, (resource_value_t *) &fsdevice_save_p00_enabled[2], set_fsdevice_10_save_p00 }, { "FSDevice11SaveP00", RES_INTEGER, (resource_value_t) 1, (resource_value_t *) &fsdevice_save_p00_enabled[3], set_fsdevice_11_save_p00 }, { "FSDevice8HideCBMFiles", RES_INTEGER, (resource_value_t) 0, (resource_value_t *) &fsdevice_hide_cbm_files_enabled[0], set_fsdevice_8_hide_cbm_files }, { "FSDevice9HideCBMFiles", RES_INTEGER, (resource_value_t) 0, (resource_value_t *) &fsdevice_hide_cbm_files_enabled[1], set_fsdevice_9_hide_cbm_files }, { "FSDevice10HideCBMFiles", RES_INTEGER, (resource_value_t) 0, (resource_value_t *) &fsdevice_hide_cbm_files_enabled[2], set_fsdevice_10_hide_cbm_files }, { "FSDevice11HideCBMFiles", RES_INTEGER, (resource_value_t) 0, (resource_value_t *) &fsdevice_hide_cbm_files_enabled[3], set_fsdevice_11_hide_cbm_files }, { NULL } }; int fsdevice_init_resources(void) { return resources_register(resources); } /* ------------------------------------------------------------------------- */ static int cmdline_fsdirectory(const char *param, void *extra_param) { int unit = (int) extra_param; char directory[MAXPATHLEN]; strcpy(directory, param); strcat(directory, "/"); switch (unit) { case 8: set_fsdevice_8_dir((resource_value_t) directory); break; case 9: set_fsdevice_9_dir((resource_value_t) directory); break; case 10: set_fsdevice_10_dir((resource_value_t) directory); break; case 11: set_fsdevice_11_dir((resource_value_t) directory); break; default: fprintf(stderr, "cmdline_fsdirectory(): unexpected unit number %d?!\n", unit); } return 0; } static cmdline_option_t cmdline_options[] = { { "-fs8", CALL_FUNCTION, 1, cmdline_fsdirectory, (void *) 8, NULL, NULL, "<name>", "Use <name> as directory for file system device #8" }, { "-fs9", CALL_FUNCTION, 1, cmdline_fsdirectory, (void *) 9, NULL, NULL, "<name>", "Use <name> as directory for file system device #9" }, { "-fs10", CALL_FUNCTION, 1, cmdline_fsdirectory, (void *) 10, NULL, NULL, "<name>", "Use <name> as directory for file system device #10" }, { "-fs11", CALL_FUNCTION, 1, cmdline_fsdirectory, (void *) 11, NULL, NULL, "<name>", "Use <name> as directory for file system device #11" }, { NULL } }; int fsdevice_init_cmdline_options(void) { return cmdline_register_options(cmdline_options); } /* ------------------------------------------------------------------------- */ int attach_fsdevice(int device, char *var, char *name) { if (serial_attach_device(device, (char *) var, (char *) name, read_fs, write_fs, open_fs, close_fs, flush_fs)) return 1; fs_error(IPE_DOS_VERSION); return 0; } void fsdevice_set_directory(char *filename, int unit) { #if 0 char *p; /* FIXME: Remove this once the select directory dialog is available. */ p = strrchr(filename, '/'); *(++p) = '\0'; #endif switch (unit) { case 8: set_fsdevice_8_dir((resource_value_t) filename); break; case 9: set_fsdevice_9_dir((resource_value_t) filename); break; case 10: set_fsdevice_10_dir((resource_value_t) filename); break; case 11: set_fsdevice_11_dir((resource_value_t) filename); break; } return; } static char *fsdevice_get_path(int unit) { switch (unit) { case 8: return fsdevice_8_dir; break; case 9: return fsdevice_9_dir; break; case 10: return fsdevice_10_dir; break; case 11: return fsdevice_11_dir; break; } return NULL; } void fs_error(int code) { static int last_code; char *message; /* Only set an error once per command */ if (code != IPE_OK && last_code != IPE_OK && last_code != IPE_DOS_VERSION) return; last_code = code; if (code == IPE_DOS_VERSION) { message = "VICE FS DRIVER V2.0"; } else { errortext_t *e; e = &floppy_error_messages; while (e->nr >= 0 && e->nr != code) e++; if (e->nr >= 0) message = e->text; else message = "UNKNOWN ERROR NUMBER"; } sprintf(fs_errorl, "%02d,%s,00,00\015", code, message); fs_elen = strlen(fs_errorl); fs_eptr = 0; if (code && code != IPE_DOS_VERSION) fprintf(stderr, "UnixFS: ERR = %02d, %s\n", code, message); } void flush_fs(void *flp, int secondary) { DRIVE *floppy = (DRIVE *)flp; char *cmd, *realarg, *arg, *realarg2 = NULL, *arg2 = NULL; char cbmcmd[MAXPATHLEN], name1[MAXPATHLEN], name2[MAXPATHLEN]; int er = IPE_SYNTAX; FILE *fd; if (secondary != 15 || !fs_cptr) return; /* remove trailing cr */ while (fs_cptr && (fs_cmdbuf[fs_cptr - 1] == 13)) fs_cptr--; fs_cmdbuf[fs_cptr] = 0; strcpy(cbmcmd, fs_cmdbuf); petconvstring(cbmcmd, 1); /* CBM name to FSname */ cmd = cbmcmd; while (*cmd == ' ') cmd++; arg = strchr(cbmcmd, ':'); if (arg) { *arg++ = '\0'; } realarg = strchr(fs_cmdbuf, ':'); if (realarg) { *realarg++ = '\0'; } #ifdef DEBUG_FS printf("Flush_FS: command='%s', cmd='%s'\n", cmd, arg); #endif if (!strcmp(cmd, "cd")) { er = IPE_OK; if (chdir(arg)) { er = IPE_NOT_FOUND; if (errno == EPERM) er = IPE_PERMISSION; } } else if (!strcmp(cmd, "md")) { er = IPE_OK; if (mkdir(arg, /*S_IFDIR | */ 0770)) { er = IPE_INVAL; if (errno == EEXIST) er = IPE_FILE_EXISTS; if (errno == EACCES) er = IPE_PERMISSION; if (errno == ENOENT) er = IPE_NOT_FOUND; } } else if (!strcmp(cmd, "rd")) { er = IPE_OK; if (rmdir(arg)) { er = IPE_NOT_EMPTY; if (errno == EPERM) er = IPE_PERMISSION; } } else if (*cmd == 's') { er = IPE_DELETED; fd = fs_find_pc64_name(flp, realarg, strlen(realarg), name1); if (fd != NULL) { fclose(fd); } else { if (fsdevice_hide_cbm_files_enabled[floppy->unit - 8]) { fs_error(IPE_NOT_FOUND); fs_cptr = 0; return; } strcpy(name1, fsdevice_get_path(floppy->unit)); strcat(name1, "/"); strcat(name1, arg); } if (unlink(name1)) { er = IPE_NOT_FOUND; if (errno == EPERM) er = IPE_PERMISSION; } } else if (*cmd == 'r') { if ((arg2 = strchr(arg, '='))) { char name2long[MAXPATHLEN]; er = IPE_OK; *arg2++ = 0; realarg2 = strchr(realarg, '='); *realarg2++ = 0; fd = fs_find_pc64_name(flp, realarg2, strlen(realarg2), name2long); if (fd != NULL) { /* Rename P00 file. */ int name1len; char *p, p00name[17], p00type, p00count[2]; char name1p00[MAXPATHLEN], name2p00[MAXPATHLEN]; fclose(fd); strcpy(name2p00, name2long); p = strrchr(name2long, '.'); p00type = p[1]; *p = '\0'; p = strrchr(name2long, '/'); strcpy(name2, ++p); name1len = fsdevice_evaluate_name_p00(realarg, strlen(realarg), name1); name1[name1len] = '\0'; memset(p00name, 0, 17); strncpy(p00name, realarg, 16); fd = fopen(name2p00, "r+"); if (fd) { if ((fseek(fd, 8, SEEK_SET) != 0) || (fwrite(p00name, 16, 1, fd) < 1)) er = IPE_NOT_FOUND; fclose(fd); } else { er = IPE_NOT_FOUND; } if (er == IPE_OK && strcmp(name1, name2) != 0) { int i; for (i = 0; i < 100; i++) { memset(name1p00, 0, MAXPATHLEN); strcpy(name1p00, fsdevice_get_path(floppy->unit)); strcat(name1p00, "/"); strcat(name1p00, name1); strcat(name1p00, "."); strncat(name1p00, &p00type, 1); sprintf(p00count, "%02i", i); strncat(name1p00, p00count, 2); fd = fopen(name1p00, READ); if (fd) { fclose(fd); continue; } if (rename(name2p00, name1p00) == 0) break; } } } else { /* Rename CBM file. */ if (fsdevice_hide_cbm_files_enabled[floppy->unit - 8]) { fs_error(IPE_NOT_FOUND); fs_cptr = 0; return; } strcpy(name1, fsdevice_get_path(floppy->unit)); strcat(name1, "/"); strcat(name1, arg); strcpy(name2, fsdevice_get_path(floppy->unit)); strcat(name2, "/"); strcat(name2, arg2); if (rename(name2, name1)) { er = IPE_NOT_FOUND; if (errno == EPERM) er = IPE_PERMISSION; } } } } fs_error(er); fs_cptr = 0; } int write_fs(void *flp, BYTE data, int secondary) { if (secondary == 15) { #ifdef DEBUG_FS_ printf("Write_FS(secadr=15, data=%02x, '%c')\n", data, data); #endif if (fs_cptr < MAXPATHLEN - 1) { /* keep place for nullbyte */ fs_cmdbuf[fs_cptr++] = data; return SERIAL_OK; } else { fs_error(IPE_LONG_LINE); return SERIAL_ERROR; } } if (fs_info[secondary].mode != Write && fs_info[secondary].mode != Append) return FLOPPY_ERROR; if (fs_info[secondary].fd) { fputc(data, fs_info[secondary].fd); return FLOPPY_COMMAND_OK; }; return FLOPPY_ERROR; } int read_fs(void *flp, BYTE * data, int secondary) { DRIVE *floppy = (DRIVE *)flp; int i, l, f; unsigned short blocks; struct dirent *dirp; /* defined in /usr/include/sys/dirent.h */ struct stat statbuf; struct fs_buffer_info *info = &fs_info[secondary]; char rname[256]; if (secondary == 15) { if (!fs_elen) fs_error(IPE_OK); if (fs_eptr < fs_elen) { *data = fs_errorl[fs_eptr++]; #ifdef DEBUG_FS printf("Read_FS(secadr=15) reads '%c'\n", *data); #endif return SERIAL_OK; } else { fs_error(IPE_OK); *data = 0xc7; return SERIAL_EOF; } } switch (info->mode) { case Write: case Append: return FLOPPY_ERROR; case Read: if (info->fd) { i = fgetc(info->fd); if (ferror(info->fd)) return FLOPPY_ERROR; if (feof(info->fd)) { *data = 0xc7; return SERIAL_EOF; } *data = i; return SERIAL_OK; } break; case Directory: if (info->dp) { if (info->buflen <= 0) { char buf[MAXPATHLEN]; #ifdef DEBUG_FSDRIVE printf("reading\n"); #endif info->bufp = info->name; if (info->eof) { *data = 0xc7; return SERIAL_EOF; } /* * Find the next directory entry and return it as a CBM * directory line. */ /* first test if dirmask is needed - maybe this should be replaced by some regex functions... */ #ifdef DEBUG_FS printf("FS_ReadDir: mask ='%s'\n", fs_dirmask); #endif f = 1; do { char *p; dirp = readdir(info->dp); if (!dirp) break; #ifdef DEBUG_FS printf("FS_ReadDir: testing file '%s'\n", dirp->d_name); #endif fs_info[secondary].type = FT_PRG; strcpy(rname, dirp->d_name); if (fsdevice_convert_p00_enabled[(floppy->unit) - 8]) fs_test_pc64_name(flp, rname, secondary); if (strcmp(rname, dirp->d_name) == 0 && fsdevice_hide_cbm_files_enabled[floppy->unit - 8]) continue; if (!*fs_dirmask) break; l = strlen(fs_dirmask); for (p = rname, i = 0; *p && fs_dirmask[i] && i < l; i++) { if (fs_dirmask[i] == '?') { p++; } else if (fs_dirmask[i] == '*') { if (!fs_dirmask[i + 1]) { f = 0; break; } /* end mask */ while (*p && (*p != fs_dirmask[i + 1])) p++; } else { if (*p != fs_dirmask[i]) break; p++; } if ((!*p) && (!fs_dirmask[i + 1])) { f = 0; break; } } } while (f); #ifdef DEBUG_FS printf("FS_ReadDir: printing file '%s'\n", dirp ? rname : NULL); #endif if (dirp != NULL) { BYTE *p = info->name; char *tp; strcpy(buf, info->dir); strcat(buf, "/"); tp = buf + strlen(buf); strcat(buf, dirp->d_name); /* Line link, Length and spaces */ p += 2; /* skip link addr, fill in later */ if (stat(buf, &statbuf) < 0) blocks = 0; /* this file can't be opened */ else blocks = (unsigned short) ((statbuf.st_size + 253) / 254); SET_LO_HI(p, blocks); if (blocks < 10) *p++ = ' '; if (blocks < 100) *p++ = ' '; if (blocks < 1000) *p++ = ' '; *p++ = ' '; /* * Filename */ *p++ = '"'; if (strcmp(rname, dirp->d_name)) { for (i = 0; rname[i] && (*p = rname[i]); ++i, ++p); } else { for (i = 0; tp[i] /*i < dirp->d_namlen */ && (*p = p_topetcii(tp[i] /*dirp->d_name[i] */ )); ++i, ++p); } *p++ = '"'; for (; i < 17; i++) *p++ = ' '; if (S_ISDIR(statbuf.st_mode)) { *p++ = 'D'; *p++ = 'I'; *p++ = 'R'; } else { switch(fs_info[secondary].type) { case FT_DEL: *p++ = 'D'; *p++ = 'E'; *p++ = 'L'; break; case FT_SEQ: *p++ = 'S'; *p++ = 'E'; *p++ = 'Q'; break; case FT_PRG: *p++ = 'P'; *p++ = 'R'; *p++ = 'G'; break; case FT_USR: *p++ = 'U'; *p++ = 'S'; *p++ = 'R'; break; case FT_REL: *p++ = 'R'; *p++ = 'E'; *p++ = 'L'; break; } } *p = '\0'; /* to allow strlen */ /* some (really very) old programs rely on the directory entry to be 32 Bytes in total (incl. nullbyte) */ l = strlen((char *) (info->name + 4)) + 4; while (l < 31) { *p++ = ' '; l++; } *p++ = '\0'; info->dirmpos += p - info->name; *info->name = info->dirmpos & 0xff; *(info->name + 1) = (info->dirmpos >> 8) & 0xff; info->buflen = (int) (p - info->name); #ifdef DEBUG_FSDRIVE printf("found %4d>%s< (%d) buf:>%s< (%d)\n", blocks, dirp->d_name, i, info->name + 4, info->buflen); #endif } else { /* EOF => End file */ memset(info->name, 0, 2); info->buflen = 2; info->eof++; } } /* info->buflen */ *data = *info->bufp++; info->buflen--; return SERIAL_OK; } /* info->dp */ break; } return FLOPPY_ERROR; } int open_fs(void *flp, char *name, int length, int secondary) { DRIVE *floppy = (DRIVE *)flp; FILE *fd; DIR *dp; BYTE *p, *linkp; char fsname[MAXPATHLEN], fsname2[MAXPATHLEN], rname[MAXPATHLEN]; char *mask, *comma; int status = 0, i, reallength, readmode, rl; if (fs_info[secondary].fd) return FLOPPY_ERROR; memcpy(fsname2, name, length); fsname2[length] = 0; if (secondary == 15) { #ifdef DEBUG_FS printf("Open_FS(secadr=15, name='%s'\n", fsname2); #endif for (i = 0; i < length; i++) { status = write_fs(flp, name[i], 15); } return status; } if (secondary == 1) readmode = FAM_WRITE; else readmode = FAM_READ; rl = 0; if (floppy_parse_name(fsname2, length, fsname, &reallength, &readmode, &fs_info[secondary].type, &rl) != SERIAL_OK) return SERIAL_ERROR; if (fs_info[secondary].type == FT_DEL) fs_info[secondary].type = (secondary < 2) ? FT_PRG : FT_SEQ; fsname[reallength] = 0; strncpy(rname, fsname, reallength); petconvstring(fsname, 1); /* CBM name to FSname */ switch (readmode) { case FAM_WRITE: fs_info[secondary].mode = Write; break; case FAM_READ: fs_info[secondary].mode = Read; break; case FAM_APPEND: fs_info[secondary].mode = Append; break; } if (*name == '$') { /* Directory read */ if ((secondary != 0) || (fs_info[secondary].mode != Read)) { fs_error(IPE_NOT_WRITE); return FLOPPY_ERROR; } /* Test on wildcards. */ if (!(mask = strrchr(fsname, '/'))) mask = fsname; if (strchr(mask, '*') || strchr(mask, '?')) { if (*mask == '/') { strcpy(fs_dirmask, mask + 1); *mask++ = 0; } else { strcpy(fs_dirmask, mask); strcpy(fsname, fsdevice_get_path(floppy->unit)); } } else { *fs_dirmask = 0; if (!*fsname) strcpy(fsname, fsdevice_get_path(floppy->unit)); } #ifdef DEBUG_FS printf("Opening Dir with dir='%s', mask='%s')\n", fsname, fs_dirmask); #endif /* trying to open */ if (!(dp = opendir((char *) fsname))) { for (p = (BYTE *) fsname; *p; p++) if (isupper(*p)) *p = tolower(*p); if (!(dp = opendir((char *) fsname))) { fs_error(IPE_NOT_FOUND); return FLOPPY_ERROR; } } strcpy(fs_info[secondary].dir, fsname); /* * Start Address, Line Link and Line number 0 */ p = fs_info[secondary].name; *p++ = 1; *p++ = 4; linkp = p; p += 2; *p++ = 0; *p++ = 0; *p++ = (BYTE) 0x12; /* Reverse on */ *p++ = '"'; strcpy((char *) p, fs_info[secondary].dir); /* Dir name */ petconvstring((char *) p, 0); /* ASCII name to PETSCII */ i = 0; while (*p) { ++p; i++; } while (i < 16) { *p++ = ' '; i++; } *p++ = '"'; while (i < 22) { *p++ = ' '; i++; } *p++ = 0; i = 0x0401 + p - linkp; *linkp = i & 0xff; *(linkp + 1) = (i >> 8) & 0xff; fs_info[secondary].buflen = p - fs_info[secondary].name; fs_info[secondary].bufp = fs_info[secondary].name; fs_info[secondary].mode = Directory; fs_info[secondary].dp = dp; fs_info[secondary].eof = 0; fs_info[secondary].dirmpos = i; /* start address of next line */ #ifdef DEBUG_FSDRIVE printf("opened directory\n"); #endif } else { /* Normal file, not directory ("$") */ /* Override access mode if secondary address is 0 or 1. */ if (secondary == 0) fs_info[secondary].mode = Read; if (secondary == 1) fs_info[secondary].mode = Write; /* Remove comma. */ if (fsname[0] == ',') { fsname[1] = '\0'; } else { comma = strchr(fsname, ','); if (comma != NULL) *comma = '\0'; } if (name[0] == ',') { name[1] = '\0'; } else { comma = memchr(name, ',', length); if (comma != NULL) { *comma = '\0'; length = strlen(name); } } strcpy(fsname2, fsname); strcpy(fsname, fsdevice_get_path(floppy->unit)); strcat(fsname, "/"); strcat(fsname, fsname2); #ifdef DEBUG_FSDRIVE printf("Open file name '%s' (before wildcard expansion).\n", fsname); #endif /* Test on wildcards. */ if (strchr(fsname2, '*') || strchr(fsname2, '?')) { if (fs_info[secondary].mode == Write || fs_info[secondary].mode == Append) { fs_error(IPE_BAD_NAME); return FLOPPY_ERROR; } else { fsdevice_compare_file_name(flp, fsname2, fsname, secondary); } } #ifdef DEBUG_FSDRIVE printf("Open file name '%s' (after wildcard expansion).\n", fsname); #endif /* Open file for write mode access. */ if (fs_info[secondary].mode == Write) { fd = fopen(fsname, READ); if (fd > 0) { fclose(fd); fs_error(IPE_FILE_EXISTS); return FLOPPY_ERROR; } if (fsdevice_convert_p00_enabled[(floppy->unit) - 8]) { fd = fs_find_pc64_name(flp, rname, reallength, fsname2); if (fd > 0) { fclose(fd); fs_error(IPE_FILE_EXISTS); return FLOPPY_ERROR; } } if (fsdevice_save_p00_enabled[(floppy->unit) - 8]) { if (fsdevice_create_file_p00(flp, rname, reallength, fsname, secondary) > 0) { fs_error(IPE_FILE_EXISTS); return FLOPPY_ERROR; } else { fd = fopen(fsname, "a+"); fs_info[secondary].fd = fd; fs_error(IPE_OK); return FLOPPY_COMMAND_OK; } } else { fd = fopen(fsname, WRITE); fs_info[secondary].fd = fd; fs_error(IPE_OK); return FLOPPY_COMMAND_OK; } } /* Open file for append mode access. */ if (fs_info[secondary].mode == Append) { fd = fopen(fsname, READ); if (!fd) { if (!fsdevice_convert_p00_enabled[(floppy->unit) - 8]) { fs_error(IPE_NOT_FOUND); return FLOPPY_ERROR; } fd = fs_find_pc64_name(flp, rname, reallength, fsname2); if (!fd) { fs_error(IPE_NOT_FOUND); return FLOPPY_ERROR; } fclose(fd); fd = fopen(fsname2, "a+"); if (!fd) { fs_error(IPE_NOT_FOUND); return FLOPPY_ERROR; } fs_info[secondary].fd = fd; fs_error(IPE_OK); return FLOPPY_COMMAND_OK; } else { fclose(fd); fd = fopen(fsname, "a+"); if (!fd) { fs_error(IPE_NOT_FOUND); return FLOPPY_ERROR; } fs_info[secondary].fd = fd; fs_error(IPE_OK); return FLOPPY_COMMAND_OK; } } /* Open file for read mode access. */ fd = fopen(fsname, READ); if (!fd) { if (!fsdevice_convert_p00_enabled[(floppy->unit) - 8]) { fs_error(IPE_NOT_FOUND); return FLOPPY_ERROR; } fd = fs_find_pc64_name(flp, rname, reallength, fsname2); if (!fd) { fs_error(IPE_NOT_FOUND); return FLOPPY_ERROR; } fs_info[secondary].fd = fd; fs_error(IPE_OK); return FLOPPY_COMMAND_OK; } else { if (fsdevice_hide_cbm_files_enabled[floppy->unit - 8]) { fclose(fd); fs_error(IPE_NOT_FOUND); return FLOPPY_ERROR; } fs_info[secondary].fd = fd; fs_error(IPE_OK); return FLOPPY_COMMAND_OK; } } fs_error(IPE_OK); return FLOPPY_COMMAND_OK; } int close_fs(void *flp, int secondary) { if (secondary == 15) { #ifdef DEBUG_FS printf("Close_FS(secadr=15)\n"); #endif fs_error(IPE_OK); return FLOPPY_COMMAND_OK; } switch (fs_info[secondary].mode) { case Write: case Read: case Append: if (!fs_info[secondary].fd) return FLOPPY_ERROR; fclose(fs_info[secondary].fd); fs_info[secondary].fd = NULL; break; case Directory: if (!fs_info[secondary].dp) return FLOPPY_ERROR; closedir(fs_info[secondary].dp); fs_info[secondary].dp = NULL; break; } return FLOPPY_COMMAND_OK; } void fs_test_pc64_name(void *flp, char *rname, int secondary) { DRIVE *floppy = (DRIVE *)flp; char p00id[8]; char p00name[17]; char pathname[MAXPATHLEN]; FILE *fd; int tmptype; tmptype = is_pc64name(rname); if (tmptype >= 0) { strcpy(pathname, fsdevice_get_path(floppy->unit)); strcat(pathname, "/"); strcat(pathname, rname); fd = fopen(pathname, READ); if (!fd) return; fread((char *) p00id, 8, 1, fd); if (ferror(fd)) { fclose(fd); return; } p00id[7] = '\0'; if (!strncmp(p00id, "C64File", 7)) { fread((char *) p00name, 16, 1, fd); if (ferror(fd)) { fclose(fd); return; } fs_info[secondary].type = tmptype; p00name[16] = '\0'; strcpy(rname, p00name); fclose(fd); return; } fclose(fd); } } FILE *fs_find_pc64_name(void *flp, char *name, int length, char *pname) { DRIVE *floppy = (DRIVE *)flp; struct dirent *dirp; char *p; DIR *dp; char p00id[8], p00name[17], p00dummy[2]; FILE *fd; name[length] = '\0'; dp = opendir(fsdevice_get_path(floppy->unit)); do { dirp = readdir(dp); if (dirp != NULL) { strcpy(pname, fsdevice_get_path(floppy->unit)); strcat(pname, "/"); strcat(pname, dirp->d_name); p = pname; if (is_pc64name(p) >= 0) { fd = fopen(p, READ); if (!fd) continue; fread((char *) p00id, 8, 1, fd); if (ferror(fd)) { fclose(fd); continue; } p00id[7] = '\0'; if (!strncmp(p00id, "C64File", 7)) { fread((char *) p00name, 16, 1, fd); if (ferror(fd)) { fclose(fd); continue; } p00name[16] = '\0'; if (fsdevice_compare_wildcards(name, p00name) > 0) { fread((char *) p00dummy, 2, 1, fd); if (ferror(fd)) { fclose(fd); continue; } return fd; } } fclose(fd); } } } while (dirp != NULL); closedir(dp); return NULL; } static int fsdevice_compare_wildcards(char *name, char *p00name) { int i, len; len = strlen(name); if (len == 0) return 0; for (i = 0; i < len; i++) { if (name[i] == '*') return 1; if (name[i] != '?' && name[i] != p00name[i]) return 0; } return 1; } static void fsdevice_compare_file_name(void *flp, char *fsname2, char *fsname, int secondary) { DRIVE *floppy = (DRIVE *)flp; struct dirent *dirp; DIR *dp; char rname[MAXPATHLEN]; dp = opendir(fsdevice_get_path(floppy->unit)); do { dirp = readdir(dp); if (dirp != NULL) { if (fsdevice_compare_wildcards(fsname2, dirp->d_name) > 0) { strcpy(rname, dirp->d_name); fs_test_pc64_name(flp, rname, secondary); if (strcmp(rname, dirp->d_name) == 0) { strcpy(fsname, fsdevice_get_path(floppy->unit)); strcat(fsname, "/"); strcat(fsname, dirp->d_name); closedir(dp); return; } } } } while (dirp != NULL); closedir(dp); return; } static int fsdevice_create_file_p00(void *flp, char *name, int length, char *fsname, int secondary) { DRIVE *floppy = (DRIVE *)flp; char filename[17], realname[16]; int i, len; FILE *fd; if (length > 16) length = 16; memset(realname, 0, 16); strncpy(realname, name, length); len = fsdevice_evaluate_name_p00(name, length, filename); strcpy(fsname, fsdevice_get_path(floppy->unit)); strcat(fsname, "/"); strncat(fsname, filename, len); switch (fs_info[secondary].type) { case FT_DEL: strcat(fsname, ".D"); break; case FT_SEQ: strcat(fsname, ".S"); break; case FT_PRG: strcat(fsname, ".P"); break; case FT_USR: strcat(fsname, ".U"); break; case FT_REL: strcat(fsname, ".R"); break; } strcat(fsname, "00"); for (i = 1; i < 100; i++) { fd = fopen(fsname, READ); if (!fd) break; fclose(fd); sprintf(&fsname[strlen(fsname) - 2], "%02i", i); } if (i >= 100) return 1; fd = fopen(fsname, WRITE); if (!fd) return 1; if (fwrite("C64File", 8, 1, fd) < 1) { fclose(fd); return 1; } if (fwrite(realname, 16, 1, fd) < 1) { fclose(fd); return 1; } if (fwrite("\0\0", 2, 1, fd) < 1) { fclose(fd); return 1; } fclose(fd); return 0; } static int fsdevice_reduce_filename_p00(char *filename, int len) { int i, j; for (i = len - 1; i >= 0; i--) { if (filename[i] == '_') if (fsdevice_eliminate_char_p00(filename, i) <= 8) return 8; } for (i = 0; i < len; i++) { if (strchr("AEIOU", filename[i]) != NULL) break; } for (j = len - 1; j >= i; j--) { if (strchr("AEIOU", filename[j]) != NULL) if (fsdevice_eliminate_char_p00(filename, j) <= 8) return 8; } for (i = len - 1; i >= 0; i--) { if (isalpha(filename[i])) if (fsdevice_eliminate_char_p00(filename, i) <= 8) return 8; } for (i = len - 1; i >= 0; i--) if (fsdevice_eliminate_char_p00(filename, i) <= 8) return 8; return 1; } static int fsdevice_eliminate_char_p00(char *filename, int pos) { memcpy(&filename[pos], &filename[pos+1], 16 - pos); return strlen(filename); } static int fsdevice_evaluate_name_p00(char *name, int length, char *filename) { int i, j; memset(filename, 0, 17); for (i = 0, j = 0; i < length; i++) { switch (name[i]) { case ' ': case '-': filename[j++] = '_'; break; default: if (islower(name[i])) { filename[j++] = toupper(name[i]); break; } if (isalnum(name[i])) { filename[j++] = name[i]; break; } } } if (j == 0) { strcpy(filename, "_"); j++; } return ((j > 8) ? fsdevice_reduce_filename_p00(filename, j) : j); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.