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