Annotation of hatari/src/gemdos.c, revision 1.1.1.17

1.1       root        1: /*
1.1.1.5   root        2:   Hatari - gemdos.c
1.1       root        3: 
1.1.1.5   root        4:   This file is distributed under the GNU Public License, version 2 or at
                      5:   your option any later version. Read the file gpl.txt for details.
                      6: 
                      7:   GEMDOS intercept routines.
                      8:   These are used mainly for hard drive redirection of high level file routines.
1.1       root        9: 
1.1.1.17! root       10:   Host file names are handled case insensitively, so files on GEMDOS
        !            11:   drive emulation directories may be either in lower or upper case.
        !            12: 
        !            13:   Too long file and directory names and names with invalid characters
        !            14:   are converted to TOS compatible 8+3 names, but matching them back to
        !            15:   host names is slower and may match several such filenames (of which
        !            16:   first one will be returned), so using them should be avoided.
1.1.1.6   root       17: 
1.1.1.2   root       18:   Bugs/things to fix:
1.1.1.17! root       19:   * Host filenames are in many places limited to 255 chars (same as
        !            20:     on TOS), FILENAME_MAX should be used if that's a problem.
1.1.1.2   root       21:   * rmdir routine, can't remove dir with files in it. (another tos/unix difference)
                     22:   * Fix bugs, there are probably a few lurking around in here..
                     23: */
1.1.1.14  root       24: const char Gemdos_fileid[] = "Hatari gemdos.c : " __DATE__ " " __TIME__;
1.1.1.12  root       25: 
                     26: #include <config.h>
1.1       root       27: 
1.1.1.4   root       28: #include <sys/stat.h>
1.1.1.17! root       29: #include <sys/types.h>
        !            30: #include <utime.h>
1.1.1.4   root       31: #include <time.h>
                     32: #include <ctype.h>
                     33: #include <unistd.h>
1.1.1.12  root       34: #include <errno.h>
                     35: 
1.1       root       36: #include "main.h"
                     37: #include "cart.h"
1.1.1.2   root       38: #include "tos.h"
1.1.1.6   root       39: #include "configuration.h"
1.1       root       40: #include "file.h"
                     41: #include "floppy.h"
1.1.1.3   root       42: #include "hdc.h"
1.1       root       43: #include "gemdos.h"
1.1.1.11  root       44: #include "gemdos_defines.h"
                     45: #include "log.h"
1.1       root       46: #include "m68000.h"
                     47: #include "memorySnapShot.h"
                     48: #include "printer.h"
                     49: #include "rs232.h"
1.1.1.13  root       50: #include "statusbar.h"
1.1.1.11  root       51: #include "scandir.h"
1.1       root       52: #include "stMemory.h"
1.1.1.13  root       53: #include "str.h"
1.1.1.12  root       54: #include "hatari-glue.h"
                     55: #include "maccess.h"
1.1.1.7   root       56: 
1.1.1.6   root       57: 
1.1.1.11  root       58: /* Maximum supported length of a GEMDOS path: */
                     59: #define MAX_GEMDOS_PATH 256
1.1.1.3   root       60: 
1.1.1.17! root       61: /* Invalid characters in paths & filenames are replaced by this
        !            62:  * (valid but very uncommon GEMDOS file name character)
        !            63:  */
        !            64: #define INVALID_CHAR '@'
1.1.1.11  root       65: 
                     66: /* Have we re-directed GemDOS vector to our own routines yet? */
1.1.1.13  root       67: bool bInitGemDOS;
1.1.1.11  root       68: 
                     69: /* structure with all the drive-specific data for our emulated drives,
                     70:  * used by GEMDOS_EMU_ON macro
                     71:  */
1.1.1.2   root       72: EMULATEDDRIVE **emudrives = NULL;
                     73: 
1.1.1.11  root       74: #define  ISHARDDRIVE(Drive)  (Drive!=-1)
                     75: 
                     76: /*
                     77:   Disk Tranfer Address (DTA)
                     78: */
                     79: #define TOS_NAMELEN  14
                     80: 
                     81: typedef struct {
                     82:   Uint8 index[2];
                     83:   Uint8 magic[4];
                     84:   char dta_pat[TOS_NAMELEN];
                     85:   char dta_sattrib;
                     86:   char dta_attrib;
                     87:   Uint8 dta_time[2];
                     88:   Uint8 dta_date[2];
                     89:   Uint8 dta_size[4];
                     90:   char dta_name[TOS_NAMELEN];
                     91: } DTA;
                     92: 
                     93: #define DTA_MAGIC_NUMBER  0x12983476
                     94: #define MAX_DTAS_FILES    256      /* Must be ^2 */
                     95: #define CALL_PEXEC_ROUTINE 3       /* Call our cartridge pexec routine */
                     96: 
                     97: #define  BASE_FILEHANDLE     64    /* Our emulation handles - MUST not be valid TOS ones, but MUST be <256 */
                     98: #define  MAX_FILE_HANDLES    32    /* We can allow 32 files open at once */
                     99: 
1.1.1.15  root      100: /*
                    101:    DateTime structure used by TOS call $57 f_dattime
1.1.1.11  root      102:    Changed to fix potential problem with alignment.
                    103: */
                    104: typedef struct {
1.1.1.17! root      105:   Uint16 timeword;
        !           106:   Uint16 dateword;
1.1.1.11  root      107: } DATETIME;
                    108: 
1.1.1.6   root      109: typedef struct
1.1       root      110: {
1.1.1.13  root      111:        bool bUsed;
1.1.1.9   root      112:        FILE *FileHandle;
1.1.1.17! root      113:        /* TODO: host path might not fit into this */
1.1.1.11  root      114:        char szActualName[MAX_GEMDOS_PATH];        /* used by F_DATIME (0x57) */
1.1       root      115: } FILE_HANDLE;
                    116: 
1.1.1.6   root      117: typedef struct
1.1.1.2   root      118: {
1.1.1.13  root      119:        bool bUsed;
1.1.1.9   root      120:        int  nentries;                      /* number of entries in fs directory */
                    121:        int  centry;                        /* current entry # */
                    122:        struct dirent **found;              /* legal files */
1.1.1.11  root      123:        char path[MAX_GEMDOS_PATH];                /* sfirst path */
1.1.1.2   root      124: } INTERNAL_DTA;
                    125: 
1.1.1.11  root      126: static FILE_HANDLE  FileHandles[MAX_FILE_HANDLES];
                    127: static INTERNAL_DTA InternalDTAs[MAX_DTAS_FILES];
                    128: static int DTAIndex;        /* Circular index into above */
                    129: static DTA *pDTA;           /* Our GEMDOS hard drive Disk Transfer Address structure */
                    130: static Uint16 CurrentDrive; /* Current drive (0=A,1=B,2=C etc...) */
                    131: static Uint32 act_pd;       /* Used to get a pointer to the current basepage */
1.1.1.13  root      132: static Uint16 nAttrSFirst;  /* File attribute for SFirst/Snext */
1.1.1.6   root      133: 
1.1       root      134: 
1.1.1.15  root      135: #if defined(WIN32) && !defined(mkdir)
1.1.1.12  root      136: #define mkdir(name,mode) mkdir(name)
1.1.1.11  root      137: #endif  /* WIN32 */
                    138: 
1.1.1.12  root      139: #ifndef S_IRGRP
                    140: #define S_IRGRP 0
                    141: #define S_IROTH 0
                    142: #endif
                    143: 
1.1.1.11  root      144: 
1.1.1.3   root      145: 
1.1.1.2   root      146: /*-------------------------------------------------------*/
1.1.1.12  root      147: /**
1.1.1.17! root      148:  * Routine to convert time and date to GEMDOS format.
1.1.1.12  root      149:  * Originally from the STonX emulator. (cheers!)
                    150:  */
1.1.1.17! root      151: static bool GemDOS_DateTime2Tos(time_t t, DATETIME *DateTime)
1.1.1.2   root      152: {
                    153:        struct tm *x;
1.1.1.12  root      154: 
                    155:        x = localtime(&t);
1.1.1.15  root      156: 
1.1.1.12  root      157:        if (x == NULL)
1.1.1.17! root      158:                return false;
1.1.1.12  root      159: 
1.1.1.17! root      160:        /* Bits: 0-4 = secs/2, 5-10 = mins, 11-15 = hours (24-hour format) */
        !           161:        DateTime->timeword = (x->tm_sec>>1)|(x->tm_min<<5)|(x->tm_hour<<11);
        !           162:        
        !           163:        /* Bits: 0-4 = day (1-31), 5-8 = month (1-12), 9-15 = years (since 1980) */
        !           164:        DateTime->dateword = x->tm_mday | ((x->tm_mon+1)<<5)
        !           165:                | (((x->tm_year-80 > 0) ? x->tm_year-80 : 0) << 9);
        !           166:        return true;
1.1.1.2   root      167: }
1.1       root      168: 
1.1.1.17! root      169: /*-----------------------------------------------------------------------*/
        !           170: /**
        !           171:  * Populate a DATETIME structure with file info.  Handle needs to be
        !           172:  * validated before calling.  Return true on success.
        !           173:  */
        !           174: static bool GemDOS_GetFileInformation(int Handle, DATETIME *DateTime)
1.1.1.2   root      175: {
1.1.1.17! root      176:        struct stat filestat;
1.1.1.12  root      177: 
1.1.1.17! root      178:        if (stat(FileHandles[Handle].szActualName, &filestat) != 0)
        !           179:                return false;
1.1.1.12  root      180: 
1.1.1.17! root      181:        return GemDOS_DateTime2Tos(filestat.st_mtime, DateTime);
1.1.1.2   root      182: }
1.1       root      183: 
1.1.1.2   root      184: /*-----------------------------------------------------------------------*/
1.1.1.12  root      185: /**
1.1.1.17! root      186:  * Set given file date/time from given DATETIME.  Handle needs to be
        !           187:  * validated before calling.  Return true on success.
1.1.1.12  root      188:  */
1.1.1.17! root      189: static bool GemDOS_SetFileInformation(int Handle, DATETIME *DateTime)
1.1.1.2   root      190: {
1.1.1.17! root      191:        const char *filename;
        !           192:        struct utimbuf timebuf;
1.1.1.9   root      193:        struct stat filestat;
1.1.1.17! root      194:        struct tm timespec;
1.1.1.9   root      195: 
1.1.1.17! root      196:        /* make sure Hatari itself doesn't need to write/modify
        !           197:         * the file after it's modification time is changed.
        !           198:         */
        !           199:        fflush(FileHandles[Handle].FileHandle);
        !           200:        filename = FileHandles[Handle].szActualName;
        !           201:        
        !           202:        /* Bits: 0-4 = secs/2, 5-10 = mins, 11-15 = hours (24-hour format) */
        !           203:        timespec.tm_sec  = (DateTime->timeword & 0x1F) << 1;
        !           204:        timespec.tm_min  = (DateTime->timeword & 0x7E0) >> 5;
        !           205:        timespec.tm_hour = (DateTime->timeword & 0xF800) >> 11;
        !           206:        /* Bits: 0-4 = day (1-31), 5-8 = month (1-12), 9-15 = years (since 1980) */
        !           207:        timespec.tm_mday = (DateTime->dateword & 0x1F);
        !           208:        timespec.tm_mon  = ((DateTime->dateword & 0x1E0) >> 5) - 1;
        !           209:        timespec.tm_year = ((DateTime->dateword & 0xFE00) >> 9) + 80;
        !           210: 
        !           211:        /* set new modification time */
        !           212:        timebuf.modtime = mktime(&timespec);
        !           213: 
        !           214:        /* but keep previous access time */
        !           215:        if (stat(filename, &filestat) != 0)
1.1.1.15  root      216:                return false;
1.1.1.17! root      217:        timebuf.actime = filestat.st_atime;
1.1.1.12  root      218: 
1.1.1.17! root      219:        if (utime(filename, &timebuf) != 0)
1.1.1.15  root      220:                return false;
1.1.1.17! root      221:        // fprintf(stderr, "set date '%s' for %s\n", asctime(&timespec), name);
        !           222:        return true;
        !           223: }
1.1.1.9   root      224: 
                    225: 
1.1.1.17! root      226: /**
        !           227:  * Convert potentially too long host filenames to 8.3 TOS filenames
        !           228:  * by truncating extension and part before it, replacing invalid
        !           229:  * GEMDOS file name characters with INVALID_CHAR + upcasing the result.
        !           230:  * 
        !           231:  * Matching them from the host file system should first try exact
        !           232:  * case-insensitive match, and then with a pattern that takes into
        !           233:  * account the conversion done in here.
        !           234:  */
        !           235: static void Convert2TOSName(char *source, char *dst)
        !           236: {
        !           237:        char *dot, *tmp, *src;
        !           238:        int len;
        !           239: 
        !           240:        src = strdup(source); /* dup so that it can be modified */
        !           241:        len = strlen(src);
        !           242: 
        !           243:        /* does filename have an extension? */
        !           244:        dot = strrchr(src, '.');
        !           245:        if (dot)
        !           246:        {
        !           247:                /* limit extension to 3 chars */
        !           248:                if (src + len - dot > 3)
        !           249:                        dot[4] = '\0';
        !           250: 
        !           251:                /* if there are extra dots, convert them */
        !           252:                for (tmp = src; tmp < dot; tmp++)
        !           253:                        if (*tmp == '.')
        !           254:                                *tmp = INVALID_CHAR;
        !           255:        }
        !           256: 
        !           257:        /* does name now fit to 8 (+3) chars? */
        !           258:        if (len <= 8 || (dot && len <= 12))
        !           259:                strcpy(dst, src);
        !           260:        else
        !           261:        {
        !           262:                /* name (still) too long, cut part before extension */
        !           263:                strncpy(dst, src, 8);
        !           264:                if (dot)
        !           265:                        strcpy(dst+8, dot);
        !           266:                else
        !           267:                        dst[8] = '\0';
        !           268:        }
        !           269:        free(src);
1.1.1.2   root      270: 
1.1.1.17! root      271:        /* replace other invalid chars than '.' in filename */
        !           272:        for (tmp = dst; *tmp; tmp++)
        !           273:        {
        !           274:                if (*tmp < 33 || *tmp > 126)
        !           275:                        *tmp = INVALID_CHAR;
        !           276:                else
        !           277:                {
        !           278:                        switch (*tmp)
        !           279:                        {
        !           280:                                case '*':
        !           281:                                case '/':
        !           282:                                case ':':
        !           283:                                case '?':
        !           284:                                case '\\':
        !           285:                                case '{':
        !           286:                                case '}':
        !           287:                                        *tmp = INVALID_CHAR;
        !           288:                        }
        !           289:                }
        !           290:        }
        !           291:        Str_ToUpper(dst);
        !           292:        LOG_TRACE(TRACE_OS_GEMDOS, "host: %s -> GEMDOS: %s\n", source, dst);
1.1.1.9   root      293: }
1.1.1.2   root      294: 
                    295: 
1.1.1.9   root      296: /*-----------------------------------------------------------------------*/
1.1.1.12  root      297: /**
1.1.1.15  root      298:  * Convert from FindFirstFile/FindNextFile attribute to GemDOS format
1.1.1.12  root      299:  */
1.1.1.17! root      300: static Uint8 GemDOS_ConvertAttribute(mode_t mode)
1.1.1.9   root      301: {
1.1.1.17! root      302:        Uint8 Attrib = 0;
1.1.1.9   root      303: 
                    304:        /* Directory attribute */
                    305:        if (S_ISDIR(mode))
                    306:                Attrib |= GEMDOS_FILE_ATTRIB_SUBDIRECTORY;
1.1.1.2   root      307: 
1.1.1.9   root      308:        /* Read-only attribute */
                    309:        if (!(mode & S_IWUSR))
                    310:                Attrib |= GEMDOS_FILE_ATTRIB_READONLY;
1.1.1.15  root      311: 
1.1.1.17! root      312:        /* TODO, Other attributes:
        !           313:         * - GEMDOS_FILE_ATTRIB_HIDDEN (file not visible on desktop/fsel)
        !           314:         * - GEMDOS_FILE_ATTRIB_ARCHIVE (file written after being backed up)
        !           315:         * ?
        !           316:         */
1.1.1.9   root      317:        return Attrib;
1.1.1.2   root      318: }
1.1.1.3   root      319: 
                    320: 
1.1.1.2   root      321: /*-----------------------------------------------------------------------*/
1.1.1.12  root      322: /**
1.1.1.13  root      323:  * Populate the DTA buffer with file info.
                    324:  * @return   0 if entry is ok, 1 if entry should be skipped, < 0 for errors.
1.1.1.12  root      325:  */
1.1.1.13  root      326: static int PopulateDTA(char *path, struct dirent *file)
1.1.1.2   root      327: {
1.1.1.17! root      328:        /* TODO: host file path can be longer than MAX_GEMDOS_PATH */
1.1.1.11  root      329:        char tempstr[MAX_GEMDOS_PATH];
1.1.1.9   root      330:        struct stat filestat;
1.1.1.17! root      331:        DATETIME DateTime;
        !           332:        int nFileAttr, nAttrMask;
1.1.1.9   root      333: 
1.1.1.12  root      334:        snprintf(tempstr, sizeof(tempstr), "%s%c%s", path, PATHSEP, file->d_name);
1.1.1.17! root      335: 
        !           336:        if (stat(tempstr, &filestat) != 0)
1.1.1.12  root      337:        {
                    338:                perror(tempstr);
1.1.1.13  root      339:                return -1;   /* return on error */
1.1.1.12  root      340:        }
1.1.1.9   root      341: 
                    342:        if (!pDTA)
1.1.1.13  root      343:                return -2;   /* no DTA pointer set */
                    344: 
1.1.1.17! root      345:        /* Check file attributes (check is done according to the Profibuch) */
1.1.1.13  root      346:        nFileAttr = GemDOS_ConvertAttribute(filestat.st_mode);
1.1.1.17! root      347:        nAttrMask = nAttrSFirst|GEMDOS_FILE_ATTRIB_WRITECLOSE|GEMDOS_FILE_ATTRIB_READONLY;
        !           348:        if (nFileAttr != 0 && !(nAttrMask & nFileAttr))
1.1.1.13  root      349:                return 1;
                    350: 
1.1.1.17! root      351:        if (!GemDOS_DateTime2Tos(filestat.st_mtime, &DateTime))
        !           352:                return -3;
        !           353: 
        !           354:        /* convert to atari-style uppercase */
        !           355:        Convert2TOSName(file->d_name, pDTA->dta_name);
        !           356: 
1.1.1.9   root      357:        do_put_mem_long(pDTA->dta_size, filestat.st_size);
1.1.1.17! root      358:        do_put_mem_word(pDTA->dta_time, DateTime.timeword);
        !           359:        do_put_mem_word(pDTA->dta_date, DateTime.dateword);
1.1.1.13  root      360:        pDTA->dta_attrib = nFileAttr;
1.1.1.2   root      361: 
1.1.1.13  root      362:        return 0;
1.1.1.2   root      363: }
                    364: 
