|
|
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.6 root 10: Now case is handled by using glob. See the function
11: GemDOS_CreateHardDriveFileName for that. It also knows about symlinks.
1.1.1.9 root 12: A filename is recognized on its eight first characters, do not try to
1.1.1.6 root 13: push this too far, or you'll get weirdness ! (But I can even run programs
14: directly from a mounted cd in lower cases, so I guess it's working well !).
15:
1.1.1.2 root 16: Bugs/things to fix:
1.1.1.7 root 17: * RS232
1.1.1.2 root 18: * rmdir routine, can't remove dir with files in it. (another tos/unix difference)
19: * Fix bugs, there are probably a few lurking around in here..
20: */
1.1.1.13! root 21: const char Gemdos_rcsid[] = "Hatari $Id: gemdos.c,v 1.80 2008/11/03 20:48:43 thothy Exp $";
1.1.1.12 root 22:
23: #include <config.h>
1.1 root 24:
1.1.1.4 root 25: #include <sys/stat.h>
26: #include <time.h>
27: #include <ctype.h>
28: #include <unistd.h>
1.1.1.12 root 29: #include <errno.h>
30:
31: #if HAVE_GLOB_H
1.1.1.6 root 32: #include <glob.h>
1.1.1.11 root 33: #endif
1.1.1.4 root 34:
1.1 root 35: #include "main.h"
36: #include "cart.h"
1.1.1.2 root 37: #include "tos.h"
1.1.1.6 root 38: #include "configuration.h"
1.1 root 39: #include "file.h"
40: #include "floppy.h"
1.1.1.3 root 41: #include "hdc.h"
1.1 root 42: #include "gemdos.h"
1.1.1.11 root 43: #include "gemdos_defines.h"
44: #include "log.h"
1.1 root 45: #include "m68000.h"
46: #include "memorySnapShot.h"
47: #include "printer.h"
48: #include "rs232.h"
1.1.1.13! root 49: #include "statusbar.h"
1.1.1.11 root 50: #include "scandir.h"
1.1 root 51: #include "stMemory.h"
1.1.1.13! root 52: #include "str.h"
1.1.1.12 root 53: #include "hatari-glue.h"
54: #include "maccess.h"
1.1.1.7 root 55:
1.1 root 56: #define ENABLE_SAVING /* Turn on saving stuff */
57:
58: #define INVALID_HANDLE_VALUE -1
59:
1.1.1.6 root 60: /* GLOB_ONLYDIR is a GNU extension for the glob() function and not defined
61: * on some systems. We should probably use something different for this
62: * case, but at the moment it we simply define it as 0... */
63: #ifndef GLOB_ONLYDIR
64: #warning GLOB_ONLYDIR was not defined.
65: #define GLOB_ONLYDIR 0
66: #endif
67:
1.1.1.11 root 68: /* Maximum supported length of a GEMDOS path: */
69: #define MAX_GEMDOS_PATH 256
1.1.1.3 root 70:
1.1.1.11 root 71:
72: /* Have we re-directed GemDOS vector to our own routines yet? */
1.1.1.13! root 73: bool bInitGemDOS;
1.1.1.11 root 74:
75: /* structure with all the drive-specific data for our emulated drives,
76: * used by GEMDOS_EMU_ON macro
77: */
1.1.1.2 root 78: EMULATEDDRIVE **emudrives = NULL;
79:
1.1.1.11 root 80: #define ISHARDDRIVE(Drive) (Drive!=-1)
81:
82: /*
83: Disk Tranfer Address (DTA)
84: */
85: #define TOS_NAMELEN 14
86:
87: typedef struct {
88: Uint8 index[2];
89: Uint8 magic[4];
90: char dta_pat[TOS_NAMELEN];
91: char dta_sattrib;
92: char dta_attrib;
93: Uint8 dta_time[2];
94: Uint8 dta_date[2];
95: Uint8 dta_size[4];
96: char dta_name[TOS_NAMELEN];
97: } DTA;
98:
99: #define DTA_MAGIC_NUMBER 0x12983476
100: #define MAX_DTAS_FILES 256 /* Must be ^2 */
101: #define CALL_PEXEC_ROUTINE 3 /* Call our cartridge pexec routine */
102:
103: #define BASE_FILEHANDLE 64 /* Our emulation handles - MUST not be valid TOS ones, but MUST be <256 */
104: #define MAX_FILE_HANDLES 32 /* We can allow 32 files open at once */
105:
106: /*
107: DateTime structure used by TOS call $57 f_dattime
108: Changed to fix potential problem with alignment.
109: */
110: typedef struct {
111: Uint16 word1;
112: Uint16 word2;
113: } DATETIME;
114:
1.1.1.6 root 115: typedef struct
1.1 root 116: {
1.1.1.13! root 117: bool bUsed;
1.1.1.9 root 118: FILE *FileHandle;
1.1.1.11 root 119: char szActualName[MAX_GEMDOS_PATH]; /* used by F_DATIME (0x57) */
1.1 root 120: } FILE_HANDLE;
121:
1.1.1.6 root 122: typedef struct
1.1.1.2 root 123: {
1.1.1.13! root 124: bool bUsed;
1.1.1.9 root 125: int nentries; /* number of entries in fs directory */
126: int centry; /* current entry # */
127: struct dirent **found; /* legal files */
1.1.1.11 root 128: char path[MAX_GEMDOS_PATH]; /* sfirst path */
1.1.1.2 root 129: } INTERNAL_DTA;
130:
1.1.1.11 root 131: static FILE_HANDLE FileHandles[MAX_FILE_HANDLES];
132: static INTERNAL_DTA InternalDTAs[MAX_DTAS_FILES];
133: static int DTAIndex; /* Circular index into above */
134: static DTA *pDTA; /* Our GEMDOS hard drive Disk Transfer Address structure */
135: static Uint16 CurrentDrive; /* Current drive (0=A,1=B,2=C etc...) */
136: static Uint32 act_pd; /* Used to get a pointer to the current basepage */
1.1.1.13! root 137: static Uint16 nAttrSFirst; /* File attribute for SFirst/Snext */
1.1.1.6 root 138:
1.1 root 139:
1.1.1.13! root 140: #ifdef HATARI_TRACE_ACTIVATED
1.1 root 141: /* List of GEMDos functions... */
1.1.1.9 root 142: static const char *pszGemDOSNames[] =
143: {
144: "Term", /*0x00*/
145: "Conin", /*0x01*/
146: "ConOut", /*0x02*/
147: "Auxiliary Input", /*0x03*/
148: "Auxiliary Output", /*0x04*/
149: "Printer Output", /*0x05*/
150: "RawConIO", /*0x06*/
151: "Direct Conin no echo", /*0x07*/
152: "Conin no echo", /*0x08*/
153: "Print line", /*0x09*/
154: "ReadLine", /*0x0a*/
155: "ConStat", /*0x0b*/
156: "", /*0x0c*/
157: "", /*0x0d*/
158: "SetDrv", /*0x0e*/
159: "", /*0x0f*/
160: "Conout Stat", /*0x10*/
161: "PrtOut Stat", /*0x11*/
162: "Auxin Stat", /*0x12*/
163: "AuxOut Stat", /*0x13*/
164: "", /*0x14*/
165: "", /*0x15*/
166: "", /*0x16*/
167: "", /*0x17*/
168: "", /*0x18*/
169: "Current Disk", /*0x19*/
170: "Set DTA", /*0x1a*/
171: "", /*0x1b*/
172: "", /*0x1c*/
173: "", /*0x1d*/
174: "", /*0x1e*/
175: "", /*0x1f*/
176: "Super", /*0x20*/
177: "", /*0x21*/
178: "", /*0x22*/
179: "", /*0x23*/
180: "", /*0x24*/
181: "", /*0x25*/
182: "", /*0x26*/
183: "", /*0x27*/
184: "", /*0x28*/
185: "", /*0x29*/
186: "Get Date", /*0x2a*/
187: "Set Date", /*0x2b*/
188: "Get Time", /*0x2c*/
189: "Set Time", /*0x2d*/
190: "", /*0x2e*/
191: "Get DTA", /*0x2f*/
192: "Get Version Number", /*0x30*/
193: "Keep Process", /*0x31*/
194: "", /*0x32*/
195: "", /*0x33*/
196: "", /*0x34*/
197: "", /*0x35*/
198: "Get Disk Free Space", /*0x36*/
199: "", /*0x37*/
200: "", /*0x38*/
201: "MkDir", /*0x39*/
202: "RmDir", /*0x3a*/
203: "ChDir", /*0x3b*/
204: "Create", /*0x3c*/
205: "Open", /*0x3d*/
206: "Close", /*0x3e*/
207: "Read", /*0x3f*/
208: "Write", /*0x40*/
1.1.1.12 root 209: "Fdelete", /*0x41*/
1.1.1.9 root 210: "LSeek", /*0x42*/
1.1.1.10 root 211: "Fattrib", /*0x43*/
1.1.1.9 root 212: "", /*0x44*/
213: "Dup", /*0x45*/
214: "Force", /*0x46*/
215: "GetDir", /*0x47*/
216: "Malloc", /*0x48*/
217: "MFree", /*0x49*/
218: "SetBlock", /*0x4a*/
219: "Exec", /*0x4b*/
220: "Term", /*0x4c*/
221: "", /*0x4d*/
222: "SFirst", /*0x4e*/
223: "SNext", /*0x4f*/
224: "", /*0x50*/
225: "", /*0x51*/
226: "", /*0x52*/
227: "", /*0x53*/
228: "", /*0x54*/
229: "", /*0x55*/
230: "Rename", /*0x56*/
231: "GSDTof" /*0x57*/
1.1 root 232: };
1.1.1.9 root 233: #endif
1.1.1.2 root 234:
1.1.1.3 root 235:
236:
1.1.1.12 root 237: /* Poor Windows (and maybe other systems) do not have a glob() function... */
238: #if !HAVE_GLOB_H
239: #warning sorry, no glob function available
1.1.1.11 root 240:
241: typedef struct
242: {
243: size_t gl_pathc; /* Count of paths matched so far */
244: char **gl_pathv; /* List of matched pathnames. */
245: size_t gl_offs; /* Slots to reserve in `gl_pathv'. */
246: } glob_t;
247:
1.1.1.12 root 248: static int glob(const char *pattern, int flags,
249: int errfunc(const char *epath, int eerrno),
250: glob_t *pglob)
251: {
252: /* Just a quick hack to keep Hatari happy... */
253: pglob->gl_pathv = malloc(1 * sizeof(void *));
254: pglob->gl_pathv[0] = NULL;
255: pglob->gl_pathc = 0;
1.1.1.11 root 256: return 0;
257: }
258:
1.1.1.12 root 259: static void globfree(glob_t *pglob)
1.1.1.11 root 260: {
1.1.1.12 root 261: free(pglob->gl_pathv);
1.1.1.11 root 262: }
263:
1.1.1.12 root 264: #endif /* HAVE_GLOB_H */
265:
1.1.1.11 root 266:
1.1.1.12 root 267: #ifdef WIN32
268: #define mkdir(name,mode) mkdir(name)
1.1.1.11 root 269: #endif /* WIN32 */
270:
1.1.1.12 root 271: #ifndef S_IRGRP
272: #define S_IRGRP 0
273: #define S_IROTH 0
274: #endif
275:
1.1.1.11 root 276:
1.1.1.3 root 277:
1.1.1.2 root 278: /*-------------------------------------------------------*/
1.1.1.12 root 279: /**
280: * Routines to convert time and date to MSDOS format.
281: * Originally from the STonX emulator. (cheers!)
282: */
1.1.1.9 root 283: static Uint16 GemDOS_Time2dos(time_t t)
1.1.1.2 root 284: {
285: struct tm *x;
1.1.1.12 root 286:
287: x = localtime(&t);
288:
289: if (x == NULL)
290: return 0;
291:
1.1.1.2 root 292: return (x->tm_sec>>1)|(x->tm_min<<5)|(x->tm_hour<<11);
293: }
1.1 root 294:
1.1.1.9 root 295: static Uint16 GemDOS_Date2dos(time_t t)
1.1.1.2 root 296: {
297: struct tm *x;
1.1.1.12 root 298:
299: x = localtime(&t);
300:
301: if (x == NULL)
302: return 0;
303:
304: return x->tm_mday | ((x->tm_mon+1)<<5)
305: | (((x->tm_year-80 > 0) ? x->tm_year-80 : 0) << 9);
1.1.1.2 root 306: }
1.1 root 307:
1.1.1.3 root 308:
1.1.1.2 root 309: /*-----------------------------------------------------------------------*/
1.1.1.12 root 310: /**
311: * Populate a DATETIME structure with file info
312: */
1.1.1.13! root 313: static bool GemDOS_GetFileInformation(char *name, DATETIME *DateTime)
1.1.1.2 root 314: {
1.1.1.9 root 315: struct stat filestat;
316: int n;
317: struct tm *x;
318:
319: n = stat(name, &filestat);
320: if (n != 0)
321: return FALSE;
1.1.1.12 root 322:
323: x = localtime(&filestat.st_mtime);
324: if (x == NULL)
325: return FALSE;
1.1.1.9 root 326:
327: DateTime->word1 = 0;
328: DateTime->word2 = 0;
329:
330: DateTime->word1 |= (x->tm_mday & 0x1F); /* 5 bits */
331: DateTime->word1 |= (x->tm_mon & 0x0F)<<5; /* 4 bits */
332: DateTime->word1 |= (((x->tm_year-80>0)?x->tm_year-80:0) & 0x7F)<<9; /* 7 bits*/
333:
334: DateTime->word2 |= (x->tm_sec & 0x1F); /* 5 bits */
335: DateTime->word2 |= (x->tm_min & 0x3F)<<5; /* 6 bits */
336: DateTime->word2 |= (x->tm_hour & 0x1F)<<11; /* 5 bits */
1.1.1.2 root 337:
1.1.1.9 root 338: return TRUE;
339: }
1.1.1.2 root 340:
341:
1.1.1.9 root 342: /*-----------------------------------------------------------------------*/
1.1.1.12 root 343: /**
344: * Covert from FindFirstFile/FindNextFile attribute to GemDOS format
345: */
1.1.1.9 root 346: static unsigned char GemDOS_ConvertAttribute(mode_t mode)
347: {
348: unsigned char Attrib = 0;
349:
350: /* Directory attribute */
351: if (S_ISDIR(mode))
352: Attrib |= GEMDOS_FILE_ATTRIB_SUBDIRECTORY;
1.1.1.2 root 353:
1.1.1.9 root 354: /* Read-only attribute */
355: if (!(mode & S_IWUSR))
356: Attrib |= GEMDOS_FILE_ATTRIB_READONLY;
357:
358: /* TODO: Other attributes like GEMDOS_FILE_ATTRIB_HIDDEN ? */
1.1.1.2 root 359:
1.1.1.9 root 360: return Attrib;
1.1.1.2 root 361: }
1.1.1.3 root 362:
363:
1.1.1.2 root 364: /*-----------------------------------------------------------------------*/
1.1.1.12 root 365: /**
1.1.1.13! root 366: * Populate the DTA buffer with file info.
! 367: * @return 0 if entry is ok, 1 if entry should be skipped, < 0 for errors.
1.1.1.12 root 368: */
1.1.1.13! root 369: static int PopulateDTA(char *path, struct dirent *file)
1.1.1.2 root 370: {
1.1.1.11 root 371: char tempstr[MAX_GEMDOS_PATH];
1.1.1.9 root 372: struct stat filestat;
373: int n;
1.1.1.13! root 374: int nFileAttr;
1.1.1.9 root 375:
1.1.1.12 root 376: snprintf(tempstr, sizeof(tempstr), "%s%c%s", path, PATHSEP, file->d_name);
1.1.1.9 root 377: n = stat(tempstr, &filestat);
378: if (n != 0)
1.1.1.12 root 379: {
380: perror(tempstr);
1.1.1.13! root 381: return -1; /* return on error */
1.1.1.12 root 382: }
1.1.1.9 root 383:
384: if (!pDTA)
1.1.1.13! root 385: return -2; /* no DTA pointer set */
! 386:
! 387: /* Check file attributes (check is done according to the Profibuch */
! 388: nFileAttr = GemDOS_ConvertAttribute(filestat.st_mode);
! 389: if (nFileAttr != 0 && !((nAttrSFirst|0x21) & nFileAttr))
! 390: return 1;
! 391:
! 392: Str_ToUpper(file->d_name); /* convert to atari-style uppercase */
1.1.1.9 root 393: strncpy(pDTA->dta_name,file->d_name,TOS_NAMELEN); /* FIXME: better handling of long file names */
394: do_put_mem_long(pDTA->dta_size, filestat.st_size);
395: do_put_mem_word(pDTA->dta_time, GemDOS_Time2dos(filestat.st_mtime));
396: do_put_mem_word(pDTA->dta_date, GemDOS_Date2dos(filestat.st_mtime));
1.1.1.13! root 397: pDTA->dta_attrib = nFileAttr;
1.1.1.2 root 398:
1.1.1.13! root 399: return 0;
1.1.1.2 root 400: }
401:
1.1.1.3 root 402:
1.1.1.2 root 403: /*-----------------------------------------------------------------------*/
1.1.1.12 root 404: /**
405: * Clear a used DTA structure.
406: */
1.1.1.7 root 407: static void ClearInternalDTA(void)
408: {
1.1.1.9 root 409: int i;
1.1.1.2 root 410:
1.1.1.9 root 411: /* clear the old DTA structure */
412: if (InternalDTAs[DTAIndex].found != NULL)
413: {
414: for (i=0; i < InternalDTAs[DTAIndex].nentries; i++)
415: free(InternalDTAs[DTAIndex].found[i]);
416: free(InternalDTAs[DTAIndex].found);
417: InternalDTAs[DTAIndex].found = NULL;
418: }
419: InternalDTAs[DTAIndex].nentries = 0;
420: InternalDTAs[DTAIndex].bUsed = FALSE;
1.1.1.2 root 421: }
422:
1.1.1.3 root 423:
1.1.1.2 root 424: /*-----------------------------------------------------------------------*/
1.1.1.12 root 425: /**
426: * Match a file to a dir mask.
427: */
1.1.1.2 root 428: static int match (char *pat, char *name)
429: {
1.1.1.9 root 430: char *p=pat, *n=name;
431:
432: if (name[0] == '.')
433: return FALSE; /* no .* files */
434: if (strcmp(pat,"*.*")==0)
435: return TRUE;
436: if (strcasecmp(pat,name)==0)
437: return TRUE;
438:
439: for (;*n;)
1.1.1.2 root 440: {
1.1.1.9 root 441: if (*p=='*')
442: {
443: while (*n && *n != '.')
444: n++;
445: p++;
446: }
447: else
448: {
449: if (*p=='?' && *n)
450: {
451: n++;
452: p++;
453: }
454: else
455: {
456: if (toupper(*p++) != toupper(*n++))
457: return FALSE;
458: }
459: }
1.1.1.2 root 460: }
1.1.1.9 root 461:
462: return (*p == 0); /* The name matches the pattern if it ends here, too */
1.1.1.2 root 463: }
464:
1.1.1.9 root 465:
1.1.1.2 root 466: /*-----------------------------------------------------------------------*/
1.1.1.12 root 467: /**
468: * Parse directory from sfirst mask
469: * - e.g.: input: "hdemudir/auto/mask*.*" outputs: "hdemudir/auto"
470: */
1.1.1.7 root 471: static void fsfirst_dirname(char *string, char *new)
472: {
1.1.1.9 root 473: int i=0;
1.1.1.6 root 474:
1.1.1.11 root 475: strcpy(new, string);
476:
1.1.1.9 root 477: /* convert to front slashes. */
478: i=0;
479: while (new[i] != '\0')
480: {
481: if (new[i] == '\\')
1.1.1.12 root 482: new[i] = PATHSEP;
1.1.1.9 root 483: i++;
484: }
485: while (string[i] != '\0')
486: {
487: new[i] = string[i];
488: i++;
489: } /* find end of string */
1.1.1.12 root 490: while (new[i] != PATHSEP)
1.1.1.9 root 491: i--; /* find last slash */
492: new[i] = '\0';
1.1 root 493: }
494:
1.1.1.11 root 495:
1.1.1.2 root 496: /*-----------------------------------------------------------------------*/
1.1.1.12 root 497: /**
498: * Parse directory mask, e.g. "*.*"
499: */
1.1.1.7 root 500: static void fsfirst_dirmask(char *string, char *new)
501: {
1.1.1.9 root 502: int i=0, j=0;
503:
504: while (string[i] != '\0')
505: i++; /* go to end of string */
1.1.1.12 root 506: while (string[i] != PATHSEP)
1.1.1.9 root 507: i--; /* find last slash */
508: i++;
509: while (string[i] != '\0')
510: new[j++] = string[i++]; /* go to end of string */
511: new[j++] = '\0';
1.1.1.2 root 512: }
1.1 root 513:
1.1.1.7 root 514:
1.1.1.2 root 515: /*-----------------------------------------------------------------------*/
1.1.1.12 root 516: /**
517: * Initialize GemDOS/PC file system
518: */
1.1 root 519: void GemDOS_Init(void)
520: {
1.1.1.9 root 521: int i;
522: bInitGemDOS = FALSE;
1.1.1.2 root 523:
1.1.1.9 root 524: /* Clear handles structure */
525: memset(FileHandles, 0, sizeof(FILE_HANDLE)*MAX_FILE_HANDLES);
526: /* Clear DTAs */
527: for(i=0; i<MAX_DTAS_FILES; i++)
528: {
529: InternalDTAs[i].bUsed = FALSE;
530: InternalDTAs[i].nentries = 0;
531: InternalDTAs[i].found = NULL;
532: }
533: DTAIndex = 0;
1.1 root 534: }
535:
1.1.1.9 root 536:
1.1.1.2 root 537: /*-----------------------------------------------------------------------*/
1.1.1.12 root 538: /**
539: * Reset GemDOS file system
540: */
1.1.1.7 root 541: void GemDOS_Reset(void)
1.1 root 542: {
1.1.1.9 root 543: int i;
544:
545: /* Init file handles table */
546: for (i=0; i<MAX_FILE_HANDLES; i++)
547: {
548: /* Was file open? If so close it */
549: if (FileHandles[i].bUsed)
550: fclose(FileHandles[i].FileHandle);
1.1 root 551:
1.1.1.9 root 552: FileHandles[i].FileHandle = NULL;
553: FileHandles[i].bUsed = FALSE;
554: }
555:
556: for (DTAIndex = 0; DTAIndex < MAX_DTAS_FILES; DTAIndex++)
557: {
558: ClearInternalDTA();
559: }
560: DTAIndex = 0;
561:
562: /* Reset */
563: bInitGemDOS = FALSE;
564: CurrentDrive = nBootDrive;
565: pDTA = NULL;
1.1 root 566: }
567:
1.1.1.3 root 568:
569: /*-----------------------------------------------------------------------*/
1.1.1.12 root 570: /**
571: * Initialize a GEMDOS drive.
572: * Only 1 emulated drive allowed, as of yet.
573: */
1.1.1.7 root 574: void GemDOS_InitDrives(void)
1.1.1.3 root 575: {
1.1.1.9 root 576: int i;
577:
578: /* intialize data for harddrive emulation: */
579: if (!GEMDOS_EMU_ON)
580: {
581: emudrives = malloc( MAX_HARDDRIVES*sizeof(EMULATEDDRIVE *) );
582: for(i=0; i<MAX_HARDDRIVES; i++)
1.1.1.11 root 583: emudrives[i] = malloc( sizeof(EMULATEDDRIVE) );
1.1.1.9 root 584: }
1.1.1.3 root 585:
1.1.1.9 root 586: for(i=0; i<MAX_HARDDRIVES; i++)
587: {
588: /* set emulation directory string */
1.1.1.10 root 589: strcpy(emudrives[i]->hd_emulation_dir, ConfigureParams.HardDisk.szHardDiskDirectories[i]);
1.1.1.6 root 590:
1.1.1.9 root 591: /* remove trailing slash, if any in the directory name */
592: File_CleanFileName(emudrives[i]->hd_emulation_dir);
593:
594: /* initialize current directory string, too (initially the same as hd_emulation_dir) */
595: strcpy(emudrives[i]->fs_currpath, emudrives[i]->hd_emulation_dir);
596: strcat(emudrives[i]->fs_currpath, "/"); /* Needs trailing slash! */
597:
598: /* set drive to 2 + number of ACSI partitions */
599: emudrives[i]->hd_letter = 2 + nPartitions + i;
600:
1.1.1.10 root 601: nNumDrives += 1;
1.1.1.9 root 602:
603: fprintf(stderr, "Hard drive emulation, %c: <-> %s\n",
604: emudrives[i]->hd_letter + 'A', emudrives[i]->hd_emulation_dir);
605: }
1.1.1.3 root 606: }
607:
1.1.1.6 root 608:
1.1.1.3 root 609: /*-----------------------------------------------------------------------*/
1.1.1.12 root 610: /**
611: * Un-init the GEMDOS drive
612: */
1.1.1.7 root 613: void GemDOS_UnInitDrives(void)
1.1.1.3 root 614: {
1.1.1.9 root 615: int i;
1.1.1.3 root 616:
1.1.1.9 root 617: GemDOS_Reset(); /* Close all open files on emulated drive*/
1.1.1.3 root 618:
1.1.1.9 root 619: if (GEMDOS_EMU_ON)
620: {
621: for(i=0; i<MAX_HARDDRIVES; i++)
622: {
623: free(emudrives[i]); /* Release memory */
1.1.1.10 root 624: nNumDrives -= 1;
1.1.1.9 root 625: }
626:
627: free(emudrives);
628: emudrives = NULL;
629: }
1.1.1.3 root 630: }
631:
632:
1.1.1.2 root 633: /*-----------------------------------------------------------------------*/
1.1.1.12 root 634: /**
635: * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
636: */
1.1.1.13! root 637: void GemDOS_MemorySnapShot_Capture(bool bSave)
1.1 root 638: {
1.1.1.9 root 639: unsigned int Addr;
640: int i;
1.1.1.13! root 641: bool bEmudrivesAvailable;
! 642:
! 643: /* Save/Restore the emudrives structure */
! 644: bEmudrivesAvailable = (emudrives != NULL);
! 645: MemorySnapShot_Store(&bEmudrivesAvailable, sizeof(bEmudrivesAvailable));
! 646: if (bEmudrivesAvailable)
! 647: {
! 648: if (!bSave && !emudrives)
! 649: {
! 650: /* We're loading a memory snapshot, but the emudrives
! 651: * structure has not been malloc yet... let's do it now! */
! 652: GemDOS_InitDrives();
! 653: }
! 654:
! 655: for(i=0; i<MAX_HARDDRIVES; i++)
! 656: {
! 657: MemorySnapShot_Store(emudrives[i]->hd_emulation_dir,
! 658: sizeof(emudrives[i]->hd_emulation_dir));
! 659: MemorySnapShot_Store(emudrives[i]->fs_currpath,
! 660: sizeof(emudrives[i]->fs_currpath));
! 661: MemorySnapShot_Store(&emudrives[i]->hd_letter,
! 662: sizeof(emudrives[i]->hd_letter));
! 663: }
! 664: }
1.1 root 665:
1.1.1.9 root 666: /* Save/Restore details */
667: MemorySnapShot_Store(&DTAIndex,sizeof(DTAIndex));
668: MemorySnapShot_Store(&bInitGemDOS,sizeof(bInitGemDOS));
1.1.1.13! root 669: MemorySnapShot_Store(&act_pd, sizeof(act_pd));
1.1.1.9 root 670: if (bSave)
671: {
1.1.1.11 root 672: Addr = ((Uint8 *)pDTA - STRam);
1.1.1.9 root 673: MemorySnapShot_Store(&Addr,sizeof(Addr));
674: }
675: else
676: {
677: MemorySnapShot_Store(&Addr,sizeof(Addr));
678: pDTA = (DTA *)(STRam + Addr);
679: }
680: MemorySnapShot_Store(&CurrentDrive,sizeof(CurrentDrive));
681: /* Don't save file handles as files may have changed which makes
682: it impossible to get a valid handle back */
683: if (!bSave)
684: {
685: /* Clear file handles */
686: for(i=0; i<MAX_FILE_HANDLES; i++)
687: {
688: FileHandles[i].FileHandle = NULL;
689: FileHandles[i].bUsed = FALSE;
690: }
691: }
1.1 root 692: }
693:
1.1.1.9 root 694:
1.1.1.2 root 695: /*-----------------------------------------------------------------------*/
1.1.1.12 root 696: /**
697: * Return free PC file handle table index, or -1 if error
698: */
1.1.1.7 root 699: static int GemDOS_FindFreeFileHandle(void)
1.1 root 700: {
1.1.1.9 root 701: int i;
1.1 root 702:
1.1.1.9 root 703: /* Scan our file list for free slot */
704: for(i=0; i<MAX_FILE_HANDLES; i++)
705: {
706: if (!FileHandles[i].bUsed)
707: return i;
708: }
1.1 root 709:
1.1.1.9 root 710: /* Cannot open any more files, return error */
711: return -1;
1.1 root 712: }
713:
1.1.1.2 root 714: /*-----------------------------------------------------------------------*/
1.1.1.12 root 715: /**
716: * Check ST handle is within our table range, return TRUE if not
717: */
1.1.1.13! root 718: static bool GemDOS_IsInvalidFileHandle(int Handle)
1.1 root 719: {
1.1.1.13! root 720: bool bInvalidHandle=FALSE;
1.1 root 721:
1.1.1.9 root 722: /* Check handle was valid with our handle table */
723: if ((Handle < 0) || (Handle >= MAX_FILE_HANDLES))
724: bInvalidHandle = TRUE;
725: else if (!FileHandles[Handle].bUsed)
726: bInvalidHandle = TRUE;
1.1 root 727:
1.1.1.9 root 728: return bInvalidHandle;
1.1 root 729: }
730:
1.1.1.2 root 731: /*-----------------------------------------------------------------------*/
1.1.1.12 root 732: /**
733: * Find drive letter from a filename, eg C,D... and return as drive ID(C:2, D:3...)
734: * returns the current drive number if none is specified.
735: */
1.1.1.7 root 736: static int GemDOS_FindDriveNumber(char *pszFileName)
1.1 root 737: {
1.1.1.9 root 738: /* Does have 'A:' or 'C:' etc.. at start of string? */
739: if ((pszFileName[0] != '\0') && (pszFileName[1] == ':'))
740: {
741: if ((pszFileName[0] >= 'a') && (pszFileName[0] <= 'z'))
742: return (pszFileName[0]-'a');
743: else if ((pszFileName[0] >= 'A') && (pszFileName[0] <= 'Z'))
744: return (pszFileName[0]-'A');
745: }
1.1 root 746:
1.1.1.9 root 747: return CurrentDrive;
1.1 root 748: }
749:
1.1.1.2 root 750: /*-----------------------------------------------------------------------*/
1.1.1.12 root 751: /**
752: * Return drive ID(C:2, D:3 etc...) or -1 if not one of our emulation hard-drives
753: */
1.1.1.7 root 754: static int GemDOS_IsFileNameAHardDrive(char *pszFileName)
1.1 root 755: {
1.1.1.9 root 756: int DriveLetter;
1.1.1.11 root 757: int n;
1.1.1.9 root 758:
759: /* Do we even have a hard-drive? */
760: if (GEMDOS_EMU_ON)
761: {
1.1.1.10 root 762: /* Find drive letter (as number) */
1.1.1.9 root 763: DriveLetter = GemDOS_FindDriveNumber(pszFileName);
764: /* add support for multiple drives here.. */
1.1.1.11 root 765: for (n=0; n<MAX_HARDDRIVES; n++) {
766: if (DriveLetter == emudrives[n]->hd_letter)
1.1.1.9 root 767: return DriveLetter;
768: }
1.1.1.11 root 769: }
1.1.1.10 root 770: /* Not a high-level redirected drive, let TOS handle it */
1.1.1.9 root 771: return -1;
1.1 root 772: }
773:
1.1.1.7 root 774:
775: /*-----------------------------------------------------------------------*/
1.1.1.12 root 776: /**
777: * Returns the length of the basename of the file passed in parameter
778: * (ie the file without extension)
779: */
1.1.1.7 root 780: static int baselen(char *s)
781: {
1.1.1.9 root 782: char *ext = strchr(s,'.');
783: if (ext)
784: return ext-s;
785: return strlen(s);
1.1.1.6 root 786: }
787:
1.1.1.2 root 788: /*-----------------------------------------------------------------------*/
1.1.1.12 root 789: /**
790: * Use hard-drive directory, current ST directory and filename to create full path
791: */
792: void GemDOS_CreateHardDriveFileName(int Drive, const char *pszFileName,
793: char *pszDestName, int nDestNameLen)
1.1 root 794: {
1.1.1.9 root 795: char *s,*start;
1.1.1.2 root 796:
1.1.1.11 root 797: /* Check for valid string */
1.1.1.9 root 798: if (pszFileName[0] == '\0')
1.1.1.11 root 799: return;
800:
801: /* Is it a valid hard drive? */
802: if (Drive < 2)
803: return;
1.1.1.3 root 804:
1.1.1.9 root 805: /* case full filename "C:\foo\bar" */
1.1.1.12 root 806: s = pszDestName;
807: start = NULL;
1.1.1.9 root 808:
809: if (pszFileName[1] == ':')
810: {
1.1.1.12 root 811: snprintf(pszDestName, nDestNameLen, "%s%s",
812: emudrives[0]->hd_emulation_dir, File_RemoveFileNameDrive(pszFileName));
1.1.1.9 root 813: }
814: /* case referenced from root: "\foo\bar" */
815: else if (pszFileName[0] == '\\')
816: {
1.1.1.12 root 817: snprintf(pszDestName, nDestNameLen, "%s%s",
818: emudrives[0]->hd_emulation_dir, pszFileName);
1.1.1.9 root 819: }
820: /* case referenced from current directory */
821: else
822: {
1.1.1.12 root 823: snprintf(pszDestName, nDestNameLen, "%s%s",
824: emudrives[0]->fs_currpath, pszFileName);
1.1.1.9 root 825: start = pszDestName + strlen(emudrives[0]->fs_currpath)-1;
1.1.1.6 root 826: }
1.1.1.9 root 827:
828: /* convert to front slashes. */
829: while((s = strchr(s+1,'\\')))
830: {
831: if (!start)
832: {
833: start = s;
834: continue;
835: }
836: {
837: glob_t globbuf;
1.1.1.12 root 838: char old1, old2;
1.1.1.9 root 839: int len, found, base_len;
840: unsigned int j;
841:
1.1.1.12 root 842: *start++ = PATHSEP;
1.1.1.9 root 843: old1 = *start;
844: *start++ = '*';
845: old2 = *start;
846: *start = 0;
847: glob(pszDestName,GLOB_ONLYDIR,NULL,&globbuf);
848: *start-- = old2;
849: *start = old1;
850: *s = 0;
851: len = strlen(pszDestName);
852: base_len = baselen(start);
853: found = 0;
854: for (j=0; j<globbuf.gl_pathc; j++)
855: {
856: /* If we search for a file of at least 8 characters, then it might
857: be a longer filename since the ST can access only the first 8
858: characters. If not, then it's a precise match (with case). */
859: if (!(base_len < 8 ? strcasecmp(globbuf.gl_pathv[j],pszDestName) :
860: strncasecmp(globbuf.gl_pathv[j],pszDestName,len)))
861: {
862: /* we found a matching name... */
1.1.1.12 root 863: snprintf(pszDestName, nDestNameLen, "%s%c%s",
864: globbuf.gl_pathv[j], PATHSEP, s+1);
1.1.1.9 root 865: j = globbuf.gl_pathc;
866: found = 1;
867: }
1.1.1.13! root 868: /* Here comes a work-around for a bug in the file selector
! 869: * of TOS 1.02: When a folder name has exactly 8 characters,
! 870: * it appends a '.' at the end of the name... */
! 871: else if (base_len == 8 && pszDestName[len-1] == '.' &&
! 872: !strncasecmp(globbuf.gl_pathv[j],pszDestName,len-1))
! 873: {
! 874: /* we found a matching name... */
! 875: snprintf(pszDestName, nDestNameLen, "%s%c%s",
! 876: globbuf.gl_pathv[j], PATHSEP, s+1);
! 877: s -= 1;
! 878: j = globbuf.gl_pathc; /* break */
! 879: found = 1;
! 880: }
1.1.1.9 root 881: }
882: globfree(&globbuf);
883: if (!found)
884: {
885: /* didn't find it. Let's try normal files (it might be a symlink) */
886: *start++ = '*';
887: *start = 0;
888: glob(pszDestName,0,NULL,&globbuf);
889: *start-- = old2;
890: *start = old1;
891: for (j=0; j<globbuf.gl_pathc; j++)
892: {
893: if (!strncasecmp(globbuf.gl_pathv[j],pszDestName,len))
894: {
895: /* we found a matching name... */
1.1.1.12 root 896: snprintf(pszDestName, nDestNameLen, "%s%c%s",
897: globbuf.gl_pathv[j], PATHSEP, s+1);
1.1.1.9 root 898: j = globbuf.gl_pathc;
899: found = 1;
900: }
901: }
902: globfree(&globbuf);
903: if (!found)
904: { /* really nothing ! */
1.1.1.12 root 905: *s = PATHSEP;
1.1.1.9 root 906: fprintf(stderr,"no path for %s\n",pszDestName);
907: }
908: }
909: }
910: start = s;
911: }
912:
913: if (!start)
1.1.1.12 root 914: start = strrchr(pszDestName, PATHSEP); // path already converted ?
1.1.1.9 root 915:
916: if (start)
917: {
1.1.1.12 root 918: *start++ = PATHSEP; /* in case there was only 1 anti slash */
1.1.1.9 root 919: if (*start && !strchr(start,'?') && !strchr(start,'*'))
920: {
921: /* We have a complete name after the path, not a wildcard */
922: glob_t globbuf;
923: char old1,old2;
924: int len, found, base_len;
925: unsigned int j;
926:
927: old1 = *start;
928: *start++ = '*';
929: old2 = *start;
930: *start = 0;
931: glob(pszDestName,0,NULL,&globbuf);
932: *start-- = old2;
933: *start = old1;
934: len = strlen(pszDestName);
935: base_len = baselen(start);
936: found = 0;
937: for (j=0; j<globbuf.gl_pathc; j++)
938: {
939: /* If we search for a file of at least 8 characters, then it might
940: be a longer filename since the ST can access only the first 8
941: characters. If not, then it's a precise match (with case). */
942: if (!(base_len < 8 ? strcasecmp(globbuf.gl_pathv[j],pszDestName) :
943: strncasecmp(globbuf.gl_pathv[j],pszDestName,len)))
944: {
945: /* we found a matching name... */
1.1.1.12 root 946: strncpy(pszDestName, globbuf.gl_pathv[j], nDestNameLen);
1.1.1.9 root 947: j = globbuf.gl_pathc;
948: found = 1;
949: }
950: }
1.1.1.13! root 951: #ifdef HATARI_TRACE_ACTIVATED
1.1.1.9 root 952: if (!found)
953: {
954: /* It's often normal, the gem uses this to test for existence */
955: /* of desktop.inf or newdesk.inf for example. */
1.1.1.13! root 956: HATARI_TRACE ( HATARI_TRACE_OS_GEMDOS, "didn't find filename %s\n", pszDestName );
1.1.1.9 root 957: }
1.1.1.6 root 958: #endif
1.1.1.9 root 959: globfree(&globbuf);
960: }
961: }
1.1.1.13! root 962: HATARI_TRACE ( HATARI_TRACE_OS_GEMDOS, "conv %s -> %s\n", pszFileName, pszDestName );
1.1 root 963: }
964:
1.1.1.6 root 965:
1.1.1.2 root 966: /*-----------------------------------------------------------------------*/
1.1.1.12 root 967: /**
968: * GEMDOS Cauxin
969: * Call 0x3
970: */
1.1.1.7 root 971: #if 0
1.1.1.13! root 972: static bool GemDOS_Cauxin(Uint32 Params)
1.1 root 973: {
1.1.1.11 root 974: unsigned char c;
1.1 root 975:
1.1.1.9 root 976: /* Wait here until a character is ready */
977: while(!RS232_GetStatus())
978: ;
1.1 root 979:
1.1.1.9 root 980: /* And read character */
1.1.1.11 root 981: RS232_ReadBytes(&c,1);
982: Regs[REG_D0] = c;
1.1 root 983:
1.1.1.9 root 984: return TRUE;
1.1 root 985: }
1.1.1.7 root 986: #endif
1.1 root 987:
1.1.1.2 root 988: /*-----------------------------------------------------------------------*/
1.1.1.12 root 989: /**
990: * GEMDOS Cauxout
991: * Call 0x4
992: */
1.1.1.7 root 993: #if 0
1.1.1.13! root 994: static bool GemDOS_Cauxout(Uint32 Params)
1.1 root 995: {
1.1.1.11 root 996: unsigned char c;
1.1 root 997:
1.1.1.9 root 998: /* Send character to RS232 */
1.1.1.11 root 999: c = STMemory_ReadWord(Params+SIZE_WORD);
1000: RS232_TransferBytesTo(&c, 1);
1.1 root 1001:
1.1.1.9 root 1002: return TRUE;
1.1 root 1003: }
1.1.1.7 root 1004: #endif
1.1 root 1005:
1.1.1.2 root 1006: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1007: /**
1008: * GEMDOS Cprnout
1009: * Call 0x5
1010: */
1.1.1.13! root 1011: #if 0
! 1012: static bool GemDOS_Cprnout(Uint32 Params)
1.1 root 1013: {
1.1.1.11 root 1014: unsigned char c;
1.1 root 1015:
1.1.1.9 root 1016: /* Send character to printer(or file) */
1.1.1.11 root 1017: c = STMemory_ReadWord(Params+SIZE_WORD);
1018: Printer_TransferByteTo(c);
1.1.1.9 root 1019: Regs[REG_D0] = -1; /* Printer OK */
1.1 root 1020:
1.1.1.9 root 1021: return TRUE;
1.1 root 1022: }
1.1.1.13! root 1023: #endif
1.1 root 1024:
1.1.1.2 root 1025: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1026: /**
1027: * GEMDOS Set drive (0=A,1=B,2=C etc...)
1028: * Call 0xE
1029: */
1.1.1.13! root 1030: static bool GemDOS_SetDrv(Uint32 Params)
1.1 root 1031: {
1.1.1.9 root 1032: /* Read details from stack for our own use */
1033: CurrentDrive = STMemory_ReadWord(Params+SIZE_WORD);
1.1 root 1034:
1.1.1.9 root 1035: /* Still re-direct to TOS */
1036: return FALSE;
1.1 root 1037: }
1038:
1.1.1.2 root 1039: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1040: /**
1041: * GEMDOS Cprnos
1042: * Call 0x11
1043: */
1.1.1.13! root 1044: #if 0
! 1045: static bool GemDOS_Cprnos(Uint32 Params)
1.1 root 1046: {
1.1.1.13! root 1047: /* printer status depends if printing is enabled or not... */
1.1.1.9 root 1048: if (ConfigureParams.Printer.bEnablePrinting)
1049: Regs[REG_D0] = -1; /* Printer OK */
1050: else
1051: Regs[REG_D0] = 0; /* printer not ready if printing disabled */
1.1 root 1052:
1.1.1.9 root 1053: return TRUE;
1.1 root 1054: }
1.1.1.13! root 1055: #endif
1.1 root 1056:
1.1.1.2 root 1057: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1058: /**
1059: * GEMDOS Cauxis
1060: * Call 0x12
1061: */
1.1.1.7 root 1062: #if 0
1.1.1.13! root 1063: static bool GemDOS_Cauxis(Uint32 Params)
1.1 root 1064: {
1.1.1.9 root 1065: /* Read our RS232 state */
1066: if (RS232_GetStatus())
1067: Regs[REG_D0] = -1; /* Chars waiting */
1068: else
1069: Regs[REG_D0] = 0;
1.1 root 1070:
1.1.1.9 root 1071: return TRUE;
1.1 root 1072: }
1.1.1.7 root 1073: #endif
1.1 root 1074:
1.1.1.2 root 1075: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1076: /**
1077: * GEMDOS Cauxos
1078: * Call 0x13
1079: */
1.1.1.7 root 1080: #if 0
1.1.1.13! root 1081: static bool GemDOS_Cauxos(Uint32 Params)
1.1 root 1082: {
1.1.1.9 root 1083: Regs[REG_D0] = -1; /* Device ready */
1.1 root 1084:
1.1.1.9 root 1085: return TRUE;
1.1 root 1086: }
1.1.1.7 root 1087: #endif
1.1 root 1088:
1.1.1.2 root 1089: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1090: /**
1091: * GEMDOS Set Disk Transfer Address (DTA)
1092: * Call 0x1A
1093: */
1.1.1.13! root 1094: static bool GemDOS_SetDTA(Uint32 Params)
1.1 root 1095: {
1.1.1.9 root 1096: /* Look up on stack to find where DTA is! Store as PC pointer */
1097: pDTA = (DTA *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
1.1 root 1098:
1.1.1.9 root 1099: return FALSE;
1.1 root 1100: }
1101:
1.1.1.2 root 1102: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1103: /**
1104: * GEMDOS Dfree Free disk space.
1105: * Call 0x39
1106: */
1.1.1.13! root 1107: static bool GemDOS_DFree(Uint32 Params)
1.1.1.2 root 1108: {
1.1.1.9 root 1109: int Drive;
1.1.1.10 root 1110: Uint32 Address;
1.1.1.9 root 1111:
1.1.1.10 root 1112: Address = STMemory_ReadLong(Params+SIZE_WORD);
1.1.1.9 root 1113: Drive = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
1114: /* is it our drive? */
1115: if ((Drive == 0 && CurrentDrive >= 2) || Drive >= 3)
1116: {
1117: /* FIXME: Report actual free drive space */
1118:
1119: STMemory_WriteLong(Address, 10*2048); /* free clusters (mock 10 Mb) */
1120: STMemory_WriteLong(Address+SIZE_LONG, 50*2048 ); /* total clusters (mock 50 Mb) */
1.1.1.2 root 1121:
1.1.1.9 root 1122: STMemory_WriteLong(Address+SIZE_LONG*2, 512 ); /* bytes per sector */
1123: STMemory_WriteLong(Address+SIZE_LONG*3, 1 ); /* sectors per cluster */
1124: return TRUE;
1125: }
1126: else
1127: return FALSE; /* redirect to TOS */
1.1.1.2 root 1128: }
1129:
1130: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1131: /**
1132: * GEMDOS MkDir
1133: * Call 0x39
1134: */
1.1.1.13! root 1135: static bool GemDOS_MkDir(Uint32 Params)
1.1.1.6 root 1136: {
1.1.1.9 root 1137: char *pDirName;
1138: int Drive;
1139:
1140: /* Find directory to make */
1141: pDirName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
1142:
1143: Drive = GemDOS_IsFileNameAHardDrive(pDirName);
1144:
1145: if (ISHARDDRIVE(Drive))
1146: {
1.1.1.12 root 1147: char *psDirPath;
1148: psDirPath = malloc(FILENAME_MAX);
1149: if (!psDirPath)
1150: {
1151: perror("GemDOS_MkDir");
1152: Regs[REG_D0] = GEMDOS_ENSMEM;
1153: return TRUE;
1154: }
1155:
1.1.1.9 root 1156: /* Copy old directory, as if calls fails keep this one */
1.1.1.12 root 1157: GemDOS_CreateHardDriveFileName(Drive, pDirName, psDirPath, FILENAME_MAX);
1.1.1.9 root 1158:
1159: /* Attempt to make directory */
1.1.1.12 root 1160: if (mkdir(psDirPath, 0755) == 0)
1.1.1.9 root 1161: Regs[REG_D0] = GEMDOS_EOK;
1162: else
1163: Regs[REG_D0] = GEMDOS_EACCDN; /* Access denied */
1164:
1.1.1.12 root 1165: free(psDirPath);
1.1.1.9 root 1166: return TRUE;
1167: }
1168: return FALSE;
1.1 root 1169: }
1170:
1.1.1.2 root 1171: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1172: /**
1173: * GEMDOS RmDir
1174: * Call 0x3A
1175: */
1.1.1.13! root 1176: static bool GemDOS_RmDir(Uint32 Params)
1.1.1.6 root 1177: {
1.1.1.9 root 1178: char *pDirName;
1179: int Drive;
1180:
1181: /* Find directory to make */
1182: pDirName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
1183: Drive = GemDOS_IsFileNameAHardDrive(pDirName);
1184: if (ISHARDDRIVE(Drive))
1185: {
1.1.1.12 root 1186: char *psDirPath;
1187: psDirPath = malloc(FILENAME_MAX);
1188: if (!psDirPath)
1189: {
1190: perror("GemDOS_RmDir");
1191: Regs[REG_D0] = GEMDOS_ENSMEM;
1192: return TRUE;
1193: }
1194:
1.1.1.9 root 1195: /* Copy old directory, as if calls fails keep this one */
1.1.1.12 root 1196: GemDOS_CreateHardDriveFileName(Drive, pDirName, psDirPath, FILENAME_MAX);
1.1.1.9 root 1197:
1198: /* Attempt to make directory */
1.1.1.12 root 1199: if (rmdir(psDirPath) == 0)
1.1.1.9 root 1200: Regs[REG_D0] = GEMDOS_EOK;
1201: else
1202: Regs[REG_D0] = GEMDOS_EACCDN; /* Access denied */
1203:
1.1.1.12 root 1204: free(psDirPath);
1.1.1.9 root 1205: return TRUE;
1206: }
1207: return FALSE;
1.1 root 1208: }
1209:
1.1.1.11 root 1210:
1.1.1.2 root 1211: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1212: /**
1213: * GEMDOS ChDir
1214: * Call 0x3B
1215: */
1.1.1.13! root 1216: static bool GemDOS_ChDir(Uint32 Params)
1.1.1.6 root 1217: {
1.1.1.9 root 1218: char *pDirName;
1219: int Drive;
1.1 root 1220:
1.1.1.9 root 1221: /* Find new directory */
1222: pDirName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
1.1.1.3 root 1223:
1.1.1.13! root 1224: HATARI_TRACE ( HATARI_TRACE_OS_GEMDOS, "Dsetpath(\"%s\")\n", pDirName );
1.1.1.3 root 1225:
1.1.1.9 root 1226: Drive = GemDOS_IsFileNameAHardDrive(pDirName);
1.1.1.3 root 1227:
1.1.1.9 root 1228: if (ISHARDDRIVE(Drive))
1229: {
1230: struct stat buf;
1.1.1.11 root 1231: char *psTempDirPath;
1.1.1.3 root 1232:
1.1.1.11 root 1233: /* Allocate temporary memory for path name: */
1234: psTempDirPath = malloc(FILENAME_MAX);
1235: if (!psTempDirPath)
1236: {
1237: perror("GemDOS_ChDir");
1238: Regs[REG_D0] = GEMDOS_ENSMEM;
1239: return TRUE;
1240: }
1241:
1.1.1.12 root 1242: GemDOS_CreateHardDriveFileName(Drive, pDirName, psTempDirPath, FILENAME_MAX);
1.1.1.11 root 1243: if (stat(psTempDirPath, &buf))
1244: {
1245: /* error */
1246: free(psTempDirPath);
1.1.1.9 root 1247: Regs[REG_D0] = GEMDOS_EPTHNF;
1248: return TRUE;
1249: }
1250:
1.1.1.11 root 1251: File_AddSlashToEndFileName(psTempDirPath);
1252: File_MakeAbsoluteName(psTempDirPath);
1.1.1.9 root 1253:
1.1.1.11 root 1254: strcpy(emudrives[0]->fs_currpath, psTempDirPath);
1255: free(psTempDirPath);
1.1.1.9 root 1256:
1257: Regs[REG_D0] = GEMDOS_EOK;
1258: return TRUE;
1259: }
1.1.1.6 root 1260:
1.1.1.9 root 1261: return FALSE;
1.1 root 1262: }
1263:
1.1.1.11 root 1264:
1.1.1.2 root 1265: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1266: /**
1267: * GEMDOS Create file
1268: * Call 0x3C
1269: */
1.1.1.13! root 1270: static bool GemDOS_Create(Uint32 Params)
1.1 root 1271: {
1.1.1.11 root 1272: char szActualFileName[MAX_GEMDOS_PATH];
1.1.1.12 root 1273: char *pszFileName, *ptr;
1.1.1.9 root 1274: int Drive,Index,Mode;
1.1.1.12 root 1275: const char *rwflags;
1.1.1.9 root 1276:
1277: /* Find filename */
1278: pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
1279: Mode = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
1280: Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
1.1.1.12 root 1281: if (!ISHARDDRIVE(Drive))
1.1.1.9 root 1282: {
1.1.1.12 root 1283: return FALSE;
1284: }
1.1.1.9 root 1285:
1.1.1.12 root 1286: if (Mode == GEMDOS_FILE_ATTRIB_VOLUME_LABEL)
1287: {
1288: fprintf(stderr, "Warning: Hatari doesn't support GEMDOS volume"
1289: " label setting\n(for '%s')\n", pszFileName);
1290: Regs[REG_D0] = GEMDOS_EFILNF; /* File not found */
1291: return TRUE;
1292: }
1.1 root 1293:
1.1.1.12 root 1294: /* Now convert to hard drive filename */
1295: GemDOS_CreateHardDriveFileName(Drive, pszFileName,
1296: szActualFileName, sizeof(szActualFileName));
1297:
1298: /* Find slot to store file handle, as need to return WORD handle for ST */
1299: Index = GemDOS_FindFreeFileHandle();
1300: if (Index==-1)
1301: {
1302: /* No free handles, return error code */
1303: Regs[REG_D0] = GEMDOS_ENHNDL; /* No more handles */
1304: return TRUE;
1305: }
1306: #ifdef ENABLE_SAVING
1307: /* FIXME: implement other Mode attributes
1308: * - GEMDOS_FILE_ATTRIB_HIDDEN (FA_HIDDEN)
1309: * - GEMDOS_FILE_ATTRIB_SYSTEM_FILE (FA_SYSTEM)
1310: * - GEMDOS_FILE_ATTRIB_SUBDIRECTORY (FA_DIR)
1311: * - GEMDOS_FILE_ATTRIB_WRITECLOSE (FA_ARCHIVE)
1312: * (set automatically by GemDOS >= 0.15)
1313: */
1314: if (Mode & GEMDOS_FILE_ATTRIB_READONLY)
1315: rwflags = "wb";
1316: else
1317: rwflags = "wb+";
1318: FileHandles[Index].FileHandle = fopen(szActualFileName, rwflags);
1319:
1320: if (FileHandles[Index].FileHandle != NULL)
1321: {
1322: /* Tag handle table entry as used and return handle */
1323: FileHandles[Index].bUsed = TRUE;
1324: Regs[REG_D0] = Index+BASE_FILEHANDLE; /* Return valid ST file handle from range 6 to 45! (ours start from 0) */
1325: return TRUE;
1326: }
1.1.1.2 root 1327:
1.1.1.12 root 1328: /* We failed to create the file... now we have to return the right
1329: * error code: Normally we return FILE-NOT-FOUND, but in case the
1330: * directory did not exist yet, we have to return PATH-NOT-FOUND
1331: * (ST-Zip 2.6 relies on that during extraction of ZIP files). */
1332: ptr = strrchr(szActualFileName, PATHSEP);
1333: if (ptr)
1334: {
1335: *ptr = 0; /* Strip filename from string */
1336: if (!File_DirectoryExists(szActualFileName))
1337: {
1338: Regs[REG_D0] = GEMDOS_EPTHNF; /* Path not found */
1.1.1.9 root 1339: return TRUE;
1340: }
1341: }
1.1.1.12 root 1342: #endif
1343: Regs[REG_D0] = GEMDOS_EFILNF; /* File not found */
1344: return TRUE;
1.1 root 1345: }
1346:
1.1.1.2 root 1347: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1348: /**
1349: * GEMDOS Open file
1350: * Call 0x3D
1351: */
1.1.1.13! root 1352: static bool GemDOS_Open(Uint32 Params)
1.1 root 1353: {
1.1.1.11 root 1354: char szActualFileName[MAX_GEMDOS_PATH];
1.1.1.9 root 1355: char *pszFileName;
1356: const char *open_modes[] =
1.1.1.12 root 1357: { /* convert atari modes to stdio modes */
1358: "rb", /* read only */
1359: "rb+", /* FIXME: should be write only, but "wb" truncates */
1360: "rb+" /* read/write */
1361: "rb" /* read only */
1362: };
1.1.1.9 root 1363: int Drive,Index,Mode;
1364:
1365: /* Find filename */
1366: pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
1367: Mode = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
1368: Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
1369:
1.1.1.12 root 1370: if (!ISHARDDRIVE(Drive))
1.1.1.9 root 1371: {
1.1.1.12 root 1372: return FALSE;
1373: }
1374: /* And convert to hard drive filename */
1375: GemDOS_CreateHardDriveFileName(Drive, pszFileName,
1376: szActualFileName, sizeof(szActualFileName));
1377:
1378: /* Find slot to store file handle, as need to return WORD handle for ST */
1379: Index = GemDOS_FindFreeFileHandle();
1380: if (Index == -1)
1381: {
1382: /* No free handles, return error code */
1383: Regs[REG_D0] = GEMDOS_ENHNDL; /* No more handles */
1.1.1.9 root 1384: return TRUE;
1385: }
1.1.1.6 root 1386:
1.1.1.12 root 1387: /* FIXME: Open file
1388: * - fopen() modes don't allow write-only mode without truncating.
1389: * Fixing this requires using open() and file descriptors instead
1390: * of fopen() and FILE* pointers, but Windows doesn't support that
1391: */
1392: FileHandles[Index].FileHandle = fopen(szActualFileName, open_modes[Mode&0x03]);
1393:
1394: snprintf(FileHandles[Index].szActualName, sizeof(FileHandles[Index].szActualName),
1395: "%s", szActualFileName);
1396:
1397: if (FileHandles[Index].FileHandle != NULL)
1398: {
1399: /* Tag handle table entry as used and return handle */
1400: FileHandles[Index].bUsed = TRUE;
1401: Regs[REG_D0] = Index+BASE_FILEHANDLE; /* Return valid ST file handle from range 6 to 45! (ours start from 0) */
1402: return TRUE;
1403: }
1404:
1405: if (Mode != 1 && errno == EACCES)
1.1.1.13! root 1406: HATARI_TRACE ( HATARI_TRACE_OS_GEMDOS, "Missing permission to read file '%s'\n", szActualFileName );
1.1.1.12 root 1407:
1408: Regs[REG_D0] = GEMDOS_EFILNF; /* File not found/ error opening */
1409: return TRUE;
1.1 root 1410: }
1411:
1.1.1.2 root 1412: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1413: /**
1414: * GEMDOS Close file
1415: * Call 0x3E
1416: */
1.1.1.13! root 1417: static bool GemDOS_Close(Uint32 Params)
1.1 root 1418: {
1.1.1.9 root 1419: int Handle;
1.1 root 1420:
1.1.1.9 root 1421: /* Find our handle - may belong to TOS */
1422: Handle = STMemory_ReadWord(Params+SIZE_WORD)-BASE_FILEHANDLE;
1.1 root 1423:
1.1.1.9 root 1424: /* Check handle was valid */
1425: if (GemDOS_IsInvalidFileHandle(Handle))
1426: {
1427: /* No assume was TOS */
1428: return FALSE;
1429: }
1430: else
1431: {
1432: /* Close file and free up handle table */
1433: fclose(FileHandles[Handle].FileHandle);
1434: FileHandles[Handle].bUsed = FALSE;
1435: /* Return no error */
1436: Regs[REG_D0] = GEMDOS_EOK;
1437: return TRUE;
1438: }
1.1 root 1439: }
1440:
1.1.1.2 root 1441: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1442: /**
1443: * GEMDOS Read file
1444: * Call 0x3F
1445: */
1.1.1.13! root 1446: static bool GemDOS_Read(Uint32 Params)
1.1 root 1447: {
1.1.1.9 root 1448: char *pBuffer;
1449: unsigned long nBytesRead,Size,CurrentPos,FileSize;
1450: long nBytesLeft;
1451: int Handle;
1452:
1453: /* Read details from stack */
1454: Handle = STMemory_ReadWord(Params+SIZE_WORD)-BASE_FILEHANDLE;
1455: Size = STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD);
1456: pBuffer = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG));
1457:
1458: /* Check handle was valid */
1459: if (GemDOS_IsInvalidFileHandle(Handle))
1460: {
1461: /* No - assume was TOS */
1462: return FALSE;
1463: }
1464: else
1465: {
1466:
1467: /* To quick check to see where our file pointer is and how large the file is */
1468: CurrentPos = ftell(FileHandles[Handle].FileHandle);
1469: fseek(FileHandles[Handle].FileHandle, 0, SEEK_END);
1470: FileSize = ftell(FileHandles[Handle].FileHandle);
1471: fseek(FileHandles[Handle].FileHandle, CurrentPos, SEEK_SET);
1472:
1473: nBytesLeft = FileSize-CurrentPos;
1474:
1475: /* Check for End Of File */
1476: if (nBytesLeft == 0)
1477: {
1478: /* FIXME: should we return zero (bytes read) or an error? */
1479: Regs[REG_D0] = 0;
1480: return TRUE;
1481: }
1482: else
1483: {
1484: /* Limit to size of file to prevent errors */
1485: if (Size > FileSize)
1486: Size = FileSize;
1487: /* And read data in */
1488: nBytesRead = fread(pBuffer, 1, Size, FileHandles[Handle].FileHandle);
1489:
1490: /* Return number of bytes read */
1491: Regs[REG_D0] = nBytesRead;
1492:
1493: return TRUE;
1494: }
1495: }
1.1 root 1496: }
1497:
1.1.1.2 root 1498: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1499: /**
1500: * GEMDOS Write file
1501: * Call 0x40
1502: */
1.1.1.13! root 1503: static bool GemDOS_Write(Uint32 Params)
1.1 root 1504: {
1.1.1.9 root 1505: char *pBuffer;
1506: unsigned long Size,nBytesWritten;
1507: int Handle;
1.1 root 1508:
1509: #ifdef ENABLE_SAVING
1.1.1.9 root 1510: /* Read details from stack */
1511: Handle = STMemory_ReadWord(Params+SIZE_WORD)-BASE_FILEHANDLE;
1512: Size = STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD);
1513: pBuffer = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG));
1514:
1.1.1.10 root 1515: /* Check if handle was not invalid */
1516: if (!GemDOS_IsInvalidFileHandle(Handle))
1.1.1.9 root 1517: {
1518: nBytesWritten = fwrite(pBuffer, 1, Size, FileHandles[Handle].FileHandle);
1.1.1.11 root 1519: if (ferror(FileHandles[Handle].FileHandle))
1.1.1.9 root 1520: {
1.1.1.11 root 1521: Regs[REG_D0] = GEMDOS_EACCDN; /* Access denied(ie read-only) */
1.1.1.9 root 1522: }
1523: else
1.1.1.11 root 1524: {
1.1.1.9 root 1525:
1.1.1.11 root 1526: Regs[REG_D0] = nBytesWritten; /* OK */
1527: }
1.1.1.9 root 1528: return TRUE;
1529: }
1.1 root 1530: #endif
1531:
1.1.1.9 root 1532: return FALSE;
1.1 root 1533: }
1534:
1.1.1.2 root 1535: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1536: /**
1537: * GEMDOS Delete file
1538: * Call 0x41
1539: */
1.1.1.13! root 1540: static bool GemDOS_FDelete(Uint32 Params)
1.1 root 1541: {
1542: #ifdef ENABLE_SAVING
1.1.1.9 root 1543: char *pszFileName;
1544: int Drive;
1545:
1546: /* Find filename */
1547: pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
1548: Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
1549: if (ISHARDDRIVE(Drive))
1550: {
1.1.1.12 root 1551: char *psActualFileName;
1552: psActualFileName = malloc(FILENAME_MAX);
1553: if (!psActualFileName)
1554: {
1555: perror("GemDOS_FDelete");
1556: Regs[REG_D0] = GEMDOS_ENSMEM;
1557: return TRUE;
1558: }
1559:
1.1.1.9 root 1560: /* And convert to hard drive filename */
1.1.1.12 root 1561: GemDOS_CreateHardDriveFileName(Drive, pszFileName, psActualFileName, FILENAME_MAX);
1.1 root 1562:
1.1.1.9 root 1563: /* Now delete file?? */
1.1.1.12 root 1564: if (unlink(psActualFileName) == 0)
1.1.1.9 root 1565: Regs[REG_D0] = GEMDOS_EOK; /* OK */
1566: else
1567: Regs[REG_D0] = GEMDOS_EFILNF; /* File not found */
1568:
1.1.1.12 root 1569: free(psActualFileName);
1.1.1.9 root 1570: return TRUE;
1571: }
1.1 root 1572: #endif
1573:
1.1.1.9 root 1574: return FALSE;
1.1 root 1575: }
1576:
1.1.1.2 root 1577: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1578: /**
1579: * GEMDOS File seek
1580: * Call 0x42
1581: */
1.1.1.13! root 1582: static bool GemDOS_LSeek(Uint32 Params)
1.1 root 1583: {
1.1.1.9 root 1584: long Offset;
1585: int Handle,Mode;
1586:
1587: /* Read details from stack */
1588: Offset = (long)STMemory_ReadLong(Params+SIZE_WORD);
1589: Handle = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG)-BASE_FILEHANDLE;
1590: Mode = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG+SIZE_WORD);
1.1 root 1591:
1.1.1.9 root 1592: /* Check handle was valid */
1593: if (GemDOS_IsInvalidFileHandle(Handle))
1594: {
1595: /* No assume was TOS */
1596: return FALSE;
1597: }
1598: else
1599: {
1600: /* Return offset from start of file */
1601: fseek(FileHandles[Handle].FileHandle, Offset, Mode);
1602: Regs[REG_D0] = ftell(FileHandles[Handle].FileHandle);
1603: return TRUE;
1604: }
1.1 root 1605: }
1606:
1.1.1.10 root 1607:
1608: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1609: /**
1610: * GEMDOS Fattrib() - get or set file attributes
1611: * Call 0x43
1612: */
1.1.1.13! root 1613: static bool GemDOS_Fattrib(Uint32 Params)
1.1.1.10 root 1614: {
1.1.1.11 root 1615: char sActualFileName[MAX_GEMDOS_PATH];
1.1.1.10 root 1616: char *psFileName;
1617: int nDrive;
1618: int nRwFlag, nAttrib;
1.1.1.12 root 1619: struct stat FileStat;
1.1.1.10 root 1620:
1621: /* Find filename */
1622: psFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
1623: nDrive = GemDOS_IsFileNameAHardDrive(psFileName);
1624:
1625: nRwFlag = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
1626: nAttrib = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG+SIZE_WORD);
1627:
1.1.1.13! root 1628: HATARI_TRACE ( HATARI_TRACE_OS_GEMDOS, "Fattrib('%s', %d, 0x%x)\n",
! 1629: psFileName, nRwFlag, nAttrib );
1.1.1.10 root 1630:
1.1.1.12 root 1631: if (!ISHARDDRIVE(nDrive))
1.1.1.10 root 1632: {
1.1.1.12 root 1633: return FALSE;
1634: }
1.1.1.10 root 1635:
1.1.1.12 root 1636: /* Convert to hard drive filename */
1637: GemDOS_CreateHardDriveFileName(nDrive, psFileName,
1638: sActualFileName, sizeof(sActualFileName));
1.1.1.10 root 1639:
1.1.1.12 root 1640: if (nAttrib == GEMDOS_FILE_ATTRIB_VOLUME_LABEL)
1641: {
1642: fprintf(stderr, "Warning: Hatari doesn't support GEMDOS volume label setting\n(for '%s')\n", sActualFileName);
1643: Regs[REG_D0] = GEMDOS_EFILNF; /* File not found */
1644: return TRUE;
1645: }
1646: if (stat(sActualFileName, &FileStat) != 0)
1647: {
1648: Regs[REG_D0] = GEMDOS_EFILNF; /* File not found */
1649: return TRUE;
1650: }
1651: if (nRwFlag == 0)
1652: {
1653: /* Read attributes */
1654: Regs[REG_D0] = GemDOS_ConvertAttribute(FileStat.st_mode);
1655: return TRUE;
1656: }
1657: if (nAttrib & GEMDOS_FILE_ATTRIB_READONLY)
1658: {
1659: /* set read-only (readable by all) */
1660: if (chmod(sActualFileName, S_IRUSR|S_IRGRP|S_IROTH) == 0)
1.1.1.10 root 1661: {
1.1.1.12 root 1662: Regs[REG_D0] = GEMDOS_FILE_ATTRIB_READONLY;
1.1.1.10 root 1663: return TRUE;
1664: }
1665: }
1.1.1.12 root 1666: /* FIXME: support hidden/system/archive flags? */
1667: Regs[REG_D0] = GEMDOS_EACCDN; /* Acces denied */
1668: return TRUE;
1.1.1.10 root 1669: }
1670:
1671:
1.1.1.2 root 1672: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1673: /**
1674: * GEMDOS Get Directory
1675: * Call 0x47
1676: */
1.1.1.10 root 1677: static int GemDOS_GetDir(Uint32 Params)
1.1.1.9 root 1678: {
1.1.1.10 root 1679: Uint32 Address;
1680: Uint16 Drive;
1.1.1.9 root 1681:
1.1.1.10 root 1682: Address = STMemory_ReadLong(Params+SIZE_WORD);
1.1.1.9 root 1683: Drive = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
1684: /* is it our drive? */
1685: if ((Drive == 0 && CurrentDrive >= 2) || Drive >= 3)
1686: {
1.1.1.11 root 1687: char path[MAX_GEMDOS_PATH];
1.1.1.9 root 1688: int i,len,c;
1689:
1690: Regs[REG_D0] = GEMDOS_EOK; /* OK */
1691: strcpy(path,&emudrives[0]->fs_currpath[strlen(emudrives[0]->hd_emulation_dir)]);
1692: // convertit en path st (dos)
1693: len = strlen(path)-1;
1694: path[len] = 0;
1695: for (i = 0; i <= len; i++)
1696: {
1697: c = path[i];
1.1.1.12 root 1698: STMemory_WriteByte(Address+i, (c==PATHSEP ? '\\' : c) );
1.1.1.9 root 1699: }
1.1.1.13! root 1700: HATARI_TRACE ( HATARI_TRACE_OS_GEMDOS, "GemDOS_GetDir (%d) = %s\n", Drive, path );
1.1.1.9 root 1701:
1702: return TRUE;
1703: }
1704: else return FALSE;
1.1.1.2 root 1705: }
1706:
1707: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1708: /**
1709: * PExec Load And Go - Redirect to cart' routine at address 0xFA1000
1710: *
1711: * If loading from hard-drive(ie drive ID 2 or more) set condition codes to run own GEMDos routines
1712: */
1.1.1.10 root 1713: static int GemDOS_Pexec_LoadAndGo(Uint32 Params)
1.1 root 1714: {
1.1.1.9 root 1715: /* add multiple disk support here too */
1716: /* Hard-drive? */
1.1.1.11 root 1717: char *pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+2*SIZE_WORD));
1718: int Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
1719:
1720: if (ISHARDDRIVE(Drive))
1.1.1.9 root 1721: {
1722: /* If not using A: or B:, use my own routines to load */
1723: return CALL_PEXEC_ROUTINE;
1724: }
1725: else return FALSE;
1.1 root 1726: }
1727:
1.1.1.2 root 1728: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1729: /**
1730: * PExec Load But Don't Go - Redirect to cart' routine at address 0xFA1000
1731: */
1.1.1.10 root 1732: static int GemDOS_Pexec_LoadDontGo(Uint32 Params)
1.1 root 1733: {
1.1.1.9 root 1734: /* Hard-drive? */
1.1.1.11 root 1735: char *pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+2*SIZE_WORD));
1736: int Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
1737: if (ISHARDDRIVE(Drive))
1.1.1.9 root 1738: {
1739: return CALL_PEXEC_ROUTINE;
1740: }
1741: else return FALSE;
1.1 root 1742: }
1743:
1.1.1.2 root 1744: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1745: /**
1746: * GEMDOS PExec handler
1747: * Call 0x4B
1748: */
1.1.1.10 root 1749: static int GemDOS_Pexec(Uint32 Params)
1.1 root 1750: {
1.1.1.10 root 1751: Uint16 Mode;
1.1.1.11 root 1752: /*char *psFileName, *psCmdLine;*/
1.1 root 1753:
1.1.1.9 root 1754: /* Find PExec mode */
1755: Mode = STMemory_ReadWord(Params+SIZE_WORD);
1.1 root 1756:
1.1.1.11 root 1757: /*
1758: psFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+2*SIZE_WORD));
1759: psCmdLine = (char *)STRAM_ADDR(STMemory_ReadLong(Params+2*SIZE_WORD+SIZE_LONG));
1760: */
1761:
1.1.1.9 root 1762: /* Re-direct as needed */
1763: switch(Mode)
1764: {
1765: case 0: /* Load and go */
1766: return GemDOS_Pexec_LoadAndGo(Params);
1767: case 3: /* Load, don't go */
1768: return GemDOS_Pexec_LoadDontGo(Params);
1769: case 4: /* Just go */
1770: return FALSE;
1771: case 5: /* Create basepage */
1772: return FALSE;
1773: case 6:
1774: return FALSE;
1775: }
1776:
1.1.1.10 root 1777: /* Default: Still re-direct to TOS */
1.1.1.9 root 1778: return FALSE;
1.1 root 1779: }
1780:
1.1.1.4 root 1781:
1782: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1783: /**
1784: * GEMDOS Search Next
1785: * Call 0x4F
1786: */
1.1.1.13! root 1787: static bool GemDOS_SNext(void)
1.1.1.4 root 1788: {
1.1.1.9 root 1789: int Index;
1.1.1.13! root 1790: int ret;
1.1.1.9 root 1791:
1792: /* Refresh pDTA pointer (from the current basepage) */
1793: pDTA = (DTA *)STRAM_ADDR(STMemory_ReadLong(STMemory_ReadLong(act_pd)+32));
1.1.1.4 root 1794:
1.1.1.9 root 1795: /* Was DTA ours or TOS? */
1796: if (do_get_mem_long(pDTA->magic) == DTA_MAGIC_NUMBER)
1797: {
1.1.1.13! root 1798: struct dirent **temp;
1.1.1.9 root 1799:
1800: /* Find index into our list of structures */
1801: Index = do_get_mem_word(pDTA->index) & (MAX_DTAS_FILES-1);
1.1.1.6 root 1802:
1.1.1.13! root 1803: if (nAttrSFirst == 8)
1.1.1.9 root 1804: {
1805: Regs[REG_D0] = GEMDOS_ENMFIL; /* No more files */
1806: return TRUE;
1807: }
1808:
1809: temp = InternalDTAs[Index].found;
1.1.1.13! root 1810: do
1.1.1.9 root 1811: {
1.1.1.13! root 1812: if (InternalDTAs[Index].centry >= InternalDTAs[Index].nentries)
! 1813: {
! 1814: Regs[REG_D0] = GEMDOS_ENMFIL; /* No more files */
! 1815: return TRUE;
! 1816: }
! 1817:
! 1818: ret = PopulateDTA(InternalDTAs[Index].path,
! 1819: temp[InternalDTAs[Index].centry++]);
! 1820: } while (ret == 1);
! 1821:
! 1822: if (ret < 0)
! 1823: {
! 1824: Log_Printf(LOG_WARN, "GemDOS_SNext: Error setting DTA.\n");
! 1825: Regs[REG_D0] = GEMDOS_EINTRN;
1.1.1.9 root 1826: return TRUE;
1827: }
1.1.1.4 root 1828:
1.1.1.9 root 1829: Regs[REG_D0] = GEMDOS_EOK;
1830: return TRUE;
1831: }
1.1.1.4 root 1832:
1.1.1.9 root 1833: return FALSE;
1.1.1.4 root 1834: }
1835:
1836:
1.1.1.2 root 1837: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1838: /**
1839: * GEMDOS Find first file
1840: * Call 0x4E
1841: */
1.1.1.13! root 1842: static bool GemDOS_SFirst(Uint32 Params)
1.1 root 1843: {
1.1.1.11 root 1844: char szActualFileName[MAX_GEMDOS_PATH];
1845: char tempstr[MAX_GEMDOS_PATH];
1.1.1.9 root 1846: char *pszFileName;
1847: struct dirent **files;
1848: int Drive;
1849: DIR *fsdir;
1850: int i,j,count;
1851:
1852: /* Find filename to search for */
1853: pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
1.1.1.13! root 1854: nAttrSFirst = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
1.1.1.9 root 1855:
1856: /* Refresh pDTA pointer (from the current basepage) */
1857: pDTA = (DTA *)STRAM_ADDR(STMemory_ReadLong(STMemory_ReadLong(act_pd)+32));
1858:
1859: Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
1860: if (ISHARDDRIVE(Drive))
1861: {
1862:
1863: /* And convert to hard drive filename */
1.1.1.12 root 1864: GemDOS_CreateHardDriveFileName(Drive, pszFileName,
1865: szActualFileName, sizeof(szActualFileName));
1.1.1.9 root 1866:
1867: /* Populate DTA, set index for our use */
1868: do_put_mem_word(pDTA->index, DTAIndex);
1869: /* set our dta magic num */
1870: do_put_mem_long(pDTA->magic, DTA_MAGIC_NUMBER);
1871:
1872: if (InternalDTAs[DTAIndex].bUsed == TRUE)
1873: ClearInternalDTA();
1874: InternalDTAs[DTAIndex].bUsed = TRUE;
1875:
1876: /* Were we looking for the volume label? */
1.1.1.13! root 1877: if (nAttrSFirst == GEMDOS_FILE_ATTRIB_VOLUME_LABEL)
1.1.1.9 root 1878: {
1879: /* Volume name */
1880: strcpy(pDTA->dta_name,"EMULATED.001");
1881: Regs[REG_D0] = GEMDOS_EOK; /* Got volume */
1882: return TRUE;
1883: }
1884:
1885: /* open directory */
1886: fsfirst_dirname(szActualFileName, InternalDTAs[DTAIndex].path);
1887: fsdir = opendir(InternalDTAs[DTAIndex].path);
1888:
1889: if (fsdir == NULL)
1890: {
1891: Regs[REG_D0] = GEMDOS_EPTHNF; /* Path not found */
1892: return TRUE;
1893: }
1894: /* close directory */
1895: closedir(fsdir);
1896:
1897: count = scandir(InternalDTAs[DTAIndex].path, &files, 0, alphasort);
1898: /* File (directory actually) not found */
1899: if (count < 0)
1900: {
1901: Regs[REG_D0] = GEMDOS_EFILNF;
1902: return TRUE;
1903: }
1904:
1905: InternalDTAs[DTAIndex].centry = 0; /* current entry is 0 */
1906: fsfirst_dirmask(szActualFileName, tempstr); /* get directory mask */
1907: InternalDTAs[DTAIndex].found = files; /* get files */
1908:
1909: /* count & copy the entries that match our mask and discard the rest */
1910: j = 0;
1911: for (i=0; i < count; i++)
1.1.1.13! root 1912: {
1.1.1.9 root 1913: if (match(tempstr, files[i]->d_name))
1914: {
1915: InternalDTAs[DTAIndex].found[j] = files[i];
1916: j++;
1917: }
1918: else
1919: {
1920: free(files[i]);
1.1.1.13! root 1921: files[i] = NULL;
1.1.1.9 root 1922: }
1.1.1.13! root 1923: }
1.1.1.9 root 1924: InternalDTAs[DTAIndex].nentries = j; /* set number of legal entries */
1925:
1926: /* No files of that match, return error code */
1927: if (j==0)
1928: {
1929: free(files);
1930: InternalDTAs[DTAIndex].found = NULL;
1931: Regs[REG_D0] = GEMDOS_EFILNF; /* File not found */
1932: return TRUE;
1933: }
1934:
1935: /* Scan for first file (SNext uses no parameters) */
1.1.1.11 root 1936: GemDOS_SNext();
1.1.1.9 root 1937: /* increment DTA index */
1938: DTAIndex++;
1939: DTAIndex&=(MAX_DTAS_FILES-1);
1940:
1941: return TRUE;
1942: }
1943: return FALSE;
1.1 root 1944: }
1945:
1946:
1.1.1.2 root 1947: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1948: /**
1949: * GEMDOS Rename
1950: * Call 0x56
1951: */
1.1.1.13! root 1952: static bool GemDOS_Rename(Uint32 Params)
1.1 root 1953: {
1.1.1.9 root 1954: char *pszNewFileName,*pszOldFileName;
1.1.1.11 root 1955: char szNewActualFileName[MAX_GEMDOS_PATH],szOldActualFileName[MAX_GEMDOS_PATH];
1.1.1.9 root 1956: int NewDrive, OldDrive;
1957:
1958: /* Read details from stack */
1959: pszOldFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD));
1960: pszNewFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG));
1961:
1962: NewDrive = GemDOS_IsFileNameAHardDrive(pszNewFileName);
1963: OldDrive = GemDOS_IsFileNameAHardDrive(pszOldFileName);
1964: if (ISHARDDRIVE(NewDrive) && ISHARDDRIVE(OldDrive))
1965: {
1966: /* And convert to hard drive filenames */
1.1.1.12 root 1967: GemDOS_CreateHardDriveFileName(NewDrive, pszNewFileName,
1968: szNewActualFileName, sizeof(szNewActualFileName));
1969: GemDOS_CreateHardDriveFileName(OldDrive, pszOldFileName,
1970: szOldActualFileName, sizeof(szOldActualFileName));
1.1.1.9 root 1971:
1972: /* Rename files */
1973: if ( rename(szOldActualFileName,szNewActualFileName)==0 )
1974: Regs[REG_D0] = GEMDOS_EOK;
1975: else
1976: Regs[REG_D0] = GEMDOS_EACCDN; /* Access denied */
1977: return TRUE;
1978: }
1.1 root 1979:
1.1.1.9 root 1980: return FALSE;
1.1 root 1981: }
1982:
1.1.1.2 root 1983: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1984: /**
1985: * GEMDOS GSDToF
1986: * Call 0x57
1987: */
1.1.1.13! root 1988: static bool GemDOS_GSDToF(Uint32 Params)
1.1 root 1989: {
1.1.1.9 root 1990: DATETIME DateTime;
1.1.1.10 root 1991: Uint32 pBuffer;
1.1.1.9 root 1992: int Handle,Flag;
1993:
1994: /* Read details from stack */
1995: pBuffer = STMemory_ReadLong(Params+SIZE_WORD);
1996: Handle = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG)-BASE_FILEHANDLE;
1997: Flag = STMemory_ReadWord(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG);
1998:
1999: /* Check handle was valid */
2000: if (GemDOS_IsInvalidFileHandle(Handle))
2001: {
2002: /* No assume was TOS */
2003: return FALSE;
2004: }
2005:
2006: /* Set time/date stamp? Do nothing. */
2007: if (Flag == 1)
2008: {
2009: Regs[REG_D0] = GEMDOS_EOK;
2010: return TRUE;
2011: }
2012:
2013: Regs[REG_D0] = GEMDOS_ERROR; /* Invalid parameter */
2014:
2015: if (GemDOS_GetFileInformation(FileHandles[Handle].szActualName, &DateTime) == TRUE)
2016: {
2017: STMemory_WriteWord(pBuffer, DateTime.word1);
2018: STMemory_WriteWord(pBuffer+2, DateTime.word2);
2019: Regs[REG_D0] = GEMDOS_EOK;
2020: }
2021: return TRUE;
1.1 root 2022: }
2023:
1.1.1.9 root 2024:
1.1 root 2025: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2026: /**
2027: * Run GEMDos call, and re-direct if need to. Used to handle hard disk emulation etc...
2028: * This sets the condition codes (in SR), which are used in the 'cart_asm.s' program to
2029: * decide if we need to run old GEM vector, or PExec or nothing.
2030: *
2031: * This method keeps the stack and other states consistant with the original ST which is very important
2032: * for the PExec call and maximum compatibility through-out
2033: */
1.1 root 2034: void GemDOS_OpCode(void)
2035: {
1.1.1.9 root 2036: unsigned short int GemDOSCall,CallingSReg;
1.1.1.10 root 2037: Uint32 Params;
1.1.1.9 root 2038: short RunOld;
1.1.1.12 root 2039: Uint16 SR;
1.1.1.9 root 2040:
1.1.1.12 root 2041: SR = M68000_GetSR();
1.1.1.9 root 2042:
2043: /* Read SReg from stack to see if parameters are on User or Super stack */
2044: CallingSReg = STMemory_ReadWord(Regs[REG_A7]);
2045: if ((CallingSReg&SR_SUPERMODE)==0) /* Calling from user mode */
2046: Params = regs.usp;
2047: else
2048: {
2049: Params = Regs[REG_A7]+SIZE_WORD+SIZE_LONG; /* super stack */
1.1.1.12 root 2050: if (currprefs.cpu_level > 0)
1.1.1.9 root 2051: Params += SIZE_WORD; /* Skip extra word whe CPU is >=68010 */
2052: }
2053:
2054: /* Default to run TOS GemDos (SR_NEG run Gemdos, SR_ZERO already done, SR_OVERFLOW run own 'Pexec' */
2055: RunOld = TRUE;
2056: SR &= SR_CLEAR_OVERFLOW;
2057: SR &= SR_CLEAR_ZERO;
2058: SR |= SR_NEG;
1.1 root 2059:
1.1.1.9 root 2060: /* Find pointer to call parameters */
2061: GemDOSCall = STMemory_ReadWord(Params);
1.1.1.2 root 2062:
1.1.1.13! root 2063: #ifdef HATARI_TRACE_ACTIVATED
1.1.1.9 root 2064: if (GemDOSCall < (sizeof(pszGemDOSNames)/sizeof(pszGemDOSNames[0])))
1.1.1.13! root 2065: {
! 2066: HATARI_TRACE ( HATARI_TRACE_OS_GEMDOS, "GemDOS 0x%X (%s)\n",
! 2067: GemDOSCall, pszGemDOSNames[GemDOSCall] );
! 2068: }
1.1.1.9 root 2069: else
1.1.1.13! root 2070: {
! 2071: HATARI_TRACE ( HATARI_TRACE_OS_GEMDOS, "GemDOS 0x%X\n",
! 2072: GemDOSCall );
! 2073: }
1.1 root 2074: #endif
2075:
1.1.1.9 root 2076: /* Intercept call */
2077: switch(GemDOSCall)
2078: {
2079: /*
2080: case 0x3:
2081: if (GemDOS_Cauxin(Params))
2082: RunOld = FALSE;
2083: break;
2084: */
2085: /*
2086: case 0x4:
2087: if (GemDOS_Cauxout(Params))
2088: RunOld = FALSE;
2089: break;
2090: */
1.1.1.13! root 2091: /* direct printing via GEMDOS */
! 2092: /*
! 2093: case 0x5:
1.1.1.9 root 2094: if (GemDOS_Cprnout(Params))
2095: RunOld = FALSE;
2096: break;
1.1.1.13! root 2097: */
1.1.1.9 root 2098: case 0xe:
2099: if (GemDOS_SetDrv(Params))
2100: RunOld = FALSE;
2101: break;
1.1.1.13! root 2102: /* Printer status */
! 2103: /*
! 2104: case 0x11:
1.1.1.9 root 2105: if (GemDOS_Cprnos(Params))
2106: RunOld = FALSE;
2107: break;
1.1.1.13! root 2108: */
1.1.1.9 root 2109: /*
2110: case 0x12:
2111: if (GemDOS_Cauxis(Params))
2112: RunOld = FALSE;
2113: break;
2114: */
2115: /*
2116: case 0x13:
2117: if (GemDOS_Cauxos(Params))
2118: RunOld = FALSE;
2119: break;
2120: */
2121: case 0x1a:
2122: if (GemDOS_SetDTA(Params))
2123: RunOld = FALSE;
2124: break;
2125: case 0x36:
2126: if (GemDOS_DFree(Params))
2127: RunOld = FALSE;
2128: break;
2129: case 0x39:
2130: if (GemDOS_MkDir(Params))
2131: RunOld = FALSE;
2132: break;
2133: case 0x3a:
2134: if (GemDOS_RmDir(Params))
2135: RunOld = FALSE;
2136: break;
2137: case 0x3b:
2138: if (GemDOS_ChDir(Params))
2139: RunOld = FALSE;
2140: break;
2141: case 0x3c:
2142: if (GemDOS_Create(Params))
2143: RunOld = FALSE;
2144: break;
2145: case 0x3d:
2146: if (GemDOS_Open(Params))
2147: RunOld = FALSE;
2148: break;
2149: case 0x3e:
2150: if (GemDOS_Close(Params))
2151: RunOld = FALSE;
2152: break;
2153: case 0x3f:
2154: if (GemDOS_Read(Params))
2155: RunOld = FALSE;
2156: break;
2157: case 0x40:
2158: if (GemDOS_Write(Params))
2159: RunOld = FALSE;
2160: break;
2161: case 0x41:
1.1.1.12 root 2162: if (GemDOS_FDelete(Params))
1.1.1.9 root 2163: RunOld = FALSE;
2164: break;
2165: case 0x42:
2166: if (GemDOS_LSeek(Params))
2167: RunOld = FALSE;
2168: break;
1.1.1.10 root 2169: case 0x43:
2170: if (GemDOS_Fattrib(Params))
2171: RunOld = FALSE;
2172: break;
1.1.1.9 root 2173: case 0x47:
2174: if (GemDOS_GetDir(Params))
2175: RunOld = FALSE;
2176: break;
2177: case 0x4b:
2178: if (GemDOS_Pexec(Params) == CALL_PEXEC_ROUTINE)
2179: RunOld = CALL_PEXEC_ROUTINE;
2180: break;
2181: case 0x4e:
2182: if (GemDOS_SFirst(Params))
2183: RunOld = FALSE;
2184: break;
2185: case 0x4f:
1.1.1.11 root 2186: if (GemDOS_SNext())
1.1.1.9 root 2187: RunOld = FALSE;
2188: break;
2189: case 0x56:
2190: if (GemDOS_Rename(Params))
2191: RunOld = FALSE;
2192: break;
2193: case 0x57:
2194: if (GemDOS_GSDToF(Params))
2195: RunOld = FALSE;
2196: break;
2197: }
1.1.1.13! root 2198:
1.1.1.9 root 2199: switch(RunOld)
2200: {
1.1.1.13! root 2201: case FALSE:
! 2202: /* skip over branch to pexec to RTE */
1.1.1.9 root 2203: SR |= SR_ZERO;
1.1.1.13! root 2204: /* visualize GemDOS emu HD access? */
! 2205: switch (GemDOSCall)
! 2206: {
! 2207: case 0x36:
! 2208: case 0x39:
! 2209: case 0x3a:
! 2210: case 0x3b:
! 2211: case 0x3c:
! 2212: case 0x3d:
! 2213: case 0x3e:
! 2214: case 0x3f:
! 2215: case 0x40:
! 2216: case 0x41:
! 2217: case 0x42:
! 2218: case 0x43:
! 2219: case 0x47:
! 2220: case 0x4e:
! 2221: case 0x4f:
! 2222: case 0x56:
! 2223: Statusbar_EnableHDLed();
! 2224: }
1.1.1.9 root 2225: break;
1.1.1.13! root 2226: case CALL_PEXEC_ROUTINE:
! 2227: /* branch to pexec, then redirect to old gemdos. */
1.1.1.9 root 2228: SR |= SR_OVERFLOW;
2229: break;
2230: }
1.1 root 2231:
1.1.1.12 root 2232: M68000_SetSR(SR); /* update the flags in the SR register */
1.1 root 2233: }
2234:
1.1.1.9 root 2235:
1.1.1.2 root 2236: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2237: /**
2238: * GemDOS_Boot - routine called on the first occurence of the gemdos opcode.
2239: * (this should be in the cartridge bootrom)
2240: * Sets up our gemdos handler (or, if we don't need one, just turn off keyclicks)
1.1.1.2 root 2241: */
1.1.1.7 root 2242: void GemDOS_Boot(void)
1.1.1.2 root 2243: {
1.1.1.9 root 2244: bInitGemDOS = TRUE;
1.1.1.2 root 2245:
1.1.1.13! root 2246: HATARI_TRACE ( HATARI_TRACE_OS_GEMDOS, "Gemdos_Boot()\n" );
1.1.1.9 root 2247:
2248: /* install our gemdos handler, if -e or --harddrive option used */
2249: if (GEMDOS_EMU_ON)
2250: {
2251: /* Get the address of the p_run variable that points to the actual basepage */
2252: if (TosVersion == 0x100)
2253: {
2254: /* We have to use fix addresses on TOS 1.00 :-( */
2255: if ((STMemory_ReadWord(TosAddress+28)>>1) == 4)
2256: act_pd = 0x873c; /* Spanish TOS is different from others! */
2257: else
2258: act_pd = 0x602c;
2259: }
2260: else
2261: {
2262: act_pd = STMemory_ReadLong(TosAddress + 0x28);
2263: }
2264:
2265: /* Save old GEMDOS handler adress */
2266: STMemory_WriteLong(CART_OLDGEMDOS, STMemory_ReadLong(0x0084));
2267: /* Setup new GEMDOS handler, see "cart_asm.s" */
2268: STMemory_WriteLong(0x0084, CART_GEMDOS);
2269: }
1.1 root 2270: }
1.1.1.2 root 2271:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.