24 #include <sys/types.h>
33 #define DEBUG_HOSTFS printf
135 #define WRITE_BUFFER_SIZE 256
136 #define READ_BUFFER_SIZE 256
137 #define SPEC_BUFFER_SIZE 4096
138 #define CBM_MAX_DIR_ENTRIES 144
152 static Uint8 hfs_status;
155 static int spec_filling_index;
156 static int last_command;
158 static char hostfs_directory[PATH_MAX];
162 static Uint8 set_error (
int status,
int errorcode,
int tracknum,
int sectnum,
const char *description )
167 case 0: p =
"OK";
break;
168 case 73: p =
"XEMU SOFTWARE CBM-DOS SUBSET";
break;
170 p =
"UNHANDLED XEMU ERROR";
171 fprintf(stderr,
"HOSTFS DOS: error code %02d is not defined, please report this." NL, errorcode);
174 hostfs_channels[15].
read_used = sprintf((
char*)hostfs_channels[15].
read_buffer,
"%02d, %s,%02d,%02d", errorcode, p, tracknum, sectnum);
175 DEBUG_HOSTFS(
"HOSTFS: error (host_status=%d) is set to \"%s\": %s." NL,
status, (
char*)hostfs_channels[15].
read_buffer, description ? description :
"-");
179 #define NO_ERROR() set_error(0, 0, 0, 0, NULL)
189 MKDIR(hostfs_directory);
191 sprintf(hostfs_directory,
"%s" DIRSEP_STR, basedir);
194 dir = opendir(hostfs_directory);
196 ERROR_WINDOW(
"Warning, specified hostFS directory (%s) cannot be used, you will have problems: %s", hostfs_directory, strerror(errno));
200 for (a = 0; a < 16; a++) {
201 hostfs_channels[a].
id = a;
202 hostfs_channels[a].
dir = NULL;
203 hostfs_channels[a].
fd = -1;
211 set_error(0, 73, 0, 0,
"init");
214 printf(
"HOSTFS: init @ %s" NL, hostfs_directory);
230 FATAL(
"HOSTFS: cannot write file, error got: %s", strerror(errno));
233 FATAL(
"HOSTFS: cannot write file, zero bytes could written!");
249 closedir(channel->
dir);
250 if (channel->
fd >= 0) {
251 hostfs_flush(channel);
265 for (channel = 0; channel < 16; channel++)
266 hostfs_close(hostfs_channels + channel);
273 for (channel = 0; channel < 16; channel++)
274 hostfs_flush(hostfs_channels + channel);
284 static const char banned_hostfilename_chars[] =
":;,/\\#$=*?@";
285 static int filename_host2cbm (
const Uint8 *in,
Uint8 *out,
int maxlen)
294 if (++len > maxlen || c < 32 || c > 126 || strchr(banned_hostfilename_chars, c))
296 if (c >= 97 && c <= 122)
305 static int xemu_stat_at (
const char *dirname,
const char *filename,
struct stat *
st )
307 char namebuffer[PATH_MAX];
308 if (snprintf(namebuffer,
sizeof namebuffer,
"%s" DIRSEP_STR "%s", dirname, filename) >=
sizeof namebuffer) {
309 errno = ENAMETOOLONG;
312 return stat(namebuffer,
st);
316 static int xemu_open_at (
const char *dirname,
const char *filename,
int flags, mode_t mode )
318 char namebuffer[PATH_MAX];
319 if (snprintf(namebuffer,
sizeof namebuffer,
"%s" DIRSEP_STR "%s", dirname, filename) >=
sizeof namebuffer) {
320 errno = ENAMETOOLONG;
323 return open(namebuffer,
flags, mode);
330 #define CBM_DIR_LOAD_ADDRESS 0x0401
333 static const Uint8 dirheadline[] = {
338 'X',
'E',
'M',
'U',
'-',
'C',
'B',
'M',
' ',
'H',
'O',
'S',
'T',
'-',
'F',
'S',
339 '"',
' ',
'X',
'E',
' ',
'M',
'U',0
341 static const Uint8 dirtailline[] = {
344 'B',
'L',
'O',
'C',
'K',
'S',
' ',
'F',
'R',
'E',
'E',
'.',
345 ' ',
' ',
' ',
' ',
' ',
' ',
' ',
' ',
' ',
' ',
' ',
' ',
' ',
357 memcpy(channel->
read_buffer, dirheadline,
sizeof dirheadline);
367 struct dirent *entry = readdir(channel->
dir);
373 if (!(namelength = filename_host2cbm((
Uint8*)entry->d_name, filename, 16)))
375 if (xemu_stat_at(hostfs_directory, entry->d_name, &
st))
377 if (!S_ISREG(
st.st_mode) && !S_ISDIR(
st.st_mode))
380 goto too_many_entries;
385 st.st_size = (
st.st_size + 253) / 254;
386 i =
st.st_size > 0xFFFF ? 0xFFFF :
st.st_size;
389 if (i < 10) *(p++) =
' ';
390 if (i < 100) *(p++) =
' ';
391 if (i < 1000) *(p++) =
' ';
393 for (i = 0; i < 16; i++)
394 *(p++) = i < namelength ? filename[i] : (i == namelength ?
'"' :
' ');
395 if (S_ISDIR(
st.st_mode)) {
401 *(p++) =
st.st_size ?
' ' :
'*';
411 closedir(channel->
dir);
416 memcpy(channel->
read_buffer, dirtailline,
sizeof dirtailline);
427 if (c >= 65 && c <= 90)
429 if (c >= 193 && c <= 218)
439 if (channel->
id == 15) {
440 FATAL(
"Sorry, channel#15 is not supported yet, and you must not use it!");
442 hostfs_close(channel);
443 if (spec_used[0] == 0) {
452 if (spec_used[0] ==
'$') {
453 channel->
dir = opendir(hostfs_directory);
456 DEBUG_HOSTFS(
"HOSTFS: cannot open directory '%s': %s" NL, hostfs_directory, strerror(errno));
461 hfs_status = cbm_read_directory(channel);
467 struct dirent *entry;
468 char filename[PATH_MAX];
469 p1 = (
Uint8*)strchr((
char*)spec_used,
',');
472 flags = char_cbm2ascii(p1[1]);
479 p2 = (
Uint8*)strchr((
char*)p1 + 1,
',');
480 len = (int)(p1 - spec_used);
482 if (strchr((
char*)p2 + 1,
',')) {
486 flags = char_cbm2ascii(p2[1]);
488 flags = channel->
id == 1 ?
'w' :
'r';
490 len = strlen((
char*)spec_used);
491 flags = channel->
id == 1 ?
'w' :
'r';
493 if (len >= PATH_MAX) {
498 if (spec_used[0] ==
'@') {
505 if (len > 1 && p0[1] ==
':') {
550 memcpy(filename, p0, len);
552 p0 = (
Uint8*)filename;
554 *p0 = (*p0 ==
'/' || *p0 ==
'\\') ?
'.' : char_cbm2ascii(*p0);
557 dir = opendir(hostfs_directory);
560 DEBUG_HOSTFS(
"HOSTFS: cannot open directory '%s': %s" NL, hostfs_directory, strerror(errno));
567 while ((entry = readdir(
dir))) {
569 if (!strcasecmp(entry->d_name, filename)) {
573 if (xemu_stat_at(hostfs_directory, entry->d_name, &
st)) {
578 if (!S_ISREG(
st.st_mode)) {
585 channel->
fd = xemu_open_at(hostfs_directory, entry->d_name,
flags, 0666);
586 if (channel->
fd < 0) {
587 DEBUG_HOSTFS(
"HOSTFS: could not open host file '%s" DIRSEP_STR "%s': %s" NL, hostfs_directory, entry->d_name, strerror(errno));
598 if (
flags & O_CREAT) {
599 channel->
fd = xemu_open_at(hostfs_directory, filename,
flags, 0666);
600 if (channel->
fd < 0) {
601 DEBUG_HOSTFS(
"HOSTFS: could not create new host file entry '%s" DIRSEP_STR "%s': %s" NL, hostfs_directory, filename, strerror(errno));
604 DEBUG_HOSTFS(
"HOSTFS: great, new host file is created as '%s'" NL, filename);
609 DEBUG_HOSTFS(
"HOSTFS: no matching pattern found for opening file" NL);
619 Uint8 ret = hfs_status;
628 last_command =
data >> 4;
630 switch (last_command) {
632 spec_filling_index = 0;
638 spec_filling[spec_filling_index] = 0;
639 strcpy((
char*)spec_used, (
char*)spec_filling);
640 spec_filling_index = 0;
641 DEBUG_HOSTFS(
"HOSTFS: command=\"%s\" on channel #%d" NL, (
char*)spec_used, channel->
id);
642 hostfs_open(channel);
646 hostfs_open(channel);
649 hostfs_close(channel);
652 use_channel = channel;
672 if (last_command == 0) {
684 if (use_channel->
eof) {
691 if (use_channel->
dir) {
692 hfs_status = cbm_read_directory(use_channel);
697 if (use_channel->
fd < 0) {
704 use_channel->
eof = 1;
708 FATAL(
"read error @ hostFS!");
722 if (last_command == 0) {
726 spec_filling[spec_filling_index++] =
data;
739 if (use_channel->
fd < 0) {
744 hostfs_flush(use_channel);