1.1.1.3   root      365: 
1.1.1.2   root      366: /*-----------------------------------------------------------------------*/
1.1.1.12  root      367: /**
                    368:  * Clear a used DTA structure.
                    369:  */
1.1.1.7   root      370: static void ClearInternalDTA(void)
                    371: {
1.1.1.9   root      372:        int i;
1.1.1.2   root      373: 
1.1.1.9   root      374:        /* clear the old DTA structure */
                    375:        if (InternalDTAs[DTAIndex].found != NULL)
                    376:        {
                    377:                for (i=0; i < InternalDTAs[DTAIndex].nentries; i++)
                    378:                        free(InternalDTAs[DTAIndex].found[i]);
                    379:                free(InternalDTAs[DTAIndex].found);
                    380:                InternalDTAs[DTAIndex].found = NULL;
                    381:        }
                    382:        InternalDTAs[DTAIndex].nentries = 0;
1.1.1.15  root      383:        InternalDTAs[DTAIndex].bUsed = false;
1.1.1.2   root      384: }
                    385: 
1.1.1.3   root      386: 
1.1.1.2   root      387: /*-----------------------------------------------------------------------*/
1.1.1.12  root      388: /**
1.1.1.17! root      389:  * Match a TOS file name to a dir mask.
1.1.1.12  root      390:  */
1.1.1.17! root      391: static bool fsfirst_match(const char *pat, const char *name)
1.1.1.2   root      392: {
1.1.1.17! root      393:        const char *p=pat, *n=name;
1.1.1.9   root      394: 
                    395:        if (name[0] == '.')
1.1.1.17! root      396:                return false;           /* skip .* files */
1.1.1.9   root      397:        if (strcmp(pat,"*.*")==0)
1.1.1.17! root      398:                return true;            /* match everything */
1.1.1.9   root      399:        if (strcasecmp(pat,name)==0)
1.1.1.17! root      400:                return true;            /* exact case insensitive match */
1.1.1.9   root      401: 
1.1.1.17! root      402:        while (*n)
1.1.1.2   root      403:        {
1.1.1.9   root      404:                if (*p=='*')
                    405:                {
                    406:                        while (*n && *n != '.')
                    407:                                n++;
                    408:                        p++;
                    409:                }
                    410:                else
                    411:                {
                    412:                        if (*p=='?' && *n)
                    413:                        {
                    414:                                n++;
                    415:                                p++;
                    416:                        }
                    417:                        else
                    418:                        {
                    419:                                if (toupper(*p++) != toupper(*n++))
1.1.1.15  root      420:                                        return false;
1.1.1.9   root      421:                        }
                    422:                }
1.1.1.2   root      423:        }
1.1.1.9   root      424: 
1.1.1.17! root      425:        /* The name matches the pattern if it ends here, too */
        !           426:        return (*p == 0 || (*p == '*' && *(p+1) == 0));
1.1.1.2   root      427: }
                    428: 
1.1.1.9   root      429: 
1.1.1.2   root      430: /*-----------------------------------------------------------------------*/
1.1.1.12  root      431: /**
                    432:  * Parse directory from sfirst mask
                    433:  * - e.g.: input:  "hdemudir/auto/mask*.*" outputs: "hdemudir/auto"
                    434:  */
1.1.1.17! root      435: static void fsfirst_dirname(const char *string, char *newstr)
1.1.1.7   root      436: {
1.1.1.9   root      437:        int i=0;
1.1.1.6   root      438: 
1.1.1.15  root      439:        strcpy(newstr, string);
1.1.1.11  root      440: 
1.1.1.15  root      441:        /* convert to front slashes and go to end of string. */
                    442:        while (newstr[i] != '\0')
1.1.1.9   root      443:        {
1.1.1.15  root      444:                if (newstr[i] == '\\')
                    445:                        newstr[i] = PATHSEP;
1.1.1.9   root      446:                i++;
                    447:        }
1.1.1.15  root      448:        /* find last slash and terminate string */
                    449:        while (i && newstr[i] != PATHSEP)
                    450:                i--;
                    451:        newstr[i] = '\0';
1.1       root      452: }
                    453: 
1.1.1.11  root      454: 
1.1.1.2   root      455: /*-----------------------------------------------------------------------*/
1.1.1.12  root      456: /**
1.1.1.17! root      457:  * Return directory mask part from the given string
1.1.1.12  root      458:  */
1.1.1.17! root      459: static const char* fsfirst_dirmask(const char *string)
1.1.1.7   root      460: {
1.1.1.17! root      461:        const char *lastsep;
1.1.1.9   root      462: 
1.1.1.17! root      463:        lastsep = strrchr(string, PATHSEP);
        !           464:        if (lastsep)
        !           465:                return lastsep + 1;
        !           466:        else
        !           467:                return string;
1.1.1.2   root      468: }
1.1       root      469: 
1.1.1.7   root      470: 
1.1.1.2   root      471: /*-----------------------------------------------------------------------*/
1.1.1.12  root      472: /**
                    473:  * Initialize GemDOS/PC file system
                    474:  */
1.1       root      475: void GemDOS_Init(void)
                    476: {
1.1.1.9   root      477:        int i;
1.1.1.15  root      478:        bInitGemDOS = false;
1.1.1.2   root      479: 
1.1.1.9   root      480:        /* Clear handles structure */
1.1.1.17! root      481:        memset(FileHandles, 0, sizeof(FileHandles));
1.1.1.9   root      482:        /* Clear DTAs */
                    483:        for(i=0; i<MAX_DTAS_FILES; i++)
                    484:        {
1.1.1.15  root      485:                InternalDTAs[i].bUsed = false;
1.1.1.9   root      486:                InternalDTAs[i].nentries = 0;
                    487:                InternalDTAs[i].found = NULL;
                    488:        }
                    489:        DTAIndex = 0;
1.1       root      490: }
                    491: 
1.1.1.9   root      492: 
1.1.1.2   root      493: /*-----------------------------------------------------------------------*/
1.1.1.12  root      494: /**
                    495:  * Reset GemDOS file system
                    496:  */
1.1.1.7   root      497: void GemDOS_Reset(void)
1.1       root      498: {
1.1.1.9   root      499:        int i;
                    500: 
                    501:        /* Init file handles table */
                    502:        for (i=0; i<MAX_FILE_HANDLES; i++)
                    503:        {
                    504:                /* Was file open? If so close it */
                    505:                if (FileHandles[i].bUsed)
                    506:                        fclose(FileHandles[i].FileHandle);
1.1       root      507: 
1.1.1.9   root      508:                FileHandles[i].FileHandle = NULL;
1.1.1.15  root      509:                FileHandles[i].bUsed = false;
1.1.1.9   root      510:        }
                    511: 
                    512:        for (DTAIndex = 0; DTAIndex < MAX_DTAS_FILES; DTAIndex++)
                    513:        {
                    514:                ClearInternalDTA();
                    515:        }
                    516:        DTAIndex = 0;
                    517: 
                    518:        /* Reset */
1.1.1.15  root      519:        bInitGemDOS = false;
1.1.1.9   root      520:        CurrentDrive = nBootDrive;
                    521:        pDTA = NULL;
1.1       root      522: }
                    523: 
1.1.1.15  root      524: /*-----------------------------------------------------------------------*/
                    525: /**
                    526:  * Routine to check the Host OS HDD path for a Drive letter sub folder
                    527:  */
                    528: static bool GEMDOS_DoesHostDriveFolderExist(char* lpstrPath, int iDrive)
                    529: {
                    530:        bool bExist = false;
                    531: 
                    532:        if (access(lpstrPath, F_OK) != 0 )
                    533:        {
                    534:                /* Try lower case drive letter instead */
                    535:                int     iIndex = strlen(lpstrPath)-1;
                    536:                lpstrPath[iIndex] = tolower(lpstrPath[iIndex]);
                    537:        }
                    538: 
                    539:        /* Check the file/folder is accessible (security basis) */
                    540:        if (access(lpstrPath, F_OK) == 0 )
                    541:        {
                    542:                 /* If its a HDD identifier (or other emulated device) */
                    543:                if (iDrive > 1)
                    544:                {
                    545:                        struct stat status;
                    546:                        stat( lpstrPath, &status );
                    547:                        if ( status.st_mode & S_IFDIR )
                    548:                                bExist = true;
                    549:                }
                    550:        }
                    551: 
                    552:        return bExist;
                    553: }
                    554: 
                    555: /*-----------------------------------------------------------------------*/
                    556: /**
                    557:  * Routine to check if any emulated drive is present
                    558:  */
                    559: #if 0
                    560: static bool GEMDOS_IsHDDPresent(int iDrive)
                    561: {
                    562:        bool bPresent = false;
                    563: 
                    564:        if ((iDrive <= nNumDrives) && (iDrive > 1))
                    565:                if (emudrives[iDrive-2])
                    566:                        bPresent = true;
                    567: 
                    568:        return bPresent;
                    569: }
                    570: #endif
                    571: 
                    572: 
                    573: /**
1.1.1.16  root      574:  * Determine upper limit of partitions that should be emulated.
                    575:  *
                    576:  * @return true if multiple GEMDOS partitions should be emulated, false otherwise
1.1.1.15  root      577:  */
1.1.1.16  root      578: static bool GemDOS_DetermineMaxPartitions(int *pnMaxDrives)
1.1.1.15  root      579: {
                    580:        struct dirent **files;
1.1.1.16  root      581:        int count, i;
1.1.1.17! root      582:        char letter;
1.1.1.16  root      583:        bool bMultiPartitions;
                    584: 
                    585:        *pnMaxDrives = 0;
1.1.1.15  root      586: 
                    587:        /* Scan through the main directory to see whether there are just single
                    588:         * letter sub-folders there (then use multi-partition mode) or if
                    589:         * arbitrary sub-folders are there (then use single-partition mode */
                    590:        count = scandir(ConfigureParams.HardDisk.szHardDiskDirectories[0], &files, 0, alphasort);
                    591:        if (count < 0)
                    592:        {
                    593:                perror("GemDOS_DetermineMaxPartitions");
1.1.1.16  root      594:                return false;
1.1.1.15  root      595:        }
                    596:        else if (count <= 2)
                    597:        {
                    598:                /* Empty directory Only "." and ".."), assume single partition mode */
1.1.1.16  root      599:                *pnMaxDrives = 1;
                    600:                bMultiPartitions = false;
1.1.1.15  root      601:        }
                    602:        else
                    603:        {
1.1.1.16  root      604:                bMultiPartitions = true;
1.1.1.15  root      605:                /* Check all files in the directory */
                    606:                for (i = 0; i < count; i++)
                    607:                {
1.1.1.17! root      608:                        letter = toupper(files[i]->d_name[0]);
        !           609:                        if (!letter || letter == '.')
1.1.1.15  root      610:                        {
1.1.1.17! root      611:                                /* Ignore hidden files like "." and ".." */
1.1.1.15  root      612:                                continue;
                    613:                        }
1.1.1.17! root      614:                        
        !           615:                        if (letter < 'C' || letter > 'Z' || files[i]->d_name[1])
1.1.1.15  root      616:                        {
1.1.1.17! root      617:                                /* folder with name other than C-Z...
        !           618:                                 * (until Z under MultiTOS, to P otherwise)
1.1.1.15  root      619:                                 * ... so use single partition mode! */
1.1.1.16  root      620:                                *pnMaxDrives = 1;
                    621:                                bMultiPartitions = false;
1.1.1.15  root      622:                                break;
                    623:                        }
1.1.1.17! root      624:                        *pnMaxDrives = letter - 'C' + 1;
1.1.1.15  root      625:                }
                    626:        }
                    627: 
1.1.1.16  root      628:        if (*pnMaxDrives > MAX_HARDDRIVES)
                    629:                *pnMaxDrives = MAX_HARDDRIVES;
1.1.1.15  root      630: 
                    631:        /* Free file list */
                    632:        for (i = 0; i < count; i++)
                    633:                free(files[i]);
                    634:        free(files);
                    635: 
1.1.1.16  root      636:        return bMultiPartitions;
1.1.1.15  root      637: }
1.1.1.3   root      638: 
                    639: /*-----------------------------------------------------------------------*/
1.1.1.12  root      640: /**
                    641:  * Initialize a GEMDOS drive.
1.1.1.15  root      642:  * Supports up to MAX_HARDDRIVES HDD units.
1.1.1.12  root      643:  */
1.1.1.7   root      644: void GemDOS_InitDrives(void)
1.1.1.3   root      645: {
1.1.1.9   root      646:        int i;
1.1.1.15  root      647:        int nMaxDrives;
1.1.1.17! root      648:        int DriveNumber;
1.1.1.16  root      649:        bool bMultiPartitions;
1.1.1.9   root      650: 
                    651:        /* intialize data for harddrive emulation: */
                    652:        if (!GEMDOS_EMU_ON)
                    653:        {
1.1.1.15  root      654:                emudrives = malloc(MAX_HARDDRIVES * sizeof(EMULATEDDRIVE *));
                    655:                if (!emudrives)
                    656:                {
                    657:                        perror("GemDOS_InitDrives");
                    658:                        return;
                    659:                }
                    660:                memset(emudrives, 0, MAX_HARDDRIVES * sizeof(EMULATEDDRIVE *));
1.1.1.9   root      661:        }
1.1.1.3   root      662: 
1.1.1.16  root      663:        bMultiPartitions = GemDOS_DetermineMaxPartitions(&nMaxDrives);
1.1.1.15  root      664: 
                    665:        /* Now initialize all available drives */
                    666:        for(i = 0; i < nMaxDrives; i++)
1.1.1.9   root      667:        {
1.1.1.15  root      668:                // Create the letter equivilent string identifier for this drive
                    669:                char sDriveLetter[] = { PATHSEP, (char)('C' + i), '\0' };
1.1.1.6   root      670: 
1.1.1.16  root      671:                /* If single partition mode, skip to the right entry */
                    672:                if (!bMultiPartitions)
                    673:                        i += nPartitions;
                    674: 
                    675:                /* Allocate emudrives entry for this drive */
1.1.1.15  root      676:                emudrives[i] = malloc(sizeof(EMULATEDDRIVE));
                    677:                if (!emudrives[i])
                    678:                {
                    679:                        perror("GemDOS_InitDrives");
                    680:                        continue;
                    681:                }
1.1.1.9   root      682: 
1.1.1.15  root      683:                /* set emulation directory string */
                    684:                strcpy(emudrives[i]->hd_emulation_dir, ConfigureParams.HardDisk.szHardDiskDirectories[0]);
1.1.1.9   root      685: 
1.1.1.15  root      686:                /* remove trailing slash, if any in the directory name */
                    687:                File_CleanFileName(emudrives[i]->hd_emulation_dir);
1.1.1.9   root      688: 
1.1.1.15  root      689:                /* Add Requisit Folder ID */
1.1.1.16  root      690:                if (bMultiPartitions)
1.1.1.15  root      691:                        strcat(emudrives[i]->hd_emulation_dir, sDriveLetter);
                    692: 
1.1.1.17! root      693:                /* drive number (C: = 2, D: = 3, etc.) */
        !           694:                DriveNumber = 2 + i;
        !           695: 
1.1.1.15  root      696:                // Check host file system to see if the drive folder for THIS
                    697:                // drive letter/number exists...
1.1.1.17! root      698:                if (GEMDOS_DoesHostDriveFolderExist(emudrives[i]->hd_emulation_dir, DriveNumber))
1.1.1.15  root      699:                {
                    700:                        /* initialize current directory string, too (initially the same as hd_emulation_dir) */
                    701:                        strcpy(emudrives[i]->fs_currpath, emudrives[i]->hd_emulation_dir);
                    702:                        File_AddSlashToEndFileName(emudrives[i]->fs_currpath);    /* Needs trailing slash! */
                    703:                         /* If the GemDos Drive letter is free then */
                    704:                        if (i >= nPartitions)
                    705:                        {
1.1.1.17! root      706:                                Log_Printf(LOG_INFO, "GEMDOS HDD emulation, %c: <-> %s.\n",
        !           707:                                           'A'+DriveNumber, emudrives[i]->hd_emulation_dir);
        !           708:                                emudrives[i]->drive_number = DriveNumber;
1.1.1.15  root      709:                                nNumDrives = i + 3;
                    710:                        }
1.1.1.17! root      711:                        else    /* This letter has already been allocated to the one supported physical disk image */
1.1.1.15  root      712:                        {
1.1.1.17! root      713:                                Log_Printf(LOG_WARN, "Drive Letter %c is already mapped to HDD image (cannot map GEMDOS drive to %s).\n",
        !           714:                                           'A'+DriveNumber, emudrives[i]->hd_emulation_dir);
1.1.1.15  root      715:                                free(emudrives[i]);
                    716:                                emudrives[i] = NULL;
                    717:                        }
                    718:                }
                    719:                else
                    720:                {
                    721:                        free(emudrives[i]);     // Deallocate Memory (save space)
                    722:                        emudrives[i] = NULL;
                    723:                }
1.1.1.9   root      724:        }
1.1.1.3   root      725: }
                    726: 
1.1.1.6   root      727: 
1.1.1.3   root      728: /*-----------------------------------------------------------------------*/
1.1.1.12  root      729: /**
                    730:  * Un-init the GEMDOS drive
                    731:  */
1.1.1.7   root      732: void GemDOS_UnInitDrives(void)
1.1.1.3   root      733: {
1.1.1.9   root      734:        int i;
1.1.1.3   root      735: 
1.1.1.9   root      736:        GemDOS_Reset();        /* Close all open files on emulated drive*/
1.1.1.3   root      737: 
1.1.1.9   root      738:        if (GEMDOS_EMU_ON)
                    739:        {
                    740:                for(i=0; i<MAX_HARDDRIVES; i++)
                    741:                {
1.1.1.15  root      742:                        if (emudrives[i])
                    743:                        {
                    744:                                free(emudrives[i]);    /* Release memory */
                    745:                                emudrives[i] = NULL;
                    746:                                nNumDrives -= 1;
                    747:                        }
1.1.1.9   root      748:                }
                    749: 
                    750:                free(emudrives);
                    751:                emudrives = NULL;
                    752:        }
1.1.1.3   root      753: }
                    754: 
                    755: 
1.1.1.2   root      756: /*-----------------------------------------------------------------------*/
1.1.1.12  root      757: /**
                    758:  * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
                    759:  */
1.1.1.13  root      760: void GemDOS_MemorySnapShot_Capture(bool bSave)
1.1       root      761: {
1.1.1.9   root      762:        unsigned int Addr;
                    763:        int i;
1.1.1.13  root      764:        bool bEmudrivesAvailable;
                    765: 
                    766:        /* Save/Restore the emudrives structure */
                    767:        bEmudrivesAvailable = (emudrives != NULL);
                    768:        MemorySnapShot_Store(&bEmudrivesAvailable, sizeof(bEmudrivesAvailable));
                    769:        if (bEmudrivesAvailable)
                    770:        {
                    771:                if (!bSave && !emudrives)
                    772:                {
                    773:                        /* We're loading a memory snapshot, but the emudrives
                    774:                         * structure has not been malloc yet... let's do it now! */
                    775:                        GemDOS_InitDrives();
                    776:                }
                    777: 
                    778:                for(i=0; i<MAX_HARDDRIVES; i++)
                    779:                {
1.1.1.15  root      780:                        int bDummyDrive = false;
                    781:                        if (!emudrives[i])
                    782:                        {
                    783:                                /* Allocate a dummy drive */
                    784:                                emudrives[i] = malloc(sizeof(EMULATEDDRIVE));
                    785:                                if (!emudrives[i])
                    786:                                        perror("GemDOS_MemorySnapShot_Capture");
                    787:                                memset(emudrives[i], 0, sizeof(EMULATEDDRIVE));
                    788:                                bDummyDrive = true;
                    789:                        }
1.1.1.13  root      790:                        MemorySnapShot_Store(emudrives[i]->hd_emulation_dir,
                    791:                                             sizeof(emudrives[i]->hd_emulation_dir));
                    792:                        MemorySnapShot_Store(emudrives[i]->fs_currpath,
                    793:                                             sizeof(emudrives[i]->fs_currpath));
1.1.1.17! root      794:                        MemorySnapShot_Store(&emudrives[i]->drive_number,
        !           795:                                             sizeof(emudrives[i]->drive_number));
1.1.1.15  root      796:                        if (bDummyDrive)
                    797:                        {
                    798:                                free(emudrives[i]);
                    799:                                emudrives[i] = NULL;
                    800:                        }
1.1.1.13  root      801:                }
                    802:        }
1.1       root      803: 
1.1.1.9   root      804:        /* Save/Restore details */
                    805:        MemorySnapShot_Store(&DTAIndex,sizeof(DTAIndex));
                    806:        MemorySnapShot_Store(&bInitGemDOS,sizeof(bInitGemDOS));
1.1.1.13  root      807:        MemorySnapShot_Store(&act_pd, sizeof(act_pd));
1.1.1.9   root      808:        if (bSave)
                    809:        {
1.1.1.11  root      810:                Addr = ((Uint8 *)pDTA - STRam);
1.1.1.9   root      811:                MemorySnapShot_Store(&Addr,sizeof(Addr));
                    812:        }
                    813:        else
                    814:        {
                    815:                MemorySnapShot_Store(&Addr,sizeof(Addr));
                    816:                pDTA = (DTA *)(STRam + Addr);
                    817:        }
                    818:        MemorySnapShot_Store(&CurrentDrive,sizeof(CurrentDrive));
                    819:        /* Don't save file handles as files may have changed which makes
                    820:           it impossible to get a valid handle back */
                    821:        if (!bSave)
                    822:        {
                    823:                /* Clear file handles  */
                    824:                for(i=0; i<MAX_FILE_HANDLES; i++)
                    825:                {
                    826:                        FileHandles[i].FileHandle = NULL;
1.1.1.15  root      827:                        FileHandles[i].bUsed = false;
1.1.1.9   root      828:                }
                    829:        }
1.1       root      830: }
                    831: 
1.1.1.9   root      832: 
1.1.1.2   root      833: /*-----------------------------------------------------------------------*/
1.1.1.12  root      834: /**
                    835:  * Return free PC file handle table index, or -1 if error
                    836:  */
1.1.1.7   root      837: static int GemDOS_FindFreeFileHandle(void)
1.1       root      838: {
1.1.1.9   root      839:        int i;
1.1       root      840: 
1.1.1.9   root      841:        /* Scan our file list for free slot */
                    842:        for(i=0; i<MAX_FILE_HANDLES; i++)
                    843:        {
                    844:                if (!FileHandles[i].bUsed)
                    845:                        return i;
                    846:        }
1.1       root      847: 
1.1.1.9   root      848:        /* Cannot open any more files, return error */
                    849:        return -1;
1.1       root      850: }
                    851: 
1.1.1.2   root      852: /*-----------------------------------------------------------------------*/
1.1.1.12  root      853: /**
                    854:  * Check ST handle is within our table range, return TRUE if not
                    855:  */
1.1.1.13  root      856: static bool GemDOS_IsInvalidFileHandle(int Handle)
1.1       root      857: {
1.1.1.9   root      858:        /* Check handle was valid with our handle table */
1.1.1.17! root      859:        if (Handle >= 0 && Handle < MAX_FILE_HANDLES
        !           860:            && FileHandles[Handle].bUsed)
        !           861:        {
        !           862:                return false;
        !           863:        }
        !           864:        /* invalid handle */
        !           865:        return true;
1.1       root      866: }
                    867: 
1.1.1.2   root      868: /*-----------------------------------------------------------------------*/
1.1.1.12  root      869: /**
                    870:  * Find drive letter from a filename, eg C,D... and return as drive ID(C:2, D:3...)
                    871:  * returns the current drive number if none is specified.
                    872:  */
1.1.1.7   root      873: static int GemDOS_FindDriveNumber(char *pszFileName)
1.1       root      874: {
1.1.1.9   root      875:        /* Does have 'A:' or 'C:' etc.. at start of string? */
                    876:        if ((pszFileName[0] != '\0') && (pszFileName[1] == ':'))
                    877:        {
                    878:                if ((pszFileName[0] >= 'a') && (pszFileName[0] <= 'z'))
                    879:                        return (pszFileName[0]-'a');
                    880:                else if ((pszFileName[0] >= 'A') && (pszFileName[0] <= 'Z'))
                    881:                        return (pszFileName[0]-'A');
                    882:        }
1.1       root      883: 
1.1.1.9   root      884:        return CurrentDrive;
1.1       root      885: }
                    886: 
1.1.1.2   root      887: /*-----------------------------------------------------------------------*/
1.1.1.12  root      888: /**
                    889:  * Return drive ID(C:2, D:3 etc...) or -1 if not one of our emulation hard-drives
                    890:  */
1.1.1.7   root      891: static int GemDOS_IsFileNameAHardDrive(char *pszFileName)
1.1       root      892: {
1.1.1.17! root      893:        int DriveNumber;
1.1.1.11  root      894:        int n;
1.1.1.9   root      895: 
                    896:        /* Do we even have a hard-drive? */
                    897:        if (GEMDOS_EMU_ON)
                    898:        {
1.1.1.10  root      899:                /* Find drive letter (as number) */
1.1.1.17! root      900:                DriveNumber = GemDOS_FindDriveNumber(pszFileName);
1.1.1.15  root      901: 
                    902:                /* We've got support for multiple drives here... */
1.1.1.17! root      903:                if (DriveNumber > 1)    // If it is not a Floppy Drive
1.1.1.15  root      904:                {
                    905:                        for (n=0; n<MAX_HARDDRIVES; n++)
                    906:                        {
                    907:                                /* Check if drive letter matches */
1.1.1.17! root      908:                                if (emudrives[n] &&  DriveNumber == emudrives[n]->drive_number)
        !           909:                                        return DriveNumber;
1.1.1.15  root      910:                        }
                    911:                }
1.1.1.11  root      912:        }
1.1.1.15  root      913: 
1.1.1.10  root      914:        /* Not a high-level redirected drive, let TOS handle it */
1.1.1.9   root      915:        return -1;
1.1       root      916: }
                    917: 
1.1.1.7   root      918: 
                    919: /*-----------------------------------------------------------------------*/
1.1.1.12  root      920: /**
1.1.1.17! root      921:  * Check whether a file in given path matches given case-insensitive pattern.
        !           922:  * Return first matched name which caller needs to free, or NULL for no match.
        !           923:  */
        !           924: static char* match_host_dir_entry(const char *path, const char *name, bool pattern)
        !           925: {
        !           926:        struct dirent *entry;
        !           927:        char *match = NULL;
        !           928:        DIR *dir;
        !           929:        
        !           930:        dir = opendir(path);
        !           931:        if (!dir)
        !           932:                return NULL;
        !           933: 
        !           934:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS match '%s'%s in '%s'", name, pattern?" (pattern)":"", path);
        !           935: 
        !           936:        if (pattern)
        !           937:        {
        !           938:                while ((entry = readdir(dir)))
        !           939:                {
        !           940:                        if (fsfirst_match(name, entry->d_name))
        !           941:                        {
        !           942:                                match = strdup(entry->d_name);
        !           943:                                break;
        !           944:                        }
        !           945:                }
        !           946:        }
        !           947:        else
        !           948:        {
        !           949:                while ((entry = readdir(dir)))
        !           950:                {
        !           951:                        if (strcasecmp(name, entry->d_name) == 0)
        !           952:                        {
        !           953:                                match = strdup(entry->d_name);
        !           954:                                break;
        !           955:                        }
        !           956:                }
        !           957:        }
        !           958:        closedir(dir);
        !           959:        LOG_TRACE(TRACE_OS_GEMDOS, " -> '%s'\n", match);
        !           960:        return match;
        !           961: }
        !           962: 
        !           963: 
        !           964: /*-----------------------------------------------------------------------*/
        !           965: /**
        !           966:  * Check whether given TOS file/dir exists in given host path.
        !           967:  * If it does, add the matched host filename to the given path,
        !           968:  * otherwise add the given filename as is to it.  Guarantees
        !           969:  * that the resulting string doesn't exceed maxlen+1.
        !           970:  * 
        !           971:  * Return true if match found, false otherwise.
        !           972:  */
        !           973: static bool add_path_component(char *path, int maxlen, const char *origname, bool is_dir)
        !           974: {
        !           975:        char *tmp, *match, name[strlen(origname) + 3];
        !           976:        int dot, namelen, pathlen;
        !           977:        bool modified;
        !           978: 
        !           979:        strcpy(name, origname);
        !           980:        namelen = strlen(name);
        !           981:        pathlen = strlen(path);
        !           982: 
        !           983:        /* append separator */
        !           984:        if (pathlen >= maxlen)
        !           985:                return false;
        !           986:        path[pathlen++] = PATHSEP;
        !           987:        path[pathlen] = '\0';
        !           988:        
        !           989:        /* first try exact (case insensitive) match */
        !           990:        match = match_host_dir_entry(path, name, false);
        !           991:        if (match)
        !           992:        {
        !           993:                /* use strncat so that string is always nul terminated */
        !           994:                strncat(path+pathlen, match, maxlen-pathlen);
        !           995:                free(match);
        !           996:                return true;
        !           997:        }
        !           998: 
        !           999:        /* Here comes a work-around for a bug in the file selector
        !          1000:         * of TOS 1.02: When a folder name has exactly 8 characters,
        !          1001:         * it appends a '.' at the end of the name...
        !          1002:         */
        !          1003:        if (is_dir && namelen == 9 && name[8] == '.')
        !          1004:        {
        !          1005:                name[8] = '\0';
        !          1006:                match = match_host_dir_entry(path, name, false);
        !          1007:                if (match)
        !          1008:                {
        !          1009:                        strncat(path+pathlen, match, maxlen-pathlen);
        !          1010:                        free(match);
        !          1011:                        return true;
        !          1012:                }
        !          1013:        }
        !          1014: 
        !          1015:        /* Assume there were invalid characters or that the host file
        !          1016:         * was too long to fit into GEMDOS 8+3 filename limits.
        !          1017:         * Change name to a pattern that will match such host files
        !          1018:         * and try again.
        !          1019:         */
        !          1020: 
        !          1021:        /* catch potentially invalid characters */
        !          1022:        for (tmp = name; *tmp; tmp++)
        !          1023:        {
        !          1024:                if (*tmp == INVALID_CHAR)
        !          1025:                {
        !          1026:                        *tmp = '?';
        !          1027:                        modified = true;
        !          1028:                }
        !          1029:        }
        !          1030: 
        !          1031:        /* catch potentially too long extension */
        !          1032:        for (dot = 0; name[dot] && name[dot] != '.'; dot++);
        !          1033:        if (namelen - dot > 3)
        !          1034:        {
        !          1035:                /* "emulated.too" -> "emulated.too*" */
        !          1036:                name[namelen++] = '*';
        !          1037:                name[namelen] = '\0';
        !          1038:                modified = true;
        !          1039:        }
        !          1040:        /* catch potentially too long part before extension */
        !          1041:        if (namelen > 8 && name[8] == '.')
        !          1042:        {
        !          1043:                /* "emulated.too*" -> "emulated*.too*" */
        !          1044:                memmove(name+9, name+8, namelen-7);
        !          1045:                namelen++;
        !          1046:                name[8] = '*';
        !          1047:                modified = true;
        !          1048:        }
        !          1049:        else if (namelen == 8)
        !          1050:        {
        !          1051:                /* "emulated" -> "emulated*" */
        !          1052:                name[8] = '*';
        !          1053:                name[9] = '\0';
        !          1054:                namelen++;
        !          1055:                modified = true;
        !          1056:        }
        !          1057: 
        !          1058:        if (modified)
        !          1059:        {
        !          1060:                match = match_host_dir_entry(path, name, true);
        !          1061:                if (match)
        !          1062:                {
        !          1063:                        strncat(path+pathlen, match, maxlen-pathlen);
        !          1064:                        free(match);
        !          1065:                        return true;
        !          1066:                }
        !          1067:        }
        !          1068: 
        !          1069:        /* not found, copy file/dirname as is */
        !          1070:        strncat(path+pathlen, origname, maxlen-pathlen);
        !          1071:        return false;
        !          1072: }
        !          1073: 
        !          1074: 
        !          1075: /**
        !          1076:  * Join remaining path without matching. This helper is used after host
        !          1077:  * file name matching fails, to append the failing part of the TOS path
        !          1078:  * to the host path, so that it won't be a valid host path.
        !          1079:  *
        !          1080:  * Specifically, the path separators need to be converted, otherwise things
        !          1081:  * like Fcreate() could create files that have TOS directory names as part
        !          1082:  * of file names on Unix (as \ is valid filename char on Unix).  Fcreate()
        !          1083:  * needs to create them only when just the file name isn't found, but all
        !          1084:  * the directory components have.
1.1.1.12  root     1085:  */
1.1.1.17! root     1086: static void add_remaining_path(const char *src, char *dstpath, int dstlen)
1.1.1.7   root     1087: {
1.1.1.17! root     1088:        char *dst;
        !          1089:        int i;
        !          1090: 
        !          1091:        dstlen--;
        !          1092:        i = strlen(dstpath);
        !          1093:        for (dst = dstpath + i; *src && i < dstlen; dst++, src++, i++)
        !          1094:        {
        !          1095:                if (*src == '\\')
        !          1096:                        *dst = PATHSEP;
        !          1097:                else
        !          1098:                        *dst = *src;
        !          1099:        }
        !          1100:        *dst = '\0';
1.1.1.6   root     1101: }
                   1102: 
1.1.1.2   root     1103: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1104: /**
1.1.1.17! root     1105:  * Use hard-drive directory, current ST directory and filename
        !          1106:  * to create correct path to host file system.  If given filename
        !          1107:  * isn't found on host file system, just append GEMDOS filename
        !          1108:  * to the path as is.
        !          1109:  * 
        !          1110:  * TODO: currently there are many callers which give this dest buffer of
        !          1111:  * MAX_GEMDOS_PATH size i.e. don't take into account that host filenames
        !          1112:  * can be upto FILENAME_MAX long.  Plain GEMDOS paths themselves may be
        !          1113:  * MAX_GEMDOS_PATH long even before host dir is prepended to it!
        !          1114:  * Way forward: allocate the host path here as FILENAME_MAX so that
        !          1115:  * it's always long enough and let callers free it. Assert if alloc
        !          1116:  * fails so that callers' don't need to.
1.1.1.12  root     1117:  */
                   1118: void GemDOS_CreateHardDriveFileName(int Drive, const char *pszFileName,
                   1119:                                     char *pszDestName, int nDestNameLen)
1.1       root     1120: {
1.1.1.17! root     1121:        const char *s, *filename = pszFileName;
        !          1122:        int minlen;
1.1.1.11  root     1123: 
                   1124:        /* Is it a valid hard drive? */
                   1125:        if (Drive < 2)
                   1126:                return;
1.1.1.3   root     1127: 
1.1.1.17! root     1128:        /* Check for valid string */
        !          1129:        if (filename[0] == '\0')
        !          1130:                return;
1.1.1.9   root     1131: 
1.1.1.17! root     1132:        /* make sure that more convenient strncat() can be used
        !          1133:         * on the destination string (it always null terminates
        !          1134:         * unlike strncpy()).
        !          1135:         */
        !          1136:        *pszDestName = 0;
        !          1137:        /* strcat writes n+1 chars, se decrease len */
        !          1138:        nDestNameLen--;
        !          1139:        
        !          1140:        /* full filename with drive "C:\foo\bar" */
        !          1141:        if (filename[1] == ':')
        !          1142:        {
        !          1143:                strncat(pszDestName, emudrives[Drive-2]->hd_emulation_dir, nDestNameLen);
        !          1144:                filename += 2;
1.1.1.9   root     1145:        }
1.1.1.17! root     1146:        /* filename referenced from root: "\foo\bar" */
        !          1147:        else if (filename[0] == '\\')
1.1.1.9   root     1148:        {
1.1.1.17! root     1149:                strncat(pszDestName, emudrives[Drive-2]->hd_emulation_dir, nDestNameLen);
1.1.1.9   root     1150:        }
1.1.1.17! root     1151:        /* filename relative to current directory */
1.1.1.9   root     1152:        else
                   1153:        {
1.1.1.17! root     1154:                strncat(pszDestName, emudrives[Drive-2]->fs_currpath, nDestNameLen);
        !          1155:        }
        !          1156: 
        !          1157:        minlen = strlen(emudrives[Drive-2]->hd_emulation_dir);
        !          1158:        /* this doesn't take into account possible long host filenames
        !          1159:         * that will make dest name longer than pszFileName 8.3 paths,
        !          1160:         * or GEMDOS paths using "../" which make it smaller.  Both
        !          1161:         * should(?) be rare in paths, so this info to user should be
        !          1162:         * good enough.
        !          1163:         */
        !          1164:        if (nDestNameLen < minlen + (int)strlen(pszFileName) + 2)
        !          1165:        {
        !          1166:                Log_AlertDlg(LOG_ERROR, "Appending GEMDOS path '%s' to HDD emu host root dir doesn't fit to %d chars (current Hatari limit)!",
        !          1167:                             pszFileName, nDestNameLen);
        !          1168:                add_remaining_path(filename, pszDestName, nDestNameLen);
        !          1169:                return;
1.1.1.6   root     1170:        }
1.1.1.9   root     1171: 
1.1.1.17! root     1172:        /* "../" handling breaks if there are extra slashes */
        !          1173:        File_CleanFileName(pszDestName);
        !          1174:        
        !          1175:        /* go through path directory components, advacing 'filename'
        !          1176:         * pointer while parsing them.
        !          1177:         */
        !          1178:        for (;;)
1.1.1.9   root     1179:        {
1.1.1.17! root     1180:                /* skip extra path separators */
        !          1181:                while (*filename == '\\')
        !          1182:                        filename++;
        !          1183: 
        !          1184:                // fprintf(stderr, "filename: '%s', path: '%s'\n", filename, pszDestName);
        !          1185: 
        !          1186:                /* skip "." references to current directory */
        !          1187:                if (filename[0] == '.' &&
        !          1188:                    (filename[1] == '\\' || !filename[1]))
1.1.1.9   root     1189:                {
1.1.1.17! root     1190:                        filename++;
1.1.1.9   root     1191:                        continue;
                   1192:                }
1.1.1.17! root     1193: 
        !          1194:                /* ".." path component -> strip last dir from dest path */
        !          1195:                if (filename[0] == '.' &&
        !          1196:                    filename[1] == '.' &&
        !          1197:                    (filename[2] == '\\' || !filename[2]))
1.1.1.9   root     1198:                {
1.1.1.17! root     1199:                        char *sep = strrchr(pszDestName, PATHSEP);
        !          1200:                        if (sep)
1.1.1.9   root     1201:                        {
1.1.1.17! root     1202:                                if (sep - pszDestName < minlen)
        !          1203:                                        Log_Printf(LOG_WARN, "GEMDOS path '%s' tried to back out of GEMDOS drive!\n", pszFileName);
        !          1204:                                else
        !          1205:                                        *sep = '\0';
1.1.1.9   root     1206:                        }
1.1.1.17! root     1207:                        filename += 2;
        !          1208:                        continue;
        !          1209:                }
        !          1210: 
        !          1211:                /* handle directory component */
        !          1212:                if ((s = strchr(filename, '\\')))
        !          1213:                {
        !          1214:                        int dirlen = s - filename;
        !          1215:                        char dirname[dirlen+1];
        !          1216:                        /* copy dirname */
        !          1217:                        strncpy(dirname, filename, dirlen);
        !          1218:                        dirname[dirlen] = '\0';
        !          1219:                        /* and advance filename */
        !          1220:                        filename = s;
        !          1221: 
        !          1222:                        if (strchr(dirname, '?') || strchr(dirname, '*'))
        !          1223:                                Log_Printf(LOG_WARN, "GEMDOS dir name '%s' with wildcards in %s!\n", dirname, pszFileName);
        !          1224: 
        !          1225:                        /* convert and append dirname to host path */
        !          1226:                        if (!add_path_component(pszDestName, nDestNameLen, dirname, true))
1.1.1.9   root     1227:                        {
1.1.1.17! root     1228:                                Log_Printf(LOG_WARN, "No GEMDOS dir '%s'\n", pszDestName);
        !          1229:                                add_remaining_path(filename, pszDestName, nDestNameLen);
        !          1230:                                return;
1.1.1.9   root     1231:                        }
1.1.1.17! root     1232:                        continue;
1.1.1.9   root     1233:                }
1.1.1.17! root     1234: 
        !          1235:                /* path directory components done */
        !          1236:                break;
1.1.1.9   root     1237:        }
                   1238: 
1.1.1.17! root     1239:        if (*filename)
1.1.1.9   root     1240:        {
1.1.1.17! root     1241:                /* a wildcard instead of a complete file name? */
        !          1242:                if (strchr(filename,'?') || strchr(filename,'*'))
1.1.1.9   root     1243:                {
1.1.1.17! root     1244:                        int len = strlen(pszDestName);
        !          1245:                        if (len < nDestNameLen)
1.1.1.9   root     1246:                        {
1.1.1.17! root     1247:                                pszDestName[len++] = PATHSEP;
        !          1248:                                pszDestName[len] = '\0';
1.1.1.9   root     1249:                        }
1.1.1.17! root     1250:                        /* use strncat so that string is always nul terminated */
        !          1251:                        strncat(pszDestName+len, filename, nDestNameLen-len);
        !          1252:                }
        !          1253:                else if (!add_path_component(pszDestName, nDestNameLen, filename, false))
        !          1254:                {
        !          1255:                        /* It's often normal, that GEM uses this to test for
        !          1256:                         * existence of desktop.inf or newdesk.inf for example.
        !          1257:                         */
        !          1258:                        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS didn't find filename %s\n", pszDestName);
        !          1259:                        return;
1.1.1.9   root     1260:                }
                   1261:        }
1.1.1.17! root     1262:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS: %s -> host: %s\n", pszFileName, pszDestName);
1.1       root     1263: }
                   1264: 
1.1.1.6   root     1265: 
1.1.1.2   root     1266: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1267: /**
                   1268:  * GEMDOS Cauxin
                   1269:  * Call 0x3
                   1270:  */
1.1.1.7   root     1271: #if 0
1.1.1.13  root     1272: static bool GemDOS_Cauxin(Uint32 Params)
1.1       root     1273: {
1.1.1.17! root     1274:        Uint8 c;
1.1       root     1275: 
1.1.1.9   root     1276:        /* Wait here until a character is ready */
                   1277:        while(!RS232_GetStatus())
                   1278:                ;
1.1       root     1279: 
1.1.1.9   root     1280:        /* And read character */
1.1.1.11  root     1281:        RS232_ReadBytes(&c,1);
                   1282:        Regs[REG_D0] = c;
1.1       root     1283: 
1.1.1.15  root     1284:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Cauxin() = 0x%x\n", (int)c);
                   1285: 
                   1286:        return true;
1.1       root     1287: }
1.1.1.7   root     1288: #endif
1.1       root     1289: 
1.1.1.2   root     1290: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1291: /**
                   1292:  * GEMDOS Cauxout
                   1293:  * Call 0x4
                   1294:  */
1.1.1.7   root     1295: #if 0
1.1.1.13  root     1296: static bool GemDOS_Cauxout(Uint32 Params)
1.1       root     1297: {
1.1.1.17! root     1298:        Uint8 c;
1.1       root     1299: 
1.1.1.15  root     1300:        /* Get character from the stack */
1.1.1.17! root     1301:        c = STMemory_ReadWord(Params);
1.1.1.15  root     1302: 
                   1303:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Cauxout(0x%x)\n", (int)c);
                   1304: 
                   1305:        /* Send character to RS232 */
1.1.1.11  root     1306:        RS232_TransferBytesTo(&c, 1);
1.1       root     1307: 
1.1.1.15  root     1308:        return true;
1.1       root     1309: }
1.1.1.7   root     1310: #endif
1.1       root     1311: 
1.1.1.2   root     1312: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1313: /**
                   1314:  * GEMDOS Cprnout
                   1315:  * Call 0x5
                   1316:  */
1.1.1.13  root     1317: #if 0
                   1318: static bool GemDOS_Cprnout(Uint32 Params)
1.1       root     1319: {
1.1.1.17! root     1320:        Uint8 c;
1.1       root     1321: 
1.1.1.9   root     1322:        /* Send character to printer(or file) */
1.1.1.17! root     1323:        c = STMemory_ReadWord(Params);
1.1.1.15  root     1324:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Cprnout(0x%x)\n", (int)c);
1.1.1.11  root     1325:        Printer_TransferByteTo(c);
1.1.1.9   root     1326:        Regs[REG_D0] = -1;                /* Printer OK */
1.1       root     1327: 
1.1.1.15  root     1328:        return true;
1.1       root     1329: }
1.1.1.13  root     1330: #endif
1.1       root     1331: 
1.1.1.2   root     1332: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1333: /**
                   1334:  * GEMDOS Set drive (0=A,1=B,2=C etc...)
                   1335:  * Call 0xE
                   1336:  */
1.1.1.13  root     1337: static bool GemDOS_SetDrv(Uint32 Params)
1.1       root     1338: {
1.1.1.9   root     1339:        /* Read details from stack for our own use */
1.1.1.17! root     1340:        CurrentDrive = STMemory_ReadWord(Params);
1.1       root     1341: 
1.1.1.15  root     1342:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Dsetdrv(0x%x)\n", (int)CurrentDrive);
                   1343: 
1.1.1.9   root     1344:        /* Still re-direct to TOS */
1.1.1.15  root     1345:        return false;
1.1       root     1346: }
                   1347: 
1.1.1.2   root     1348: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1349: /**
                   1350:  * GEMDOS Cprnos
                   1351:  * Call 0x11
                   1352:  */
1.1.1.13  root     1353: #if 0
                   1354: static bool GemDOS_Cprnos(Uint32 Params)
1.1       root     1355: {
1.1.1.13  root     1356:        /* printer status depends if printing is enabled or not... */
1.1.1.9   root     1357:        if (ConfigureParams.Printer.bEnablePrinting)
                   1358:                Regs[REG_D0] = -1;              /* Printer OK */
                   1359:        else
                   1360:                Regs[REG_D0] = 0;               /* printer not ready if printing disabled */
1.1       root     1361: 
1.1.1.15  root     1362:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Cprnos() = 0x%x\n", Regs[REG_D0]);
                   1363: 
                   1364:        return true;
1.1       root     1365: }
1.1.1.13  root     1366: #endif
1.1       root     1367: 
1.1.1.2   root     1368: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1369: /**
                   1370:  * GEMDOS Cauxis
                   1371:  * Call 0x12
                   1372:  */
1.1.1.7   root     1373: #if 0
1.1.1.13  root     1374: static bool GemDOS_Cauxis(Uint32 Params)
1.1       root     1375: {
1.1.1.9   root     1376:        /* Read our RS232 state */
                   1377:        if (RS232_GetStatus())
                   1378:                Regs[REG_D0] = -1;              /* Chars waiting */
                   1379:        else
                   1380:                Regs[REG_D0] = 0;
1.1       root     1381: 
1.1.1.15  root     1382:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Cauxis() = 0x%x\n", Regs[REG_D0]);
                   1383: 
                   1384:        return true;
1.1       root     1385: }
1.1.1.7   root     1386: #endif
1.1       root     1387: 
1.1.1.2   root     1388: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1389: /**
                   1390:  * GEMDOS Cauxos
                   1391:  * Call 0x13
                   1392:  */
1.1.1.7   root     1393: #if 0
1.1.1.13  root     1394: static bool GemDOS_Cauxos(Uint32 Params)
1.1       root     1395: {
1.1.1.9   root     1396:        Regs[REG_D0] = -1;                /* Device ready */
1.1       root     1397: 
1.1.1.15  root     1398:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Cauxos() = 0x%x\n", Regs[REG_D0]);
                   1399: 
                   1400:        return true;
1.1       root     1401: }
1.1.1.7   root     1402: #endif
1.1       root     1403: 
1.1.1.2   root     1404: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1405: /**
                   1406:  * GEMDOS Set Disk Transfer Address (DTA)
                   1407:  * Call 0x1A
                   1408:  */
1.1.1.13  root     1409: static bool GemDOS_SetDTA(Uint32 Params)
1.1       root     1410: {
1.1.1.17! root     1411:        /*  Look up on stack to find where DTA is */
        !          1412:        Uint32 nDTA = STMemory_ReadLong(Params);
1.1.1.15  root     1413: 
                   1414:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fsetdta(0x%x)\n", nDTA);
                   1415: 
1.1.1.17! root     1416:        if (STMemory_ValidArea(nDTA, sizeof(DTA)))
        !          1417:        {
        !          1418:                /* Store as PC pointer */
        !          1419:                pDTA = (DTA *)STRAM_ADDR(nDTA);
        !          1420:        }
        !          1421:        else
        !          1422:        {
        !          1423:                pDTA = NULL;
        !          1424:                Log_Printf(LOG_WARN, "GEMDOS Fsetdta() failed due to invalid DTA address 0x%x\n", nDTA);
        !          1425:        }
1.1.1.15  root     1426:        return false;
1.1       root     1427: }
                   1428: 
1.1.1.2   root     1429: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1430: /**
                   1431:  * GEMDOS Dfree Free disk space.
1.1.1.15  root     1432:  * Call 0x36
1.1.1.12  root     1433:  */
1.1.1.13  root     1434: static bool GemDOS_DFree(Uint32 Params)
1.1.1.2   root     1435: {
1.1.1.9   root     1436:        int Drive;
1.1.1.10  root     1437:        Uint32 Address;
1.1.1.9   root     1438: 
1.1.1.17! root     1439:        Address = STMemory_ReadLong(Params);
        !          1440:        Drive = STMemory_ReadWord(Params+SIZE_LONG);
1.1.1.15  root     1441: 
                   1442:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Dfree(0x%x, %i)\n", Address, Drive);
                   1443: 
1.1.1.9   root     1444:        /* is it our drive? */
                   1445:        if ((Drive == 0 && CurrentDrive >= 2) || Drive >= 3)
                   1446:        {
                   1447:                /* FIXME: Report actual free drive space */
                   1448: 
                   1449:                STMemory_WriteLong(Address,  10*2048);           /* free clusters (mock 10 Mb) */
                   1450:                STMemory_WriteLong(Address+SIZE_LONG, 50*2048 ); /* total clusters (mock 50 Mb) */
1.1.1.2   root     1451: 
1.1.1.9   root     1452:                STMemory_WriteLong(Address+SIZE_LONG*2, 512 );   /* bytes per sector */
                   1453:                STMemory_WriteLong(Address+SIZE_LONG*3, 1 );     /* sectors per cluster */
1.1.1.15  root     1454:                return true;
1.1.1.9   root     1455:        }
1.1.1.17! root     1456:        /* redirect to TOS */
        !          1457:        return false;
1.1.1.2   root     1458: }
                   1459: 
                   1460: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1461: /**
                   1462:  * GEMDOS MkDir
                   1463:  * Call 0x39
                   1464:  */
1.1.1.13  root     1465: static bool GemDOS_MkDir(Uint32 Params)
1.1.1.6   root     1466: {
1.1.1.17! root     1467:        char *pDirName, *psDirPath;
1.1.1.9   root     1468:        int Drive;
                   1469: 
                   1470:        /* Find directory to make */
1.1.1.17! root     1471:        pDirName = (char *)STRAM_ADDR(STMemory_ReadLong(Params));
1.1.1.9   root     1472: 
1.1.1.15  root     1473:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Dcreate(\"%s\")\n", pDirName);
                   1474: 
1.1.1.9   root     1475:        Drive = GemDOS_IsFileNameAHardDrive(pDirName);
                   1476: 
1.1.1.17! root     1477:        if (!ISHARDDRIVE(Drive))
1.1.1.9   root     1478:        {
1.1.1.17! root     1479:                /* redirect to TOS */
        !          1480:                return false;
        !          1481:        }
1.1.1.9   root     1482: 
1.1.1.17! root     1483:        /* write protected device? */
        !          1484:        if (ConfigureParams.HardDisk.nWriteProtection == WRITEPROT_ON)
        !          1485:        {
        !          1486:                Log_Printf(LOG_WARN, "PREVENTED: GEMDOS Dcreate(\"%s\")\n", pDirName);
        !          1487:                Regs[REG_D0] = GEMDOS_EWRPRO;
        !          1488:                return true;
        !          1489:        }
1.1.1.9   root     1490: 
1.1.1.17! root     1491:        psDirPath = malloc(FILENAME_MAX);
        !          1492:        if (!psDirPath)
        !          1493:        {
        !          1494:                perror("GemDOS_MkDir");
        !          1495:                Regs[REG_D0] = GEMDOS_ENSMEM;
1.1.1.15  root     1496:                return true;
1.1.1.9   root     1497:        }
1.1.1.17! root     1498:        
        !          1499:        /* Copy old directory, as if calls fails keep this one */
        !          1500:        GemDOS_CreateHardDriveFileName(Drive, pDirName, psDirPath, FILENAME_MAX);
        !          1501:        
        !          1502:        /* Attempt to make directory */
        !          1503:        if (mkdir(psDirPath, 0755) == 0)
        !          1504:                Regs[REG_D0] = GEMDOS_EOK;
        !          1505:        else
        !          1506:                Regs[REG_D0] = GEMDOS_EACCDN;        /* Access denied */
        !          1507:        
        !          1508:        free(psDirPath);
        !          1509:        return true;
1.1       root     1510: }
                   1511: 
1.1.1.2   root     1512: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1513: /**
                   1514:  * GEMDOS RmDir
                   1515:  * Call 0x3A
                   1516:  */
1.1.1.13  root     1517: static bool GemDOS_RmDir(Uint32 Params)
1.1.1.6   root     1518: {
1.1.1.17! root     1519:        char *pDirName, *psDirPath;
1.1.1.9   root     1520:        int Drive;
                   1521: 
                   1522:        /* Find directory to make */
1.1.1.17! root     1523:        pDirName = (char *)STRAM_ADDR(STMemory_ReadLong(Params));
1.1.1.15  root     1524: 
                   1525:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Ddelete(\"%s\")\n", pDirName);
                   1526: 
1.1.1.9   root     1527:        Drive = GemDOS_IsFileNameAHardDrive(pDirName);
1.1.1.15  root     1528: 
1.1.1.17! root     1529:        if (!ISHARDDRIVE(Drive))
1.1.1.9   root     1530:        {
1.1.1.17! root     1531:                /* redirect to TOS */
        !          1532:                return false;
        !          1533:        }
1.1.1.9   root     1534: 
1.1.1.17! root     1535:        /* write protected device? */
        !          1536:        if (ConfigureParams.HardDisk.nWriteProtection == WRITEPROT_ON)
        !          1537:        {
        !          1538:                Log_Printf(LOG_WARN, "PREVENTED: GEMDOS Ddelete(\"%s\")\n", pDirName);
        !          1539:                Regs[REG_D0] = GEMDOS_EWRPRO;
        !          1540:                return true;
        !          1541:        }
1.1.1.9   root     1542: 
1.1.1.17! root     1543:        psDirPath = malloc(FILENAME_MAX);
        !          1544:        if (!psDirPath)
        !          1545:        {
        !          1546:                perror("GemDOS_RmDir");
        !          1547:                Regs[REG_D0] = GEMDOS_ENSMEM;
1.1.1.15  root     1548:                return true;
1.1.1.9   root     1549:        }
1.1.1.17! root     1550: 
        !          1551:        /* Copy old directory, as if calls fails keep this one */
        !          1552:        GemDOS_CreateHardDriveFileName(Drive, pDirName, psDirPath, FILENAME_MAX);
        !          1553: 
        !          1554:        /* Attempt to remove directory */
        !          1555:        if (rmdir(psDirPath) == 0)
        !          1556:                Regs[REG_D0] = GEMDOS_EOK;
        !          1557:        else
        !          1558:                Regs[REG_D0] = GEMDOS_EACCDN;        /* Access denied */
        !          1559:        
        !          1560:        free(psDirPath);
        !          1561:        return true;
1.1       root     1562: }
                   1563: 
1.1.1.11  root     1564: 
1.1.1.2   root     1565: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1566: /**
                   1567:  * GEMDOS ChDir
                   1568:  * Call 0x3B
                   1569:  */
1.1.1.13  root     1570: static bool GemDOS_ChDir(Uint32 Params)
1.1.1.6   root     1571: {
1.1.1.17! root     1572:        char *pDirName, *psTempDirPath;
        !          1573:        struct stat buf;
1.1.1.9   root     1574:        int Drive;
1.1       root     1575: 
1.1.1.9   root     1576:        /* Find new directory */
1.1.1.17! root     1577:        pDirName = (char *)STRAM_ADDR(STMemory_ReadLong(Params));
1.1.1.3   root     1578: 
1.1.1.15  root     1579:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Dsetpath(\"%s\")\n", pDirName);
1.1.1.3   root     1580: 
1.1.1.9   root     1581:        Drive = GemDOS_IsFileNameAHardDrive(pDirName);
1.1.1.3   root     1582: 
1.1.1.17! root     1583:        if (!ISHARDDRIVE(Drive))
1.1.1.9   root     1584:        {
1.1.1.17! root     1585:                /* redirect to TOS */
        !          1586:                return false;
        !          1587:        }
1.1.1.3   root     1588: 
1.1.1.17! root     1589:        /* Allocate temporary memory for path name: */
        !          1590:        psTempDirPath = malloc(FILENAME_MAX);
        !          1591:        if (!psTempDirPath)
        !          1592:        {
        !          1593:                perror("GemDOS_ChDir");
        !          1594:                Regs[REG_D0] = GEMDOS_ENSMEM;
        !          1595:                return true;
        !          1596:        }
1.1.1.11  root     1597: 
1.1.1.17! root     1598:        GemDOS_CreateHardDriveFileName(Drive, pDirName, psTempDirPath, FILENAME_MAX);
1.1.1.15  root     1599: 
1.1.1.17! root     1600:        // Remove trailing slashes (stat on Windows does not like that)
        !          1601:        File_CleanFileName(psTempDirPath);
1.1.1.15  root     1602: 
1.1.1.17! root     1603:        if (stat(psTempDirPath, &buf))
        !          1604:        {
        !          1605:                /* error */
        !          1606:                free(psTempDirPath);
        !          1607:                Regs[REG_D0] = GEMDOS_EPTHNF;
        !          1608:                return true;
        !          1609:        }
1.1.1.9   root     1610: 
1.1.1.17! root     1611:        File_AddSlashToEndFileName(psTempDirPath);
        !          1612:        File_MakeAbsoluteName(psTempDirPath);
1.1.1.9   root     1613: 
1.1.1.17! root     1614:        /* Prevent '..' commands moving BELOW the root HDD folder */
        !          1615:        /* by double checking if path is valid */
        !          1616:        if (strncmp(psTempDirPath, emudrives[Drive-2]->hd_emulation_dir,
1.1.1.15  root     1617:                    strlen(emudrives[Drive-2]->hd_emulation_dir)) == 0)
1.1.1.17! root     1618:        {
        !          1619:                strcpy(emudrives[Drive-2]->fs_currpath, psTempDirPath);
        !          1620:                Regs[REG_D0] = GEMDOS_EOK;
        !          1621:        }
        !          1622:        else
        !          1623:        {
        !          1624:                Regs[REG_D0] = GEMDOS_EPTHNF;
1.1.1.9   root     1625:        }
1.1.1.17! root     1626:        free(psTempDirPath);
        !          1627: 
        !          1628:        return true;
1.1.1.6   root     1629: 
1.1.1.17! root     1630: }
        !          1631: 
        !          1632: 
        !          1633: /*-----------------------------------------------------------------------*/
        !          1634: /**
        !          1635:  * Helper to check whether given file's path is missing.
        !          1636:  * Returns true if missing, false if found.
        !          1637:  * Modifies the argument buffer.
        !          1638:  */
        !          1639: static bool GemDOS_FilePathMissing(char *szActualFileName)
        !          1640: {
        !          1641:        char *ptr = strrchr(szActualFileName, PATHSEP);
        !          1642:        if (ptr)
        !          1643:        {
        !          1644:                *ptr = 0;   /* Strip filename from string */
        !          1645:                if (!File_DirectoryExists(szActualFileName))
        !          1646:                        return true;
        !          1647:        }
        !          1648:        return false;
1.1       root     1649: }
                   1650: 
1.1.1.11  root     1651: 
1.1.1.2   root     1652: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1653: /**
                   1654:  * GEMDOS Create file
                   1655:  * Call 0x3C
                   1656:  */
1.1.1.13  root     1657: static bool GemDOS_Create(Uint32 Params)
1.1       root     1658: {
1.1.1.17! root     1659:        /* TODO: host filenames might not fit into this */
1.1.1.11  root     1660:        char szActualFileName[MAX_GEMDOS_PATH];
1.1.1.17! root     1661:        char *pszFileName;
1.1.1.9   root     1662:        int Drive,Index,Mode;
                   1663: 
                   1664:        /* Find filename */
1.1.1.17! root     1665:        pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params));
        !          1666:        Mode = STMemory_ReadWord(Params+SIZE_LONG);
1.1.1.15  root     1667: 
                   1668:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fcreate(\"%s\", 0x%x)\n", pszFileName, Mode);
                   1669: 
1.1.1.9   root     1670:        Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
1.1.1.15  root     1671: 
1.1.1.12  root     1672:        if (!ISHARDDRIVE(Drive))
1.1.1.9   root     1673:        {
1.1.1.17! root     1674:                /* redirect to TOS */
1.1.1.15  root     1675:                return false;
1.1.1.12  root     1676:        }
1.1.1.9   root     1677: 
1.1.1.12  root     1678:        if (Mode == GEMDOS_FILE_ATTRIB_VOLUME_LABEL)
                   1679:        {
1.1.1.17! root     1680:                Log_Printf(LOG_WARN, "Warning: Hatari doesn't support GEMDOS volume"
        !          1681:                           " label setting\n(for '%s')\n", pszFileName);
1.1.1.12  root     1682:                Regs[REG_D0] = GEMDOS_EFILNF;         /* File not found */
1.1.1.15  root     1683:                return true;
1.1.1.12  root     1684:        }
1.1       root     1685: 
1.1.1.17! root     1686:        /* write protected device? */
        !          1687:        if (ConfigureParams.HardDisk.nWriteProtection == WRITEPROT_ON)
        !          1688:        {
        !          1689:                Log_Printf(LOG_WARN, "PREVENTED: GEMDOS Fcreate(\"%s\")\n", pszFileName);
        !          1690:                Regs[REG_D0] = GEMDOS_EWRPRO;
        !          1691:                return true;
        !          1692:        }
        !          1693: 
1.1.1.12  root     1694:        /* Now convert to hard drive filename */
                   1695:        GemDOS_CreateHardDriveFileName(Drive, pszFileName,
                   1696:                                    szActualFileName, sizeof(szActualFileName));
                   1697: 
                   1698:        /* Find slot to store file handle, as need to return WORD handle for ST */
                   1699:        Index = GemDOS_FindFreeFileHandle();
                   1700:        if (Index==-1)
                   1701:        {
                   1702:                /* No free handles, return error code */
                   1703:                Regs[REG_D0] = GEMDOS_ENHNDL;       /* No more handles */
1.1.1.15  root     1704:                return true;
1.1.1.12  root     1705:        }
1.1.1.17! root     1706:        
        !          1707:        /* truncate and open for reading & writing */
        !          1708:        FileHandles[Index].FileHandle = fopen(szActualFileName, "wb+");
1.1.1.15  root     1709: 
1.1.1.12  root     1710:        if (FileHandles[Index].FileHandle != NULL)
                   1711:        {
1.1.1.17! root     1712:                /* FIXME: implement other Mode attributes
        !          1713:                 * - GEMDOS_FILE_ATTRIB_HIDDEN       (FA_HIDDEN)
        !          1714:                 * - GEMDOS_FILE_ATTRIB_SYSTEM_FILE  (FA_SYSTEM)
        !          1715:                 * - GEMDOS_FILE_ATTRIB_SUBDIRECTORY (FA_DIR)
        !          1716:                 * - GEMDOS_FILE_ATTRIB_WRITECLOSE   (FA_ARCHIVE)
        !          1717:                 *   (set automatically by GemDOS >= 0.15)
        !          1718:                 */
        !          1719:                if (Mode & GEMDOS_FILE_ATTRIB_READONLY)
        !          1720:                {
        !          1721:                        /* after closing, file should be read-only */
        !          1722:                        chmod(szActualFileName, S_IRUSR|S_IRGRP|S_IROTH);
        !          1723:                }
1.1.1.12  root     1724:                /* Tag handle table entry as used and return handle */
1.1.1.15  root     1725:                FileHandles[Index].bUsed = true;
1.1.1.17! root     1726:                snprintf(FileHandles[Index].szActualName,
        !          1727:                         sizeof(FileHandles[Index].szActualName),
        !          1728:                         "%s", szActualFileName);
        !          1729: 
        !          1730:                /* Return valid ST file handle from our range (from BASE_FILEHANDLE upwards) */
        !          1731:                Regs[REG_D0] = Index+BASE_FILEHANDLE;
        !          1732:                LOG_TRACE(TRACE_OS_GEMDOS, "-> FD %d (%s)\n", Index,
        !          1733:                          Mode & GEMDOS_FILE_ATTRIB_READONLY ? "read-only":"read/write");
1.1.1.15  root     1734:                return true;
1.1.1.12  root     1735:        }
1.1.1.2   root     1736: 
1.1.1.17! root     1737:        /* We failed to create the file, did we have required access rights? */
        !          1738:        if (errno == EACCES || errno == EROFS ||
        !          1739:            errno == EPERM || errno == EISDIR)
1.1.1.12  root     1740:        {
1.1.1.17! root     1741:                Log_Printf(LOG_WARN, "GEMDOS failed to create/truncate '%s'\n",
        !          1742:                           szActualFileName);
        !          1743:                Regs[REG_D0] = GEMDOS_EACCDN;
        !          1744:                return true;
1.1.1.9   root     1745:        }
1.1.1.17! root     1746: 
        !          1747:        /* Or was path to file missing? (ST-Zip 2.6 relies on getting
        !          1748:         * correct error about that during extraction of ZIP files.)
        !          1749:         */
        !          1750:        if (errno == ENOTDIR || GemDOS_FilePathMissing(szActualFileName))
        !          1751:        {
        !          1752:                Regs[REG_D0] = GEMDOS_EPTHNF; /* Path not found */
        !          1753:                return true;
        !          1754:        }
        !          1755: 
1.1.1.12  root     1756:        Regs[REG_D0] = GEMDOS_EFILNF;         /* File not found */
1.1.1.15  root     1757:        return true;
1.1       root     1758: }
                   1759: 
1.1.1.2   root     1760: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1761: /**
                   1762:  * GEMDOS Open file
                   1763:  * Call 0x3D
                   1764:  */
1.1.1.13  root     1765: static bool GemDOS_Open(Uint32 Params)
1.1       root     1766: {
1.1.1.17! root     1767:        /* TODO: host filenames might not fit into this */
1.1.1.11  root     1768:        char szActualFileName[MAX_GEMDOS_PATH];
1.1.1.9   root     1769:        char *pszFileName;
1.1.1.17! root     1770:        const char *ModeStr;
        !          1771:        /* convert atari modes to stdio modes */
        !          1772:        struct {
        !          1773:                const char *mode;
        !          1774:                const char *desc;
        !          1775:        } Modes[] = {
        !          1776:                { "rb",  "read-only" },
        !          1777:                /* FIXME: is actually read/write as "wb" would truncate */
        !          1778:                { "rb+", "write-only" },
        !          1779:                { "rb+", "read/write" },
        !          1780:                { "rb+", "read/write" }
        !          1781:        };
        !          1782:        int Drive, Index, Mode;
1.1.1.9   root     1783: 
                   1784:        /* Find filename */
1.1.1.17! root     1785:        pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params));
        !          1786:        Mode = STMemory_ReadWord(Params+SIZE_LONG);
1.1.1.15  root     1787: 
                   1788:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fopen(\"%s\", 0x%x)\n", pszFileName, Mode);
                   1789: 
1.1.1.9   root     1790:        Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
                   1791: 
1.1.1.12  root     1792:        if (!ISHARDDRIVE(Drive))
1.1.1.9   root     1793:        {
1.1.1.17! root     1794:                /* redirect to TOS */
1.1.1.15  root     1795:                return false;
1.1.1.12  root     1796:        }
1.1.1.17! root     1797: 
1.1.1.12  root     1798:        /* And convert to hard drive filename */
                   1799:        GemDOS_CreateHardDriveFileName(Drive, pszFileName,
                   1800:                                    szActualFileName, sizeof(szActualFileName));
                   1801: 
                   1802:        /* Find slot to store file handle, as need to return WORD handle for ST  */
                   1803:        Index = GemDOS_FindFreeFileHandle();
                   1804:        if (Index == -1)
                   1805:        {
                   1806:                /* No free handles, return error code */
                   1807:                Regs[REG_D0] = GEMDOS_ENHNDL;       /* No more handles */
1.1.1.15  root     1808:                return true;
1.1.1.9   root     1809:        }
1.1.1.6   root     1810: 
1.1.1.17! root     1811:        if (ConfigureParams.HardDisk.nWriteProtection == WRITEPROT_ON)
        !          1812:        {
        !          1813:                /* force all accesses to be read-only */
        !          1814:                ModeStr = Modes[0].mode;
        !          1815:        }
        !          1816:        else
        !          1817:        {
        !          1818:                /* GEMDOS mount can be written, try open in requested mode */
        !          1819:                ModeStr = Modes[Mode&0x03].mode;
        !          1820:        }
        !          1821: 
1.1.1.12  root     1822:        /* FIXME: Open file
1.1.1.17! root     1823:         * - fopen() modes don't allow write-only mode without truncating
        !          1824:         *   which would be needed to implement mode 1 (write-only) correctly.
1.1.1.12  root     1825:         *   Fixing this requires using open() and file descriptors instead
1.1.1.17! root     1826:         *   of fopen() and FILE* pointers, but Windows doesn't support that.
1.1.1.12  root     1827:         */
1.1.1.17! root     1828:        FileHandles[Index].FileHandle =  fopen(szActualFileName, ModeStr);
1.1.1.15  root     1829: 
1.1.1.12  root     1830:        if (FileHandles[Index].FileHandle != NULL)
                   1831:        {
                   1832:                /* Tag handle table entry as used and return handle */
1.1.1.15  root     1833:                FileHandles[Index].bUsed = true;
1.1.1.17! root     1834:                snprintf(FileHandles[Index].szActualName,
        !          1835:                         sizeof(FileHandles[Index].szActualName),
        !          1836:                         "%s", szActualFileName);
        !          1837: 
        !          1838:                /* Return valid ST file handle from our range (BASE_FILEHANDLE upwards) */
        !          1839:                Regs[REG_D0] = Index+BASE_FILEHANDLE;
        !          1840:                LOG_TRACE(TRACE_OS_GEMDOS, "-> FD %d (%s)\n",
        !          1841:                          Index, Modes[Mode&0x03].desc);
1.1.1.15  root     1842:                return true;
1.1.1.12  root     1843:        }
1.1.1.15  root     1844: 
1.1.1.17! root     1845:        if (errno == EACCES || errno == EROFS ||
        !          1846:            errno == EPERM || errno == EISDIR)
        !          1847:        {
        !          1848:                Log_Printf(LOG_WARN, "GEMDOS missing %s permission to file '%s'\n",
        !          1849:                           Modes[Mode&0x03].desc, szActualFileName);
        !          1850:                Regs[REG_D0] = GEMDOS_EACCDN;
        !          1851:                return true;
        !          1852:        }
        !          1853:        if (errno == ENOTDIR || GemDOS_FilePathMissing(szActualFileName))
        !          1854:        {
        !          1855:                /* Path not found */
        !          1856:                Regs[REG_D0] = GEMDOS_EPTHNF;
        !          1857:                return true;
        !          1858:        }
        !          1859:        /* File not found / error opening */
        !          1860:        Regs[REG_D0] = GEMDOS_EFILNF;
1.1.1.15  root     1861:        return true;
1.1       root     1862: }
                   1863: 
1.1.1.2   root     1864: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1865: /**
                   1866:  * GEMDOS Close file
                   1867:  * Call 0x3E
                   1868:  */
1.1.1.13  root     1869: static bool GemDOS_Close(Uint32 Params)
1.1       root     1870: {
1.1.1.9   root     1871:        int Handle;
1.1       root     1872: 
1.1.1.9   root     1873:        /* Find our handle - may belong to TOS */
1.1.1.17! root     1874:        Handle = STMemory_ReadWord(Params);
1.1       root     1875: 
1.1.1.15  root     1876:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fclose(%i)\n", Handle);
                   1877: 
1.1.1.17! root     1878:        Handle -= BASE_FILEHANDLE;
        !          1879: 
1.1.1.9   root     1880:        /* Check handle was valid */
                   1881:        if (GemDOS_IsInvalidFileHandle(Handle))
                   1882:        {
1.1.1.17! root     1883:                /* no, assume it was TOS one -> redirect */
1.1.1.15  root     1884:                return false;
1.1.1.9   root     1885:        }
1.1.1.17! root     1886:        
        !          1887:        /* Close file and free up handle table */
        !          1888:        fclose(FileHandles[Handle].FileHandle);
        !          1889:        FileHandles[Handle].bUsed = false;
        !          1890: 
        !          1891:        /* Return no error */
        !          1892:        Regs[REG_D0] = GEMDOS_EOK;
        !          1893:        return true;
1.1       root     1894: }
                   1895: 
1.1.1.2   root     1896: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1897: /**
                   1898:  * GEMDOS Read file
                   1899:  * Call 0x3F
                   1900:  */
1.1.1.13  root     1901: static bool GemDOS_Read(Uint32 Params)
1.1       root     1902: {
1.1.1.9   root     1903:        char *pBuffer;
1.1.1.17! root     1904:        long CurrentPos, FileSize, nBytesRead, nBytesLeft;
        !          1905:        Uint32 Addr;
        !          1906:        Uint32 Size;
1.1.1.9   root     1907:        int Handle;
                   1908: 
                   1909:        /* Read details from stack */
1.1.1.17! root     1910:        Handle = STMemory_ReadWord(Params);
        !          1911:        Size = STMemory_ReadLong(Params+SIZE_WORD);
        !          1912:        Addr = STMemory_ReadLong(Params+SIZE_WORD+SIZE_LONG);
        !          1913:        pBuffer = (char *)STRAM_ADDR(Addr);
1.1.1.9   root     1914: 
1.1.1.17! root     1915:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fread(%i, %i, 0x%x)\n", 
        !          1916:                  Handle, Size, Addr);
        !          1917: 
        !          1918:        Handle -= BASE_FILEHANDLE;
1.1.1.15  root     1919: 
1.1.1.9   root     1920:        /* Check handle was valid */
                   1921:        if (GemDOS_IsInvalidFileHandle(Handle))
                   1922:        {
1.1.1.17! root     1923:                /* assume it was TOS one -> redirect */
1.1.1.15  root     1924:                return false;
1.1.1.9   root     1925:        }
                   1926: 
1.1.1.17! root     1927:        /* Old TOS versions treat the Size parameter as signed */
        !          1928:        if (TosVersion < 0x400 && (Size & 0x80000000))
        !          1929:        {
        !          1930:                /* return -1 as original GEMDOS */
        !          1931:                Regs[REG_D0] = -1;
        !          1932:                return true;
        !          1933:        }
        !          1934:        
        !          1935:        /* To quick check to see where our file pointer is and how large the file is */
        !          1936:        CurrentPos = ftell(FileHandles[Handle].FileHandle);
        !          1937:        fseek(FileHandles[Handle].FileHandle, 0, SEEK_END);
        !          1938:        FileSize = ftell(FileHandles[Handle].FileHandle);
        !          1939:        fseek(FileHandles[Handle].FileHandle, CurrentPos, SEEK_SET);
        !          1940: 
        !          1941:        nBytesLeft = FileSize-CurrentPos;
        !          1942:        
        !          1943:        /* Check for bad size and End Of File */
        !          1944:        if (Size <= 0 || nBytesLeft <= 0)
        !          1945:        {
        !          1946:                /* return zero (bytes read) as original GEMDOS/EmuTOS */
        !          1947:                Regs[REG_D0] = 0;
        !          1948:                return true;
        !          1949:        }
1.1.1.9   root     1950: 
1.1.1.17! root     1951:        /* Limit to size of file to prevent errors */
        !          1952:        if (Size > (Uint32)nBytesLeft)
        !          1953:                Size = nBytesLeft;
1.1.1.9   root     1954: 
1.1.1.17! root     1955:        /* Check that read is to valid memory area */
        !          1956:        if (!STMemory_ValidArea(Addr, Size))
        !          1957:        {
        !          1958:                Log_Printf(LOG_TODO, "GEMDOS Fread() failed due to invalid RAM range 0x%x+%i\n", Addr, Size);
        !          1959:                Regs[REG_D0] = GEMDOS_ERANGE;
        !          1960:                return true;
1.1.1.9   root     1961:        }
1.1.1.17! root     1962:        /* And read data in */
        !          1963:        nBytesRead = fread(pBuffer, 1, Size, FileHandles[Handle].FileHandle);
        !          1964:        
        !          1965:        /* Return number of bytes read */
        !          1966:        Regs[REG_D0] = nBytesRead;
        !          1967:        
        !          1968:        return true;
1.1       root     1969: }
                   1970: 
1.1.1.2   root     1971: /*-----------------------------------------------------------------------*/
1.1.1.12  root     1972: /**
                   1973:  * GEMDOS Write file
                   1974:  * Call 0x40
                   1975:  */
1.1.1.13  root     1976: static bool GemDOS_Write(Uint32 Params)
1.1       root     1977: {
1.1.1.9   root     1978:        char *pBuffer;
1.1.1.17! root     1979:        long nBytesWritten;
        !          1980:        Uint32 Addr;
        !          1981:        Sint32 Size;
1.1.1.9   root     1982:        int Handle;
1.1       root     1983: 
1.1.1.9   root     1984:        /* Read details from stack */
1.1.1.17! root     1985:        Handle = STMemory_ReadWord(Params);
        !          1986:        Size = STMemory_ReadLong(Params+SIZE_WORD);
        !          1987:        Addr = STMemory_ReadLong(Params+SIZE_WORD+SIZE_LONG);
        !          1988:        pBuffer = (char *)STRAM_ADDR(Addr);
        !          1989: 
        !          1990:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fwrite(%i, %i, 0x%x)\n", 
        !          1991:                  Handle, Size, Addr);
1.1.1.9   root     1992: 
1.1.1.17! root     1993:        Handle -= BASE_FILEHANDLE;
1.1.1.15  root     1994: 
1.1.1.17! root     1995:        /* Check handle was valid */
        !          1996:        if (GemDOS_IsInvalidFileHandle(Handle))
1.1.1.9   root     1997:        {
1.1.1.17! root     1998:                /* assume it was TOS one -> redirect */
        !          1999:                return false;
        !          2000:        }
1.1.1.9   root     2001: 
1.1.1.17! root     2002:        /* write protected device? */
        !          2003:        if (ConfigureParams.HardDisk.nWriteProtection == WRITEPROT_ON)
        !          2004:        {
        !          2005:                Log_Printf(LOG_WARN, "PREVENTED: GEMDOS Fwrite(%d,...)\n", Handle);
        !          2006:                Regs[REG_D0] = GEMDOS_EWRPRO;
1.1.1.15  root     2007:                return true;
1.1.1.9   root     2008:        }
1.1       root     2009: 
1.1.1.17! root     2010:        /* Check that write is from valid memory area */
        !          2011:        if (!STMemory_ValidArea(Addr, Size))
        !          2012:        {
        !          2013:                Log_Printf(LOG_TODO, "GEMDOS Fwrite() failed due to invalid RAM range 0x%x+%i\n", Addr, Size);
        !          2014:                Regs[REG_D0] = GEMDOS_ERANGE;
        !          2015:                return true;
        !          2016:        }
        !          2017: 
        !          2018:        nBytesWritten = fwrite(pBuffer, 1, Size, FileHandles[Handle].FileHandle);
        !          2019:        if (ferror(FileHandles[Handle].FileHandle))
        !          2020:        {
        !          2021:                Log_Printf(LOG_WARN, "GEMDOS failed to write to '%s'\n",
        !          2022:                           FileHandles[Handle].szActualName );
        !          2023:                Regs[REG_D0] = GEMDOS_EACCDN;      /* Access denied (ie read-only) */
        !          2024:        }
        !          2025:        else
        !          2026:        {
        !          2027:                Regs[REG_D0] = nBytesWritten;      /* OK */
        !          2028:        }
        !          2029:        return true;
1.1       root     2030: }
                   2031: 
1.1.1.2   root     2032: /*-----------------------------------------------------------------------*/
1.1.1.12  root     2033: /**
                   2034:  * GEMDOS Delete file
                   2035:  * Call 0x41
                   2036:  */
1.1.1.13  root     2037: static bool GemDOS_FDelete(Uint32 Params)
1.1       root     2038: {
1.1.1.17! root     2039:        char *pszFileName, *psActualFileName;
1.1.1.9   root     2040:        int Drive;
                   2041: 
                   2042:        /* Find filename */
1.1.1.17! root     2043:        pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params));
1.1.1.15  root     2044: 
                   2045:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fdelete(\"%s\")\n", pszFileName);
                   2046: 
1.1.1.9   root     2047:        Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
1.1.1.15  root     2048: 
1.1.1.17! root     2049:        if (!ISHARDDRIVE(Drive))
1.1.1.9   root     2050:        {
1.1.1.17! root     2051:                /* redirect to TOS */
        !          2052:                return false;
        !          2053:        }
1.1       root     2054: 
1.1.1.17! root     2055:        /* write protected device? */
        !          2056:        if (ConfigureParams.HardDisk.nWriteProtection == WRITEPROT_ON)
        !          2057:        {
        !          2058:                Log_Printf(LOG_WARN, "PREVENTED: GEMDOS Fdelete(\"%s\")\n", pszFileName);
        !          2059:                Regs[REG_D0] = GEMDOS_EWRPRO;
        !          2060:                return true;
        !          2061:        }
1.1.1.9   root     2062: 
1.1.1.17! root     2063:        psActualFileName = malloc(FILENAME_MAX);
        !          2064:        if (!psActualFileName)
        !          2065:        {
        !          2066:                perror("GemDOS_FDelete");
        !          2067:                Regs[REG_D0] = GEMDOS_ENSMEM;
1.1.1.15  root     2068:                return true;
1.1.1.9   root     2069:        }
1.1       root     2070: 
1.1.1.17! root     2071:        /* And convert to hard drive filename */
        !          2072:        GemDOS_CreateHardDriveFileName(Drive, pszFileName, psActualFileName, FILENAME_MAX);
        !          2073: 
        !          2074:        /* Now delete file?? */
        !          2075:        if (unlink(psActualFileName) == 0)
        !          2076:                Regs[REG_D0] = GEMDOS_EOK;          /* OK */
        !          2077:        else
        !          2078:                Regs[REG_D0] = GEMDOS_EFILNF;       /* File not found */
        !          2079: 
        !          2080:        free(psActualFileName);
        !          2081:        return true;
1.1       root     2082: }
                   2083: 
1.1.1.2   root     2084: /*-----------------------------------------------------------------------*/
1.1.1.12  root     2085: /**
                   2086:  * GEMDOS File seek
                   2087:  * Call 0x42
                   2088:  */
1.1.1.13  root     2089: static bool GemDOS_LSeek(Uint32 Params)
1.1       root     2090: {
1.1.1.9   root     2091:        long Offset;
1.1.1.15  root     2092:        int Handle, Mode;
                   2093:        long nFileSize;
                   2094:        long nOldPos, nDestPos;
                   2095:        FILE *fhndl;
1.1.1.9   root     2096: 
                   2097:        /* Read details from stack */
1.1.1.17! root     2098:        Offset = (Sint32)STMemory_ReadLong(Params);
        !          2099:        Handle = STMemory_ReadWord(Params+SIZE_LONG);
        !          2100:        Mode = STMemory_ReadWord(Params+SIZE_LONG+SIZE_WORD);
1.1       root     2101: 
1.1.1.15  root     2102:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fseek(%li, %i, %i)\n", Offset, Handle, Mode);
                   2103: 
1.1.1.17! root     2104:        Handle -= BASE_FILEHANDLE;
        !          2105: 
1.1.1.9   root     2106:        /* Check handle was valid */
                   2107:        if (GemDOS_IsInvalidFileHandle(Handle))
                   2108:        {
1.1.1.17! root     2109:                /* assume it was TOS one -> redirect */
1.1.1.15  root     2110:                return false;
1.1.1.9   root     2111:        }
1.1.1.15  root     2112: 
                   2113:        fhndl = FileHandles[Handle].FileHandle;
                   2114: 
                   2115:        /* Save old position in file */
                   2116:        nOldPos = ftell(fhndl);
                   2117: 
                   2118:        /* Determine the size of the file */
                   2119:        fseek(fhndl, 0L, SEEK_END);
                   2120:        nFileSize = ftell(fhndl);
                   2121: 
                   2122:        switch (Mode)
                   2123:        {
1.1.1.17! root     2124:         case 0: nDestPos = Offset; break; /* positive offset */
1.1.1.15  root     2125:         case 1: nDestPos = nOldPos + Offset; break;
1.1.1.17! root     2126:         case 2: nDestPos = nFileSize + Offset; break; /* negative offset */
1.1.1.15  root     2127:         default:
                   2128:                /* Restore old position and return error */
                   2129:                fseek(fhndl, nOldPos, SEEK_SET);
                   2130:                Regs[REG_D0] = GEMDOS_EINVFN;
                   2131:                return true;
                   2132:        }
                   2133: 
                   2134:        if (nDestPos < 0 || nDestPos > nFileSize)
1.1.1.9   root     2135:        {
1.1.1.15  root     2136:                /* Restore old position and return error */
                   2137:                fseek(fhndl, nOldPos, SEEK_SET);
                   2138:                Regs[REG_D0] = GEMDOS_ERANGE;
                   2139:                return true;
1.1.1.9   root     2140:        }
1.1.1.15  root     2141: 
                   2142:        /* Seek to new position and return offset from start of file */
                   2143:        fseek(fhndl, nDestPos, SEEK_SET);
                   2144:        Regs[REG_D0] = ftell(fhndl);
                   2145: 
                   2146:        return true;
1.1       root     2147: }
                   2148: 
1.1.1.10  root     2149: 
                   2150: /*-----------------------------------------------------------------------*/
1.1.1.12  root     2151: /**
1.1.1.17! root     2152:  * GEMDOS Fattrib() - get or set file and directory attributes
1.1.1.12  root     2153:  * Call 0x43
                   2154:  */
1.1.1.13  root     2155: static bool GemDOS_Fattrib(Uint32 Params)
1.1.1.10  root     2156: {
1.1.1.17! root     2157:        /* TODO: host filenames might not fit into this */
1.1.1.11  root     2158:        char sActualFileName[MAX_GEMDOS_PATH];
1.1.1.10  root     2159:        char *psFileName;
                   2160:        int nDrive;
                   2161:        int nRwFlag, nAttrib;
1.1.1.12  root     2162:        struct stat FileStat;
1.1.1.10  root     2163: 
                   2164:        /* Find filename */
1.1.1.17! root     2165:        psFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params));
1.1.1.10  root     2166:        nDrive = GemDOS_IsFileNameAHardDrive(psFileName);
                   2167: 
1.1.1.17! root     2168:        nRwFlag = STMemory_ReadWord(Params+SIZE_LONG);
        !          2169:        nAttrib = STMemory_ReadWord(Params+SIZE_LONG+SIZE_WORD);
1.1.1.10  root     2170: 
1.1.1.15  root     2171:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fattrib(\"%s\", %d, 0x%x)\n",
                   2172:                  psFileName, nRwFlag, nAttrib);
1.1.1.10  root     2173: 
1.1.1.12  root     2174:        if (!ISHARDDRIVE(nDrive))
1.1.1.10  root     2175:        {
1.1.1.17! root     2176:                /* redirect to TOS */
1.1.1.15  root     2177:                return false;
1.1.1.12  root     2178:        }
1.1.1.10  root     2179: 
1.1.1.12  root     2180:        /* Convert to hard drive filename */
                   2181:        GemDOS_CreateHardDriveFileName(nDrive, psFileName,
                   2182:                                      sActualFileName, sizeof(sActualFileName));
1.1.1.10  root     2183: 
1.1.1.12  root     2184:        if (nAttrib == GEMDOS_FILE_ATTRIB_VOLUME_LABEL)
                   2185:        {
1.1.1.17! root     2186:                Log_Printf(LOG_WARN, "Warning: Hatari doesn't support GEMDOS volume label setting\n(for '%s')\n", sActualFileName);
1.1.1.12  root     2187:                Regs[REG_D0] = GEMDOS_EFILNF;         /* File not found */
1.1.1.15  root     2188:                return true;
1.1.1.12  root     2189:        }
                   2190:        if (stat(sActualFileName, &FileStat) != 0)
                   2191:        {
                   2192:                Regs[REG_D0] = GEMDOS_EFILNF;         /* File not found */
1.1.1.15  root     2193:                return true;
1.1.1.12  root     2194:        }
                   2195:        if (nRwFlag == 0)
                   2196:        {
                   2197:                /* Read attributes */
                   2198:                Regs[REG_D0] = GemDOS_ConvertAttribute(FileStat.st_mode);
1.1.1.15  root     2199:                return true;
1.1.1.12  root     2200:        }
1.1.1.17! root     2201: 
        !          2202:        /* write or auto protected device? */
        !          2203:        if (ConfigureParams.HardDisk.nWriteProtection != WRITEPROT_OFF)
        !          2204:        {
        !          2205:                Log_Printf(LOG_WARN, "PREVENTED: GEMDOS Fattrib(\"%s\",...)\n", psFileName);
        !          2206:                Regs[REG_D0] = GEMDOS_EWRPRO;
        !          2207:                return true;
        !          2208:        }
        !          2209: 
        !          2210:        if (nAttrib & GEMDOS_FILE_ATTRIB_SUBDIRECTORY)
        !          2211:        {
        !          2212:                if (!S_ISDIR(FileStat.st_mode))
        !          2213:                {
        !          2214:                        /* file, not dir -> path not found */
        !          2215:                        Regs[REG_D0] = GEMDOS_EPTHNF;
        !          2216:                        return true;
        !          2217:                }
        !          2218:        }
        !          2219:        else
        !          2220:        {
        !          2221:                if (S_ISDIR(FileStat.st_mode))
        !          2222:                {
        !          2223:                        /* dir, not file -> file not found */
        !          2224:                        Regs[REG_D0] = GEMDOS_EFILNF;
        !          2225:                        return true;
        !          2226:                }
        !          2227:        }
        !          2228:        
1.1.1.12  root     2229:        if (nAttrib & GEMDOS_FILE_ATTRIB_READONLY)
                   2230:        {
                   2231:                /* set read-only (readable by all) */
                   2232:                if (chmod(sActualFileName, S_IRUSR|S_IRGRP|S_IROTH) == 0)
1.1.1.10  root     2233:                {
1.1.1.17! root     2234:                        Regs[REG_D0] = nAttrib;
1.1.1.15  root     2235:                        return true;
1.1.1.10  root     2236:                }
                   2237:        }
1.1.1.17! root     2238:        else
        !          2239:        {
        !          2240:                /* set writable (by user, readable by all) */
        !          2241:                if (chmod(sActualFileName, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH) == 0)
        !          2242:                {
        !          2243:                        Regs[REG_D0] = nAttrib;
        !          2244:                        return true;
        !          2245:                }
        !          2246:        }
        !          2247: 
        !          2248:        /* FIXME: support hidden/system/archive flags?
        !          2249:         * System flag is from DOS, not used by TOS.
        !          2250:         * Archive bit is cleared by backup programs
        !          2251:         * and set whenever file is written to.
        !          2252:         */
1.1.1.12  root     2253:        Regs[REG_D0] = GEMDOS_EACCDN;         /* Acces denied */
1.1.1.15  root     2254:        return true;
1.1.1.10  root     2255: }
                   2256: 
                   2257: 
1.1.1.2   root     2258: /*-----------------------------------------------------------------------*/
1.1.1.12  root     2259: /**
                   2260:  * GEMDOS Get Directory
                   2261:  * Call 0x47
                   2262:  */
1.1.1.10  root     2263: static int GemDOS_GetDir(Uint32 Params)
1.1.1.9   root     2264: {
1.1.1.10  root     2265:        Uint32 Address;
                   2266:        Uint16 Drive;
1.1.1.9   root     2267: 
1.1.1.17! root     2268:        Address = STMemory_ReadLong(Params);
        !          2269:        Drive = STMemory_ReadWord(Params+SIZE_LONG);
1.1.1.15  root     2270:        /* Note: Drive = 0 means current drive, 1 = A:, 2 = B:, 3 = C:, etc. */
                   2271: 
                   2272:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Dgetpath(0x%x, %i)\n", Address, (int)Drive);
                   2273: 
1.1.1.9   root     2274:        /* is it our drive? */
1.1.1.15  root     2275:        if ((Drive == 0 && CurrentDrive >= 2) || (Drive >= 3 /*&& Drive <= nNumDrives*/))
1.1.1.9   root     2276:        {
1.1.1.11  root     2277:                char path[MAX_GEMDOS_PATH];
1.1.1.9   root     2278:                int i,len,c;
                   2279: 
1.1.1.15  root     2280:                if (Drive == 0)
                   2281:                        Drive = CurrentDrive;
                   2282:                else
                   2283:                        Drive--;
                   2284: 
                   2285:                if (emudrives[Drive-2] == NULL)
                   2286:                {
                   2287:                        return false;
                   2288:                }
                   2289: 
1.1.1.17! root     2290:                *path = '\0';
        !          2291:                strncat(path,&emudrives[Drive-2]->fs_currpath[strlen(emudrives[Drive-2]->hd_emulation_dir)], sizeof(path)-1);
1.1.1.15  root     2292: 
                   2293:                // convert it to ST path (DOS)
1.1.1.17! root     2294:                File_CleanFileName(path);
        !          2295:                len = strlen(path);
1.1.1.9   root     2296:                for (i = 0; i <= len; i++)
                   2297:                {
                   2298:                        c = path[i];
1.1.1.12  root     2299:                        STMemory_WriteByte(Address+i, (c==PATHSEP ? '\\' : c) );
1.1.1.9   root     2300:                }
1.1.1.15  root     2301:                LOG_TRACE(TRACE_OS_GEMDOS, "GemDOS_GetDir (%d) = %s\n", Drive, path );
                   2302: 
                   2303:                Regs[REG_D0] = GEMDOS_EOK;          /* OK */
1.1.1.9   root     2304: 
1.1.1.15  root     2305:                return true;
1.1.1.9   root     2306:        }
1.1.1.17! root     2307:        /* redirect to TOS */
        !          2308:        return false;
1.1       root     2309: }
                   2310: 
                   2311: 
1.1.1.2   root     2312: /*-----------------------------------------------------------------------*/
1.1.1.12  root     2313: /**
                   2314:  * GEMDOS PExec handler
                   2315:  * Call 0x4B
                   2316:  */
1.1.1.10  root     2317: static int GemDOS_Pexec(Uint32 Params)
1.1       root     2318: {
1.1.1.17! root     2319:        int Drive;
1.1.1.10  root     2320:        Uint16 Mode;
1.1.1.17! root     2321:        char *pszFileName;
1.1       root     2322: 
1.1.1.9   root     2323:        /* Find PExec mode */
1.1.1.17! root     2324:        Mode = STMemory_ReadWord(Params);
1.1.1.11  root     2325: 
1.1.1.15  root     2326:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Pexec(%i, ...)\n", Mode);
                   2327: 
1.1.1.9   root     2328:        /* Re-direct as needed */
                   2329:        switch(Mode)
                   2330:        {
                   2331:         case 0:      /* Load and go */
                   2332:         case 3:      /* Load, don't go */
1.1.1.17! root     2333:                pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
        !          2334:                Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
        !          2335:                
        !          2336:                /* If not using A: or B:, use my own routines to load */
        !          2337:                if (ISHARDDRIVE(Drive))
        !          2338:                {
        !          2339:                        /* Redirect to cart' routine at address 0xFA1000 */
        !          2340:                        return CALL_PEXEC_ROUTINE;
        !          2341:                }
        !          2342:                return false;
1.1.1.9   root     2343:         case 4:      /* Just go */
1.1.1.15  root     2344:                return false;
1.1.1.9   root     2345:         case 5:      /* Create basepage */
1.1.1.15  root     2346:                return false;
1.1.1.9   root     2347:         case 6:
1.1.1.15  root     2348:                return false;
1.1.1.9   root     2349:        }
                   2350: 
1.1.1.10  root     2351:        /* Default: Still re-direct to TOS */
1.1.1.15  root     2352:        return false;
1.1       root     2353: }
                   2354: 
1.1.1.4   root     2355: 
                   2356: /*-----------------------------------------------------------------------*/
1.1.1.12  root     2357: /**
                   2358:  * GEMDOS Search Next
                   2359:  * Call 0x4F
                   2360:  */
1.1.1.13  root     2361: static bool GemDOS_SNext(void)
1.1.1.4   root     2362: {
1.1.1.17! root     2363:        struct dirent **temp;
        !          2364:        Uint32 nDTA;
1.1.1.9   root     2365:        int Index;
1.1.1.13  root     2366:        int ret;
1.1.1.9   root     2367: 
1.1.1.15  root     2368:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fsnext()\n");
                   2369: 
1.1.1.9   root     2370:        /* Refresh pDTA pointer (from the current basepage) */
1.1.1.17! root     2371:        nDTA = STMemory_ReadLong(STMemory_ReadLong(act_pd)+32);
        !          2372: 
        !          2373:        if (!STMemory_ValidArea(nDTA, sizeof(DTA)))
        !          2374:        {
        !          2375:                pDTA = NULL;
        !          2376:                Log_Printf(LOG_WARN, "GEMDOS Fsnext() failed due to invalid DTA address 0x%x\n", nDTA);
        !          2377:                Regs[REG_D0] = GEMDOS_EINTRN;    /* "internal error */
        !          2378:                return true;
        !          2379:        }
        !          2380:        pDTA = (DTA *)STRAM_ADDR(nDTA);
1.1.1.4   root     2381: 
1.1.1.9   root     2382:        /* Was DTA ours or TOS? */
1.1.1.17! root     2383:        if (do_get_mem_long(pDTA->magic) != DTA_MAGIC_NUMBER)
1.1.1.9   root     2384:        {
1.1.1.17! root     2385:                /* redirect to TOS */
        !          2386:                return false;
        !          2387:        }
1.1.1.9   root     2388: 
1.1.1.17! root     2389:        /* Find index into our list of structures */
        !          2390:        Index = do_get_mem_word(pDTA->index) & (MAX_DTAS_FILES-1);
1.1.1.6   root     2391: 
1.1.1.17! root     2392:        if (nAttrSFirst == GEMDOS_FILE_ATTRIB_VOLUME_LABEL)
        !          2393:        {
        !          2394:                /* Volume label was given already in Sfirst() */
        !          2395:                Regs[REG_D0] = GEMDOS_ENMFIL;
        !          2396:                return true;
        !          2397:        }
        !          2398: 
        !          2399:        temp = InternalDTAs[Index].found;
        !          2400:        do
        !          2401:        {
        !          2402:                if (InternalDTAs[Index].centry >= InternalDTAs[Index].nentries)
1.1.1.9   root     2403:                {
                   2404:                        Regs[REG_D0] = GEMDOS_ENMFIL;    /* No more files */
1.1.1.15  root     2405:                        return true;
1.1.1.9   root     2406:                }
                   2407: 
1.1.1.17! root     2408:                ret = PopulateDTA(InternalDTAs[Index].path,
        !          2409:                                  temp[InternalDTAs[Index].centry++]);
        !          2410:        } while (ret == 1);
1.1.1.4   root     2411: 
1.1.1.17! root     2412:        if (ret < 0)
        !          2413:        {
        !          2414:                Log_Printf(LOG_WARN, "GEMDOS Fsnext(): Error setting DTA.\n");
        !          2415:                Regs[REG_D0] = GEMDOS_EINTRN;
1.1.1.15  root     2416:                return true;
1.1.1.9   root     2417:        }
1.1.1.4   root     2418: 
1.1.1.17! root     2419:        Regs[REG_D0] = GEMDOS_EOK;
        !          2420:        return true;
1.1.1.4   root     2421: }
                   2422: 
                   2423: 
1.1.1.2   root     2424: /*-----------------------------------------------------------------------*/
1.1.1.12  root     2425: /**
                   2426:  * GEMDOS Find first file
                   2427:  * Call 0x4E
                   2428:  */
1.1.1.13  root     2429: static bool GemDOS_SFirst(Uint32 Params)
1.1       root     2430: {
1.1.1.17! root     2431:        /* TODO: host filenames might not fit into this */
1.1.1.11  root     2432:        char szActualFileName[MAX_GEMDOS_PATH];
1.1.1.9   root     2433:        char *pszFileName;
1.1.1.17! root     2434:        const char *dirmask;
1.1.1.9   root     2435:        struct dirent **files;
1.1.1.17! root     2436:        Uint32 nDTA;
1.1.1.9   root     2437:        int Drive;
                   2438:        DIR *fsdir;
                   2439:        int i,j,count;
                   2440: 
                   2441:        /* Find filename to search for */
1.1.1.17! root     2442:        pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params));
        !          2443:        nAttrSFirst = STMemory_ReadWord(Params+SIZE_LONG);
1.1.1.9   root     2444: 
1.1.1.15  root     2445:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fsfirst(\"%s\", 0x%x)\n", pszFileName, nAttrSFirst);
                   2446: 
1.1.1.9   root     2447:        Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
1.1.1.17! root     2448:        if (!ISHARDDRIVE(Drive))
1.1.1.9   root     2449:        {
1.1.1.17! root     2450:                /* redirect to TOS */
        !          2451:                return false;
        !          2452:        }
1.1.1.9   root     2453: 
1.1.1.17! root     2454:        /* Convert to hard drive filename */
        !          2455:        GemDOS_CreateHardDriveFileName(Drive, pszFileName,
1.1.1.12  root     2456:                                    szActualFileName, sizeof(szActualFileName));
1.1.1.9   root     2457: 
1.1.1.17! root     2458:        /* Refresh pDTA pointer (from the current basepage) */
        !          2459:        nDTA = STMemory_ReadLong(STMemory_ReadLong(act_pd)+32);
1.1.1.9   root     2460: 
1.1.1.17! root     2461:        if (!STMemory_ValidArea(nDTA, sizeof(DTA)))
        !          2462:        {
        !          2463:                pDTA = NULL;
        !          2464:                Log_Printf(LOG_WARN, "GEMDOS Fsfirst() failed due to invalid DTA address 0x%x\n", nDTA);
        !          2465:                Regs[REG_D0] = GEMDOS_EINTRN;    /* "internal error */
        !          2466:                return true;
        !          2467:        }
        !          2468:        pDTA = (DTA *)STRAM_ADDR(nDTA);
1.1.1.9   root     2469: 
1.1.1.17! root     2470:        /* Populate DTA, set index for our use */
        !          2471:        do_put_mem_word(pDTA->index, DTAIndex);
        !          2472:        /* set our dta magic num */
        !          2473:        do_put_mem_long(pDTA->magic, DTA_MAGIC_NUMBER);
1.1.1.9   root     2474: 
1.1.1.17! root     2475:        if (InternalDTAs[DTAIndex].bUsed == true)
        !          2476:                ClearInternalDTA();
        !          2477:        InternalDTAs[DTAIndex].bUsed = true;
        !          2478: 
        !          2479:        /* Were we looking for the volume label? */
        !          2480:        if (nAttrSFirst == GEMDOS_FILE_ATTRIB_VOLUME_LABEL)
        !          2481:        {
        !          2482:                /* Volume name */
        !          2483:                strcpy(pDTA->dta_name,"EMULATED.001");
        !          2484:                Regs[REG_D0] = GEMDOS_EOK;          /* Got volume */
        !          2485:                return true;
        !          2486:        }
1.1.1.9   root     2487: 
1.1.1.17! root     2488:        /* open directory
        !          2489:         * TODO: host path may not fit into InternalDTA
        !          2490:         */
        !          2491:        fsfirst_dirname(szActualFileName, InternalDTAs[DTAIndex].path);
        !          2492:        fsdir = opendir(InternalDTAs[DTAIndex].path);
        !          2493: 
        !          2494:        if (fsdir == NULL)
        !          2495:        {
        !          2496:                Regs[REG_D0] = GEMDOS_EPTHNF;        /* Path not found */
        !          2497:                return true;
        !          2498:        }
        !          2499:        /* close directory */
        !          2500:        closedir(fsdir);
        !          2501: 
        !          2502:        count = scandir(InternalDTAs[DTAIndex].path, &files, 0, alphasort);
        !          2503:        /* File (directory actually) not found */
        !          2504:        if (count < 0)
        !          2505:        {
        !          2506:                Regs[REG_D0] = GEMDOS_EFILNF;
        !          2507:                return true;
        !          2508:        }
        !          2509: 
        !          2510:        InternalDTAs[DTAIndex].centry = 0;          /* current entry is 0 */
        !          2511:        dirmask = fsfirst_dirmask(szActualFileName);/* directory mask part */
        !          2512:        InternalDTAs[DTAIndex].found = files;       /* get files */
        !          2513: 
        !          2514:        /* count & copy the entries that match our mask and discard the rest */
        !          2515:        j = 0;
        !          2516:        for (i=0; i < count; i++)
        !          2517:        {
        !          2518:                if (fsfirst_match(dirmask, files[i]->d_name))
1.1.1.13  root     2519:                {
1.1.1.17! root     2520:                        InternalDTAs[DTAIndex].found[j] = files[i];
        !          2521:                        j++;
1.1.1.13  root     2522:                }
1.1.1.17! root     2523:                else
1.1.1.9   root     2524:                {
1.1.1.17! root     2525:                        free(files[i]);
        !          2526:                        files[i] = NULL;
1.1.1.9   root     2527:                }
1.1.1.17! root     2528:        }
        !          2529:        InternalDTAs[DTAIndex].nentries = j; /* set number of legal entries */
1.1.1.9   root     2530: 
1.1.1.17! root     2531:        /* No files of that match, return error code */
        !          2532:        if (j==0)
        !          2533:        {
        !          2534:                free(files);
        !          2535:                InternalDTAs[DTAIndex].found = NULL;
        !          2536:                Regs[REG_D0] = GEMDOS_EFILNF;        /* File not found */
1.1.1.15  root     2537:                return true;
1.1.1.9   root     2538:        }
1.1.1.17! root     2539: 
        !          2540:        /* Scan for first file (SNext uses no parameters) */
        !          2541:        GemDOS_SNext();
        !          2542:        /* increment DTA index */
        !          2543:        DTAIndex++;
        !          2544:        DTAIndex&=(MAX_DTAS_FILES-1);
        !          2545:        
        !          2546:        return true;
1.1       root     2547: }
                   2548: 
                   2549: 
1.1.1.2   root     2550: /*-----------------------------------------------------------------------*/
1.1.1.12  root     2551: /**
                   2552:  * GEMDOS Rename
                   2553:  * Call 0x56
                   2554:  */
1.1.1.13  root     2555: static bool GemDOS_Rename(Uint32 Params)
1.1       root     2556: {
1.1.1.9   root     2557:        char *pszNewFileName,*pszOldFileName;
1.1.1.17! root     2558:        /* TODO: host filenames might not fit into this */
        !          2559:        char szNewActualFileName[MAX_GEMDOS_PATH];
        !          2560:        char szOldActualFileName[MAX_GEMDOS_PATH];
1.1.1.9   root     2561:        int NewDrive, OldDrive;
                   2562: 
1.1.1.17! root     2563:        /* Read details from stack, skip first (dummy) arg */
        !          2564:        pszOldFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
        !          2565:        pszNewFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_LONG));
1.1.1.9   root     2566: 
1.1.1.15  root     2567:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Frename(\"%s\", \"%s\")\n", pszOldFileName, pszNewFileName);
                   2568: 
1.1.1.9   root     2569:        NewDrive = GemDOS_IsFileNameAHardDrive(pszNewFileName);
                   2570:        OldDrive = GemDOS_IsFileNameAHardDrive(pszOldFileName);
1.1.1.17! root     2571:        if (!(ISHARDDRIVE(NewDrive) && ISHARDDRIVE(OldDrive)))
1.1.1.9   root     2572:        {
1.1.1.17! root     2573:                /* redirect to TOS */
        !          2574:                return false;
        !          2575:        }
1.1.1.9   root     2576: 
1.1.1.17! root     2577:        /* write protected device? */
        !          2578:        if (ConfigureParams.HardDisk.nWriteProtection == WRITEPROT_ON)
        !          2579:        {
        !          2580:                Log_Printf(LOG_WARN, "PREVENTED: GEMDOS Frename(\"%s\", \"%s\")\n", pszOldFileName, pszNewFileName);
        !          2581:                Regs[REG_D0] = GEMDOS_EWRPRO;
1.1.1.15  root     2582:                return true;
1.1.1.9   root     2583:        }
1.1       root     2584: 
1.1.1.17! root     2585:        /* And convert to hard drive filenames */
        !          2586:        GemDOS_CreateHardDriveFileName(NewDrive, pszNewFileName,
        !          2587:                              szNewActualFileName, sizeof(szNewActualFileName));
        !          2588:        GemDOS_CreateHardDriveFileName(OldDrive, pszOldFileName,
        !          2589:                              szOldActualFileName, sizeof(szOldActualFileName));
        !          2590: 
        !          2591:        /* Rename files */
        !          2592:        if ( rename(szOldActualFileName,szNewActualFileName)==0 )
        !          2593:                Regs[REG_D0] = GEMDOS_EOK;
        !          2594:        else
        !          2595:                Regs[REG_D0] = GEMDOS_EACCDN;        /* Access denied */
        !          2596:        return true;
1.1       root     2597: }
                   2598: 
1.1.1.15  root     2599: 
1.1.1.17! root     2600: #if ENABLE_TRACING
        !          2601: /*-----------------------------------------------------------------------*/
        !          2602: /**
        !          2603:  * Map GEMDOS call opcodes to their names
        !          2604:  */
        !          2605: static const char* GemDOS_Opcode2Name(Uint16 opcode)
        !          2606: {
        !          2607:        static const char* names[] = {
        !          2608:                "Pterm0",
        !          2609:                "Cconin",
        !          2610:                "Cconout",
        !          2611:                "Cauxin",
        !          2612:                "Cauxout",
        !          2613:                "Cprnout",
        !          2614:                "Crawio",
        !          2615:                "Crawcin",
        !          2616:                "Cnecin",
        !          2617:                "Cconws",
        !          2618:                "Cconrs",
        !          2619:                "Cconis",
        !          2620:                "", /* 0C */
        !          2621:                "", /* 0D */
        !          2622:                "Dsetdrv",
        !          2623:                "", /* 0F */
        !          2624:                "Cconos",
        !          2625:                "Cprnos",
        !          2626:                "Cauxis",
        !          2627:                "Cauxos",
        !          2628:                "Maddalt",
        !          2629:                "", /* 15 */
        !          2630:                "", /* 16 */
        !          2631:                "", /* 17 */
        !          2632:                "", /* 18 */
        !          2633:                "Dgetdrv",
        !          2634:                "Fsetdta",
        !          2635:                "", /* 1B */
        !          2636:                "", /* 1C */
        !          2637:                "", /* 1D */
        !          2638:                "", /* 1E */
        !          2639:                "", /* 1F */
        !          2640:                "Super",
        !          2641:                "", /* 21 */
        !          2642:                "", /* 22 */
        !          2643:                "", /* 23 */
        !          2644:                "", /* 24 */
        !          2645:                "", /* 25 */
        !          2646:                "", /* 26 */
        !          2647:                "", /* 27 */
        !          2648:                "", /* 28 */
        !          2649:                "", /* 29 */
        !          2650:                "Tgetdate",
        !          2651:                "Tsetdate",
        !          2652:                "Tgettime",
        !          2653:                "Tsettime",
        !          2654:                "", /* 2E */
        !          2655:                "Fgetdta",
        !          2656:                "Sversion",
        !          2657:                "Ptermres",
        !          2658:                "", /* 32 */
        !          2659:                "", /* 33 */
        !          2660:                "", /* 34 */
        !          2661:                "", /* 35 */
        !          2662:                "Dfree",
        !          2663:                "", /* 37 */
        !          2664:                "", /* 38 */
        !          2665:                "Dcreate",
        !          2666:                "Ddelete",
        !          2667:                "Dsetpath",
        !          2668:                "Fcreate",
        !          2669:                "Fopen",
        !          2670:                "Fclose",
        !          2671:                "Fread",
        !          2672:                "Fwrite",
        !          2673:                "Fdelete",
        !          2674:                "Fseek",
        !          2675:                "Fattrib",
        !          2676:                "Mxalloc",
        !          2677:                "Fdup",
        !          2678:                "Fforce",
        !          2679:                "Dgetpath",
        !          2680:                "Malloc",
        !          2681:                "Mfree",
        !          2682:                "Mshrink",
        !          2683:                "Pexec",
        !          2684:                "Pterm",
        !          2685:                "", /* 4D */
        !          2686:                "Fsfirst",
        !          2687:                "Fsnext",
        !          2688:                "", /* 50 */
        !          2689:                "", /* 51 */
        !          2690:                "", /* 52 */
        !          2691:                "", /* 53 */
        !          2692:                "", /* 54 */
        !          2693:                "", /* 55 */
        !          2694:                "Frename",
        !          2695:                "Fdatime"
        !          2696:        };
        !          2697:        if (opcode < ARRAYSIZE(names))
        !          2698:                return names[opcode];
        !          2699:        return "MiNT call?";
        !          2700: }
        !          2701: #endif
        !          2702: 
1.1.1.2   root     2703: /*-----------------------------------------------------------------------*/
1.1.1.12  root     2704: /**
                   2705:  * GEMDOS GSDToF
                   2706:  * Call 0x57
                   2707:  */
1.1.1.13  root     2708: static bool GemDOS_GSDToF(Uint32 Params)
1.1       root     2709: {
1.1.1.9   root     2710:        DATETIME DateTime;
1.1.1.10  root     2711:        Uint32 pBuffer;
1.1.1.9   root     2712:        int Handle,Flag;
                   2713: 
                   2714:        /* Read details from stack */
1.1.1.17! root     2715:        pBuffer = STMemory_ReadLong(Params);
        !          2716:        Handle = STMemory_ReadWord(Params+SIZE_LONG);
        !          2717:        Flag = STMemory_ReadWord(Params+SIZE_LONG+SIZE_WORD);
1.1.1.9   root     2718: 
1.1.1.15  root     2719:        LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fdatime(0x%x, %i, %i)\n", pBuffer,
                   2720:                  Handle, Flag);
                   2721: 
1.1.1.17! root     2722:        Handle -= BASE_FILEHANDLE;
        !          2723: 
1.1.1.9   root     2724:        /* Check handle was valid */
                   2725:        if (GemDOS_IsInvalidFileHandle(Handle))
                   2726:        {
1.1.1.17! root     2727:                /* No, assume was TOS -> redirect */
1.1.1.15  root     2728:                return false;
1.1.1.9   root     2729:        }
                   2730: 
                   2731:        if (Flag == 1)
                   2732:        {
1.1.1.17! root     2733:                /* write protected device? */
        !          2734:                if (ConfigureParams.HardDisk.nWriteProtection == WRITEPROT_ON)
        !          2735:                {
        !          2736:                        Log_Printf(LOG_WARN, "PREVENTED: GEMDOS Fdatime(,%d,)\n", Handle);
        !          2737:                        Regs[REG_D0] = GEMDOS_EWRPRO;
        !          2738:                        return true;
        !          2739:                }
        !          2740:                DateTime.timeword = STMemory_ReadWord(pBuffer);
        !          2741:                DateTime.dateword = STMemory_ReadWord(pBuffer+SIZE_WORD);
        !          2742:                if (GemDOS_SetFileInformation(Handle, &DateTime) == true)
        !          2743:                        Regs[REG_D0] = GEMDOS_EOK;
        !          2744:                else
        !          2745:                        Regs[REG_D0] = GEMDOS_EACCDN;        /* Access denied */
1.1.1.15  root     2746:                return true;
1.1.1.9   root     2747:        }
                   2748: 
1.1.1.17! root     2749:        if (GemDOS_GetFileInformation(Handle, &DateTime) == true)
1.1.1.9   root     2750:        {
1.1.1.17! root     2751:                STMemory_WriteWord(pBuffer, DateTime.timeword);
        !          2752:                STMemory_WriteWord(pBuffer+SIZE_WORD, DateTime.dateword);
1.1.1.9   root     2753:                Regs[REG_D0] = GEMDOS_EOK;
                   2754:        }
1.1.1.17! root     2755:        else
        !          2756:        {
        !          2757:                Regs[REG_D0] = GEMDOS_ERROR; /* Generic error */
        !          2758:        }
1.1.1.15  root     2759:        return true;
1.1       root     2760: }
                   2761: 
1.1.1.9   root     2762: 
1.1       root     2763: /*-----------------------------------------------------------------------*/
1.1.1.12  root     2764: /**
                   2765:  * Run GEMDos call, and re-direct if need to. Used to handle hard disk emulation etc...
                   2766:  * This sets the condition codes (in SR), which are used in the 'cart_asm.s' program to
                   2767:  * decide if we need to run old GEM vector, or PExec or nothing.
1.1.1.15  root     2768:  *
1.1.1.12  root     2769:  * This method keeps the stack and other states consistant with the original ST which is very important
                   2770:  * for the PExec call and maximum compatibility through-out
                   2771:  */
1.1       root     2772: void GemDOS_OpCode(void)
                   2773: {
1.1.1.17! root     2774:        Uint16 GemDOSCall, CallingSReg;
1.1.1.10  root     2775:        Uint32 Params;
1.1.1.9   root     2776:        short RunOld;
1.1.1.12  root     2777:        Uint16 SR;
1.1.1.9   root     2778: 
1.1.1.12  root     2779:        SR = M68000_GetSR();
1.1.1.9   root     2780: 
                   2781:        /* Read SReg from stack to see if parameters are on User or Super stack  */
                   2782:        CallingSReg = STMemory_ReadWord(Regs[REG_A7]);
                   2783:        if ((CallingSReg&SR_SUPERMODE)==0)      /* Calling from user mode */
                   2784:                Params = regs.usp;
                   2785:        else
                   2786:        {
                   2787:                Params = Regs[REG_A7]+SIZE_WORD+SIZE_LONG;  /* super stack */
1.1.1.12  root     2788:                if (currprefs.cpu_level > 0)
1.1.1.9   root     2789:                        Params += SIZE_WORD;   /* Skip extra word whe CPU is >=68010 */
                   2790:        }
                   2791: 
                   2792:        /* Default to run TOS GemDos (SR_NEG run Gemdos, SR_ZERO already done, SR_OVERFLOW run own 'Pexec' */
1.1.1.15  root     2793:        RunOld = true;
1.1.1.9   root     2794:        SR &= SR_CLEAR_OVERFLOW;
                   2795:        SR &= SR_CLEAR_ZERO;
                   2796:        SR |= SR_NEG;
1.1       root     2797: 
1.1.1.9   root     2798:        /* Find pointer to call parameters */
                   2799:        GemDOSCall = STMemory_ReadWord(Params);
1.1.1.17! root     2800:        Params += SIZE_WORD;
1.1.1.2   root     2801: 
1.1.1.9   root     2802:        /* Intercept call */
                   2803:        switch(GemDOSCall)
                   2804:        {
                   2805:         /*
                   2806:         case 0x3:
                   2807:                if (GemDOS_Cauxin(Params))
1.1.1.15  root     2808:                        RunOld = false;
1.1.1.9   root     2809:                break;
                   2810:         */
                   2811:         /*
                   2812:         case 0x4:
                   2813:                if (GemDOS_Cauxout(Params))
1.1.1.15  root     2814:                        RunOld = false;
1.1.1.9   root     2815:                break;
                   2816:         */
1.1.1.13  root     2817:         /* direct printing via GEMDOS */
                   2818:         /*
                   2819:         case 0x5:
1.1.1.9   root     2820:                if (GemDOS_Cprnout(Params))
1.1.1.15  root     2821:                        RunOld = false;
1.1.1.9   root     2822:                break;
1.1.1.13  root     2823:         */
1.1.1.9   root     2824:         case 0xe:
                   2825:                if (GemDOS_SetDrv(Params))
1.1.1.15  root     2826:                        RunOld = false;
1.1.1.9   root     2827:                break;
1.1.1.13  root     2828:         /* Printer status  */
                   2829:         /*
                   2830:         case 0x11:
1.1.1.9   root     2831:                if (GemDOS_Cprnos(Params))
1.1.1.15  root     2832:                        RunOld = false;
1.1.1.9   root     2833:                break;
1.1.1.13  root     2834:         */
1.1.1.9   root     2835:         /*
                   2836:         case 0x12:
                   2837:                if (GemDOS_Cauxis(Params))
1.1.1.15  root     2838:                        RunOld = false;
1.1.1.9   root     2839:                break;
                   2840:         */
                   2841:         /*
                   2842:         case 0x13:
                   2843:                if (GemDOS_Cauxos(Params))
1.1.1.15  root     2844:                        RunOld = false;
1.1.1.9   root     2845:                break;
                   2846:         */
                   2847:         case 0x1a:
                   2848:                if (GemDOS_SetDTA(Params))
1.1.1.15  root     2849:                        RunOld = false;
1.1.1.9   root     2850:                break;
                   2851:         case 0x36:
                   2852:                if (GemDOS_DFree(Params))
1.1.1.15  root     2853:                        RunOld = false;
1.1.1.9   root     2854:                break;
                   2855:         case 0x39:
                   2856:                if (GemDOS_MkDir(Params))
1.1.1.15  root     2857:                        RunOld = false;
1.1.1.9   root     2858:                break;
                   2859:         case 0x3a:
                   2860:                if (GemDOS_RmDir(Params))
1.1.1.15  root     2861:                        RunOld = false;
1.1.1.9   root     2862:                break;
                   2863:         case 0x3b:
                   2864:                if (GemDOS_ChDir(Params))
1.1.1.15  root     2865:                        RunOld = false;
1.1.1.9   root     2866:                break;
                   2867:         case 0x3c:
                   2868:                if (GemDOS_Create(Params))
1.1.1.15  root     2869:                        RunOld = false;
1.1.1.9   root     2870:                break;
                   2871:         case 0x3d:
                   2872:                if (GemDOS_Open(Params))
1.1.1.15  root     2873:                        RunOld = false;
1.1.1.9   root     2874:                break;
                   2875:         case 0x3e:
                   2876:                if (GemDOS_Close(Params))
1.1.1.15  root     2877:                        RunOld = false;
1.1.1.9   root     2878:                break;
                   2879:         case 0x3f:
                   2880:                if (GemDOS_Read(Params))
1.1.1.15  root     2881:                        RunOld = false;
1.1.1.9   root     2882:                break;
                   2883:         case 0x40:
                   2884:                if (GemDOS_Write(Params))
1.1.1.15  root     2885:                        RunOld = false;
1.1.1.9   root     2886:                break;
                   2887:         case 0x41:
1.1.1.12  root     2888:                if (GemDOS_FDelete(Params))
1.1.1.15  root     2889:                        RunOld = false;
1.1.1.9   root     2890:                break;
                   2891:         case 0x42:
                   2892:                if (GemDOS_LSeek(Params))
1.1.1.15  root     2893:                        RunOld = false;
1.1.1.9   root     2894:                break;
1.1.1.10  root     2895:         case 0x43:
                   2896:                if (GemDOS_Fattrib(Params))
1.1.1.15  root     2897:                        RunOld = false;
1.1.1.10  root     2898:                break;
1.1.1.9   root     2899:         case 0x47:
                   2900:                if (GemDOS_GetDir(Params))
1.1.1.15  root     2901:                        RunOld = false;
1.1.1.9   root     2902:                break;
                   2903:         case 0x4b:
                   2904:                if (GemDOS_Pexec(Params) == CALL_PEXEC_ROUTINE)
                   2905:                        RunOld = CALL_PEXEC_ROUTINE;
                   2906:                break;
                   2907:         case 0x4e:
                   2908:                if (GemDOS_SFirst(Params))
1.1.1.15  root     2909:                        RunOld = false;
1.1.1.9   root     2910:                break;
                   2911:         case 0x4f:
1.1.1.11  root     2912:                if (GemDOS_SNext())
1.1.1.15  root     2913:                        RunOld = false;
1.1.1.9   root     2914:                break;
                   2915:         case 0x56:
                   2916:                if (GemDOS_Rename(Params))
1.1.1.15  root     2917:                        RunOld = false;
1.1.1.9   root     2918:                break;
                   2919:         case 0x57:
                   2920:                if (GemDOS_GSDToF(Params))
1.1.1.15  root     2921:                        RunOld = false;
1.1.1.9   root     2922:                break;
1.1.1.15  root     2923:         default:
1.1.1.17! root     2924:                LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS call 0x%X (%s)\n",
        !          2925:                          GemDOSCall, GemDOS_Opcode2Name(GemDOSCall));
1.1.1.9   root     2926:        }
1.1.1.15  root     2927: 
1.1.1.9   root     2928:        switch(RunOld)
                   2929:        {
1.1.1.15  root     2930:         case false:
1.1.1.13  root     2931:                /* skip over branch to pexec to RTE */
1.1.1.9   root     2932:                SR |= SR_ZERO;
1.1.1.13  root     2933:                /* visualize GemDOS emu HD access? */
                   2934:                switch (GemDOSCall)
                   2935:                {
                   2936:                 case 0x36:
                   2937:                 case 0x39:
                   2938:                 case 0x3a:
                   2939:                 case 0x3b:
                   2940:                 case 0x3c:
                   2941:                 case 0x3d:
                   2942:                 case 0x3e:
                   2943:                 case 0x3f:
                   2944:                 case 0x40:
                   2945:                 case 0x41:
                   2946:                 case 0x42:
                   2947:                 case 0x43:
                   2948:                 case 0x47:
                   2949:                 case 0x4e:
                   2950:                 case 0x4f:
                   2951:                 case 0x56:
                   2952:                        Statusbar_EnableHDLed();
                   2953:                }
1.1.1.9   root     2954:                break;
1.1.1.13  root     2955:         case CALL_PEXEC_ROUTINE:
                   2956:                /* branch to pexec, then redirect to old gemdos. */
1.1.1.9   root     2957:                SR |= SR_OVERFLOW;
                   2958:                break;
                   2959:        }
1.1       root     2960: 
1.1.1.12  root     2961:        M68000_SetSR(SR);   /* update the flags in the SR register */
1.1       root     2962: }
                   2963: 
1.1.1.9   root     2964: 
1.1.1.2   root     2965: /*-----------------------------------------------------------------------*/
1.1.1.12  root     2966: /**
                   2967:  * GemDOS_Boot - routine called on the first occurence of the gemdos opcode.
                   2968:  * (this should be in the cartridge bootrom)
                   2969:  * Sets up our gemdos handler (or, if we don't need one, just turn off keyclicks)
1.1.1.2   root     2970:  */
1.1.1.7   root     2971: void GemDOS_Boot(void)
1.1.1.2   root     2972: {
1.1.1.15  root     2973:        bInitGemDOS = true;
1.1.1.2   root     2974: 
1.1.1.15  root     2975:        LOG_TRACE(TRACE_OS_GEMDOS, "Gemdos_Boot()\n" );
1.1.1.9   root     2976: 
                   2977:        /* install our gemdos handler, if -e or --harddrive option used */
1.1.1.17! root     2978:        if (!GEMDOS_EMU_ON)
        !          2979:                return;
        !          2980: 
        !          2981:        /* Get the address of the p_run variable that points to the actual basepage */
        !          2982:        if (TosVersion == 0x100)
1.1.1.9   root     2983:        {
1.1.1.17! root     2984:                /* We have to use fix addresses on TOS 1.00 :-( */
        !          2985:                if ((STMemory_ReadWord(TosAddress+28)>>1) == 4)
        !          2986:                        act_pd = 0x873c;    /* Spanish TOS is different from others! */
1.1.1.9   root     2987:                else
1.1.1.17! root     2988:                        act_pd = 0x602c;
1.1.1.9   root     2989:        }
1.1.1.17! root     2990:        else
        !          2991:        {
        !          2992:                act_pd = STMemory_ReadLong(TosAddress + 0x28);
        !          2993:        }
        !          2994: 
        !          2995:        /* Save old GEMDOS handler adress */
        !          2996:        STMemory_WriteLong(CART_OLDGEMDOS, STMemory_ReadLong(0x0084));
        !          2997:        /* Setup new GEMDOS handler, see "cart_asm.s" */
        !          2998:        STMemory_WriteLong(0x0084, CART_GEMDOS);
1.1       root     2999: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.