2 * (c) 1993, 1994 Erik Bos
14 #include <sys/types.h>
18 #include "prototypes.h"
23 #include "registers.h"
26 WORD ExtendedError
, CodePage
= 437;
27 BYTE ErrorClass
, Action
, ErrorLocus
;
35 static struct DosHeap
*heap
;
37 WORD sharing_retries
= 3; /* number of retries at sharing violation */
38 WORD sharing_pause
= 1; /* pause between retries */
40 extern char TempDirectory
[];
42 static int Error(int e
, int class, int el
)
45 Action
= SA_Ask4Retry
;
52 void errno_to_doserr(void)
56 Error (ShareViolation
, EC_Temporary
, EL_Unknown
);
59 Error (InvalidHandle
, EC_AppError
, EL_Unknown
);
62 Error (DiskFull
, EC_MediaError
, EL_Disk
);
67 Error (WriteProtected
, EC_AccessDenied
, EL_Unknown
);
70 Error (LockViolation
, EC_AccessDenied
, EL_Unknown
);
73 Error (FileNotFound
, EC_NotFound
, EL_Unknown
);
76 Error (CanNotMakeDir
, EC_AccessDenied
, EL_Unknown
);
80 Error (NoMoreFiles
, EC_MediaError
, EL_Unknown
);
83 Error (FileExists
, EC_Exists
, EL_Disk
);
86 fprintf(stderr
, "int21: unknown errno %d!\n", errno
);
87 Error (GeneralFailure
, EC_SystemFailure
, EL_Unknown
);
92 static void Barf(struct sigcontext_struct
*context
)
94 fprintf(stderr
, "int21: unknown/not implemented parameters:\n");
95 fprintf(stderr
, "int21: AX %04x, BX %04x, CX %04x, DX %04x, "
96 "SI %04x, DI %04x, DS %04x, ES %04x\n",
97 AX
, BX
, CX
, DX
, SI
, DI
, DS
, ES
);
100 void ChopOffWhiteSpace(char *string
)
104 for (length
= strlen(string
) ; length
; length
--)
105 if (string
[length
] == ' ')
106 string
[length
] = '\0';
109 static void CreateBPB(int drive
, BYTE
*data
)
114 setword(&data
[3], 0);
116 setword(&data
[6], 240);
117 setword(&data
[8], 64000);
119 setword(&data
[0x0b], 40);
120 setword(&data
[0x0d], 56);
121 setword(&data
[0x0f], 2);
122 setword(&data
[0x11], 0);
123 setword(&data
[0x1f], 800);
125 setword(&data
[0x22], 1);
126 } else { /* 1.44mb */
129 setword(&data
[3], 0);
131 setword(&data
[6], 240);
132 setword(&data
[8], 2880);
134 setword(&data
[0x0b], 6);
135 setword(&data
[0x0d], 18);
136 setword(&data
[0x0f], 2);
137 setword(&data
[0x11], 0);
138 setword(&data
[0x1f], 80);
140 setword(&data
[0x22], 2);
144 static void GetFreeDiskSpace(struct sigcontext_struct
*context
)
150 drive
= DOS_GetDefaultDrive();
154 if (!DOS_ValidDrive(drive
)) {
155 Error(InvalidDrive
, EC_MediaError
, EL_Disk
);
160 if (!DOS_GetFreeSpace(drive
, &size
, &available
)) {
161 Error(GeneralFailure
, EC_MediaError
, EL_Disk
);
169 BX
= (available
/ (CX
* AX
));
170 DX
= (size
/ (CX
* AX
));
174 static void GetDriveAllocInfo(struct sigcontext_struct
*context
)
177 long size
, available
;
180 if (!DOS_ValidDrive(DL
)) {
184 Error (InvalidDrive
, EC_MediaError
, EL_Disk
);
188 if (!DOS_GetFreeSpace(DL
, &size
, &available
)) {
189 Error(GeneralFailure
, EC_MediaError
, EL_Disk
);
196 EDX
= (size
/ (CX
* AX
));
200 DS
= segment(mediaID
);
201 BX
= offset(mediaID
);
205 static void GetDefDriveAllocInfo(struct sigcontext_struct
*context
)
207 DX
= DOS_GetDefaultDrive();
208 GetDriveAllocInfo(context
);
211 static void GetDrivePB(struct sigcontext_struct
*context
)
213 Error (InvalidDrive
, EC_MediaError
, EL_Disk
);
215 /* I'm sorry but I only got networked drives :-) */
218 static void ReadFile(struct sigcontext_struct
*context
)
223 /* can't read from stdout / stderr */
224 if ((BX
== 1) || (BX
== 2)) {
225 Error (InvalidHandle
, EL_Unknown
, EC_Unknown
);
231 ptr
= pointer (DS
,DX
);
239 size
= read(BX
, ptr
, CX
);
252 static void WriteFile(struct sigcontext_struct
*context
)
257 ptr
= pointer (DS
,DX
);
260 Error (InvalidHandle
, EC_Unknown
, EL_Unknown
);
267 for (x
= 0;x
!= CX
;x
++) {
268 fprintf(stderr
, "%c", *ptr
++);
276 size
= write(BX
, ptr
, CX
);
278 Error (WriteFault
, EC_Unknown
, EL_Unknown
);
295 static void SeekFile(struct sigcontext_struct
*context
)
297 off_t status
, fileoffset
;
300 case 1: fileoffset
= SEEK_CUR
;
302 case 2: fileoffset
= SEEK_END
;
305 case 0: fileoffset
= SEEK_SET
;
308 status
= lseek(BX
, (CX
* 0x100) + DX
, fileoffset
);
311 AL
= ExtendedError
; SetCflag
;
315 AX
= (status
& 0xffff);
316 DX
= ((status
>> 16) & 0xffff);
321 static void ioctlGetDeviceInfo(struct sigcontext_struct
*context
)
334 if (fstat(BX
, &sbuf
) < 0)
336 IntBarf(0x21, context
);
342 /* This isn't the right answer, but should be close enough. */
349 static void ioctlGenericBlkDevReq(struct sigcontext_struct
*context
)
351 BYTE
*dataptr
= pointer(DS
, DX
);
355 drive
= DOS_GetDefaultDrive();
360 IntBarf(0x21, context
);
364 case 0x60: /* get device parameters */
365 /* used by w4wgrp's winfile */
367 dataptr
[6] = 0; /* media type */
370 dataptr
[1] = 0x05; /* fixed disk */
371 setword(&dataptr
[2], 0x01); /* non removable */
372 setword(&dataptr
[4], 0x300); /* # of cylinders */
376 dataptr
[1] = 0x07; /* block dev, floppy */
377 setword(&dataptr
[2], 0x02); /* removable */
378 setword(&dataptr
[4], 80); /* # of cylinders */
380 CreateBPB(drive
, &dataptr
[7]);
385 IntBarf(0x21, context
);
389 static void GetSystemDate(struct sigcontext_struct
*context
)
395 now
= localtime(<ime
);
397 CX
= now
->tm_year
+ 1900;
398 DX
= ((now
->tm_mon
+ 1) << 8) | now
->tm_mday
;
402 static void GetSystemTime(struct sigcontext_struct
*context
)
407 gettimeofday(&tv
,NULL
); /* Note use of gettimeofday(), instead of time() */
408 now
= localtime(&tv
.tv_sec
);
410 CX
= (now
->tm_hour
<<8) | now
->tm_min
;
411 DX
= (now
->tm_sec
<<8) | tv
.tv_usec
/10000;
412 /* Note hundredths of seconds */
415 static void GetExtendedErrorInfo(struct sigcontext_struct
*context
)
418 BX
= (ErrorClass
<< 8) | Action
;
419 CH
= ErrorLocus
<< 8;
422 static void CreateFile(struct sigcontext_struct
*context
)
426 if ((handle
= open(GetUnixFileName( pointer(DS
,DX
)),
427 O_CREAT
| O_TRUNC
| O_RDWR
)) == -1) {
434 EAX
= (EAX
& 0xffff0000) | handle
;
438 void OpenExistingFile(struct sigcontext_struct
*context
)
459 if ((handle
= open(GetUnixFileName(pointer(DS
,DX
)), mode
)) == -1) {
468 case 0x00: /* compatability mode */
469 case 0x40: /* DENYNONE */
473 case 0x30: /* DENYREAD */
475 "OpenExistingFile (%s): DENYREAD changed to DENYALL\n",
477 case 0x10: /* DENYALL */
481 case 0x20: /* DENYWRITE */
492 int result
,retries
=sharing_retries
;
494 result
= flock(handle
, lock
| LOCK_NB
);
495 if ( retries
&& (!result
) )
498 for(i
=0;i
<32768*((int)sharing_pause
);i
++)
499 result
++; /* stop the optimizer */
500 for(i
=0;i
<32768*((int)sharing_pause
);i
++)
504 while( (!result
) && (!(retries
--)) );
509 EAX
= (EAX
& 0xffffff00) | ExtendedError
;
518 EAX
= (EAX
& 0xffff0000) | handle
;
522 static void CloseFile(struct sigcontext_struct
*context
)
524 if (close(BX
) == -1) {
535 static void RenameFile(struct sigcontext_struct
*context
)
537 char *newname
, *oldname
;
539 fprintf(stderr
,"int21: renaming %s to %s\n",
540 pointer(DS
,DX
), pointer(ES
,DI
) );
542 oldname
= GetUnixFileName( pointer(DS
,DX
) );
543 newname
= GetUnixFileName( pointer(ES
,DI
) );
545 rename( oldname
, newname
);
550 static void MakeDir(struct sigcontext_struct
*context
)
554 fprintf(stderr
,"int21: makedir %s\n", pointer(DS
,DX
) );
556 if ((dirname
= GetUnixFileName( pointer(DS
,DX
) ))== NULL
) {
562 if (mkdir(dirname
,0) == -1) {
570 static void ChangeDir(struct sigcontext_struct
*context
)
573 char *dirname
= pointer(DS
,DX
);
574 drive
= DOS_GetDefaultDrive();
575 fprintf(stderr
,"int21: changedir %s\n", dirname
);
576 if (dirname
!= NULL
&& dirname
[1] == ':') {
577 drive
= toupper(dirname
[0]) - 'A';
580 DOS_ChangeDir(drive
, dirname
);
583 static void RemoveDir(struct sigcontext_struct
*context
)
587 fprintf(stderr
,"int21: removedir %s\n", pointer(DS
,DX
) );
589 if ((dirname
= GetUnixFileName( pointer(DS
,DX
) ))== NULL
) {
596 if (strcmp(unixname,DosDrives[drive].CurrentDirectory)) {
597 AL = CanNotRemoveCwd;
601 if (rmdir(dirname
) == -1) {
608 static void ExecProgram(struct sigcontext_struct
*context
)
610 execl("wine", GetUnixFileName( pointer(DS
,DX
)) );
613 static void FindNext(struct sigcontext_struct
*context
)
615 struct dosdirent
*dp
;
617 memcpy(&dp
, dta
+0x0d, sizeof(dp
));
620 if ((dp
= DOS_readdir(dp
)) == NULL
) {
621 Error(NoMoreFiles
, EC_MediaError
, EL_Disk
);
626 } while (*(dta
+ 0x0c) != dp
->attribute
);
628 setword(&dta
[0x16], 0x1234); /* time */
629 setword(&dta
[0x18], 0x1234); /* date */
630 setdword(&dta
[0x1a], dp
->filesize
);
631 strncpy(dta
+ 0x1e, dp
->filename
, 13);
638 static void FindFirst(struct sigcontext_struct
*context
)
640 BYTE drive
, *path
= pointer(DS
, DX
);
641 struct dosdirent
*dp
;
643 if (path
[1] == ':') {
644 drive
= (islower(*path
) ? toupper(*path
) : *path
) - 'A';
646 if (!DOS_ValidDrive(drive
)) {
647 Error(InvalidDrive
, EC_MediaError
, EL_Disk
);
653 drive
= DOS_GetDefaultDrive();
656 memset(dta
+ 1 , '?', 11);
657 *(dta
+ 0x0c) = ECX
& (FA_LABEL
| FA_DIREC
);
659 if (ECX
& FA_LABEL
) {
660 /* return volume label */
662 if (DOS_GetVolumeLabel(drive
) != NULL
)
663 strncpy(dta
+ 0x1e, DOS_GetVolumeLabel(drive
), 8);
670 if ((dp
= DOS_opendir(path
)) == NULL
) {
671 Error(PathNotFound
, EC_MediaError
, EL_Disk
);
677 memcpy(dta
+ 0x0d, &dp
, sizeof(dp
));
681 static void GetFileDateTime(struct sigcontext_struct
*context
)
684 struct stat filestat
;
687 if ((filename
= GetUnixFileName( pointer(DS
,DX
) ))== NULL
) {
692 stat(filename
, &filestat
);
694 now
= localtime (&filestat
.st_mtime
);
696 CX
= ((now
->tm_hour
* 0x2000) + (now
->tm_min
* 0x20) + now
->tm_sec
/2);
697 DX
= ((now
->tm_year
* 0x200) + (now
->tm_mon
* 0x20) + now
->tm_mday
);
702 static void SetFileDateTime(struct sigcontext_struct
*context
)
705 struct utimbuf filetime
;
707 filename
= GetUnixFileName( pointer(DS
,DX
) );
709 filetime
.actime
= 0L;
710 filetime
.modtime
= filetime
.actime
;
712 utime(filename
, &filetime
);
716 static void CreateTempFile(struct sigcontext_struct
*context
)
721 sprintf(temp
,"%s\\win%d.tmp",TempDirectory
,(int) getpid());
723 fprintf(stderr
,"CreateTempFile %s\n",temp
);
725 handle
= open(GetUnixFileName(temp
), O_CREAT
| O_TRUNC
| O_RDWR
);
733 strcpy(pointer(DS
,DX
), temp
);
739 static void CreateNewFile(struct sigcontext_struct
*context
)
743 if ((handle
= open(GetUnixFileName( pointer(DS
,DX
) ), O_CREAT
| O_EXCL
| O_RDWR
)) == -1) {
753 static void GetCurrentDirectory(struct sigcontext_struct
*context
)
758 drive
= DOS_GetDefaultDrive();
762 if (!DOS_ValidDrive(drive
)) {
768 strcpy(pointer(DS
,SI
), DOS_GetCurrentDir(drive
) );
772 static void GetDiskSerialNumber(struct sigcontext_struct
*context
)
775 BYTE
*dataptr
= pointer(DS
, DX
);
779 drive
= DOS_GetDefaultDrive();
783 if (!DOS_ValidDrive(drive
)) {
789 DOS_GetSerialNumber(drive
, &serialnumber
);
792 setdword(&dataptr
[2], serialnumber
);
793 strncpy(dataptr
+ 6, DOS_GetVolumeLabel(drive
), 8);
794 strncpy(dataptr
+ 0x11, "FAT16 ", 8);
800 static void SetDiskSerialNumber(struct sigcontext_struct
*context
)
803 BYTE
*dataptr
= pointer(DS
, DX
);
807 drive
= DOS_GetDefaultDrive();
811 if (!DOS_ValidDrive(drive
)) {
817 serialnumber
= dataptr
[1] + (dataptr
[2] << 8) + (dataptr
[3] << 16) +
820 DOS_SetSerialNumber(drive
, serialnumber
);
825 static void DumpFCB(BYTE
*fcb
)
831 for (y
= 0; y
!=2 ; y
++) {
832 for (x
= 0; x
!=15;x
++)
833 fprintf(stderr
, "%02x ", *fcb
++);
834 fprintf(stderr
,"\n");
838 /* microsoft's programmers should be shot for using CP/M style int21
839 calls in Windows for Workgroup's winfile.exe */
841 static void FindFirstFCB(struct sigcontext_struct
*context
)
843 BYTE
*fcb
= pointer(DS
, DX
);
851 drive
= DOS_GetDefaultDrive();
853 if (*(fcb
- 7) == 0xff) {
854 if (*(fcb
- 1) == FA_DIREC
) {
855 /* return volume label */
857 memset(dta
, ' ', 11);
858 if (DOS_GetVolumeLabel(drive
) != NULL
)
859 strncpy(dta
, DOS_GetVolumeLabel(drive
), 8);
860 *(dta
+ 0x0b) = FA_DIREC
;
866 IntBarf(0x21, context
);
869 static void DeleteFileFCB(struct sigcontext_struct
*context
)
871 BYTE
*fcb
= pointer(DS
, DX
);
873 struct dosdirent
*dp
;
874 char temp
[256], *ptr
;
881 drive
= DOS_GetDefaultDrive();
883 strcpy(temp
, DOS_GetCurrentDir(drive
));
885 strncat(temp
, fcb
+ 1, 8);
886 ChopOffWhiteSpace(temp
);
887 strncat(temp
, fcb
+ 9, 3);
888 ChopOffWhiteSpace(temp
);
890 if ((dp
= DOS_opendir(temp
)) == NULL
) {
891 Error(InvalidDrive
, EC_MediaError
, EL_Disk
);
896 strcpy(temp
, DOS_GetCurrentDir(drive
) );
899 ptr
= temp
+ strlen(temp
);
901 while (DOS_readdir(dp
) != NULL
)
903 strcpy(ptr
, dp
->filename
);
904 fprintf(stderr
, "int21: delete file %s\n", temp
);
905 /* unlink(GetUnixFileName(temp)); */
911 static void RenameFileFCB(struct sigcontext_struct
*context
)
913 BYTE
*fcb
= pointer(DS
, DX
);
915 struct dosdirent
*dp
;
916 char temp
[256], oldname
[256], newname
[256], *oldnameptr
, *newnameptr
;
923 drive
= DOS_GetDefaultDrive();
925 strcpy(temp
, DOS_GetCurrentDir(drive
));
927 strncat(temp
, fcb
+ 1, 8);
928 ChopOffWhiteSpace(temp
);
929 strncat(temp
, fcb
+ 9, 3);
930 ChopOffWhiteSpace(temp
);
932 if ((dp
= DOS_opendir(temp
)) == NULL
) {
933 Error(InvalidDrive
, EC_MediaError
, EL_Disk
);
938 strcpy(oldname
, DOS_GetCurrentDir(drive
) );
939 strcat(oldname
, "\\");
940 oldnameptr
= oldname
+ strlen(oldname
);
942 strcpy(newname
, DOS_GetCurrentDir(drive
) );
943 strcat(newname
, "\\");
944 newnameptr
= newname
+ strlen(newname
);
946 while (DOS_readdir(dp
) != NULL
)
948 strcpy(oldnameptr
, dp
->filename
);
949 strcpy(newnameptr
, fcb
+ 1);
950 fprintf(stderr
, "int21: renamefile %s -> %s\n", oldname
, newname
);
958 static void fLock (struct sigcontext_struct
* context
)
961 int result
,retries
=sharing_retries
;
963 f
.l_start
= MAKELONG(DX
,CX
);
964 f
.l_len
= MAKELONG(DI
,SI
);
970 case 0x00: /* LOCK */
974 case 0x01: /* UNLOCK */
979 EAX
= (EAX
& 0xffff0000) | 0x0001;
985 result
= fcntl(BX
,F_SETLK
,&f
);
986 if ( retries
&& (!result
) )
989 for(i
=0;i
<32768*((int)sharing_pause
);i
++)
990 result
++; /* stop the optimizer */
991 for(i
=0;i
<32768*((int)sharing_pause
);i
++)
995 while( (!result
) && (!(retries
--)) );
1000 EAX
= (EAX
& 0xffffff00) | ExtendedError
;
1010 static void GetFileAttribute (struct sigcontext_struct
* context
)
1012 char *filename
= pointer (DS
,DX
);
1016 res
= stat(GetUnixFileName(filename
), &s
);
1020 EAX
= (EAX
& 0xffffff00) | ExtendedError
;
1026 if (S_ISDIR(s
.st_mode
))
1028 if ((S_IWRITE
& s
.st_mode
) != S_IWRITE
)
1031 ECX
= (ECX
& 0xffff0000) | cx
;
1038 /************************************************************************/
1040 int do_int21(struct sigcontext_struct
* context
)
1042 if (Options
.relay_debug
)
1044 printf("int21: AX %04x, BX %04x, CX %04x, DX %04x, "
1045 "SI %04x, DI %04x, DS %04x, ES %04x\n",
1046 AX
, BX
, CX
, DX
, SI
, DI
, DS
, ES
);
1051 GetExtendedErrorInfo(context
);
1059 case 0x00: /* TERMINATE PROGRAM */
1062 case 0x01: /* READ CHARACTER FROM STANDARD INPUT, WITH ECHO */
1063 case 0x02: /* WRITE CHARACTER TO STANDARD OUTPUT */
1064 case 0x03: /* READ CHARACTER FROM STDAUX */
1065 case 0x04: /* WRITE CHARACTER TO STDAUX */
1066 case 0x05: /* WRITE CHARACTER TO PRINTER */
1067 case 0x06: /* DIRECT CONSOLE IN/OUTPUT */
1068 case 0x07: /* DIRECT CHARACTER INPUT, WITHOUT ECHO */
1069 case 0x08: /* CHARACTER INPUT WITHOUT ECHO */
1070 case 0x09: /* WRITE STRING TO STANDARD OUTPUT */
1071 case 0x0a: /* BUFFERED INPUT */
1072 case 0x0b: /* GET STDIN STATUS */
1073 case 0x0c: /* FLUSH BUFFER AND READ STANDARD INPUT */
1074 case 0x0f: /* OPEN FILE USING FCB */
1075 case 0x10: /* CLOSE FILE USING FCB */
1076 case 0x12: /* FIND NEXT MATCHING FILE USING FCB */
1077 case 0x14: /* SEQUENTIAL READ FROM FCB FILE */
1078 case 0x15: /* SEQUENTIAL WRITE TO FCB FILE */
1079 case 0x16: /* CREATE OR TRUNCATE FILE USING FCB */
1080 case 0x21: /* READ RANDOM RECORD FROM FCB FILE */
1081 case 0x22: /* WRITE RANDOM RECORD TO FCB FILE */
1082 case 0x23: /* GET FILE SIZE FOR FCB */
1083 case 0x24: /* SET RANDOM RECORD NUMBER FOR FCB */
1084 case 0x26: /* CREATE NEW PROGRAM SEGMENT PREFIX */
1085 case 0x27: /* RANDOM BLOCK READ FROM FCB FILE */
1086 case 0x28: /* RANDOM BLOCK WRITE TO FCB FILE */
1087 case 0x29: /* PARSE FILENAME INTO FCB */
1088 case 0x2e: /* SET VERIFY FLAG */
1089 IntBarf(0x21, context
);
1092 case 0x18: /* NULL FUNCTIONS FOR CP/M COMPATIBILITY */
1096 case 0x2b: /* SET SYSTEM DATE */
1097 case 0x2d: /* SET SYSTEM TIME */
1098 case 0x37: /* "SWITCHAR" - GET SWITCH CHARACTER
1099 "SWITCHAR" - SET SWITCH CHARACTER
1100 "AVAILDEV" - SPECIFY \DEV\ PREFIX USE */
1101 case 0x54: /* GET VERIFY FLAG */
1102 case 0x6b: /* NULL FUNCTION */
1103 IntBarf(0x21, context
);
1107 case 0x5c: /* "FLOCK" - RECORD LOCKING */
1111 case 0x0d: /* DISK BUFFER FLUSH */
1112 ResetCflag
; /* dos 6+ only */
1115 case 0x0e: /* SELECT DEFAULT DRIVE */
1116 if (!DOS_ValidDrive(DL
)) {
1117 Error (InvalidDrive
, EC_MediaError
, EL_Disk
);
1120 DOS_SetDefaultDrive(DL
);
1121 AX
= MAX_DOS_DRIVES
;
1126 case 0x11: /* FIND FIRST MATCHING FILE USING FCB */
1127 FindFirstFCB(context
);
1130 case 0x13: /* DELETE FILE USING FCB */
1131 DeleteFileFCB(context
);
1134 case 0x17: /* RENAME FILE USING FCB */
1135 RenameFileFCB(context
);
1138 case 0x19: /* GET CURRENT DEFAULT DRIVE */
1139 AL
= DOS_GetDefaultDrive();
1143 case 0x1a: /* SET DISK TRANSFER AREA ADDRESS */
1144 dta
= pointer(DS
, DX
);
1147 case 0x1b: /* GET ALLOCATION INFORMATION FOR DEFAULT DRIVE */
1148 GetDefDriveAllocInfo(context
);
1151 case 0x1c: /* GET ALLOCATION INFORMATION FOR SPECIFIC DRIVE */
1152 GetDriveAllocInfo(context
);
1155 case 0x1f: /* GET DRIVE PARAMETER BLOCK FOR DEFAULT DRIVE */
1156 GetDrivePB(context
);
1159 case 0x25: /* SET INTERRUPT VECTOR */
1160 /* Ignore any attempt to set a segment vector */
1161 fprintf(stderr
, "int21: set interrupt vector %2x (%04x:%04x)\n", AL
, DS
, DX
);
1164 case 0x2a: /* GET SYSTEM DATE */
1165 GetSystemDate(context
);
1168 case 0x2c: /* GET SYSTEM TIME */
1169 GetSystemTime(context
);
1172 case 0x2f: /* GET DISK TRANSFER AREA ADDRESS */
1177 case 0x30: /* GET DOS VERSION */
1179 BX
= 0x0012; /* 0x123456 is Wine's serial # */
1183 case 0x31: /* TERMINATE AND STAY RESIDENT */
1184 IntBarf(0x21, context
);
1187 case 0x32: /* GET DOS DRIVE PARAMETER BLOCK FOR SPECIFIC DRIVE */
1188 GetDrivePB(context
);
1191 case 0x33: /* MULTIPLEXED */
1193 case 0x00: /* GET CURRENT EXTENDED BREAK STATE */
1198 case 0x01: /* SET EXTENDED BREAK STATE */
1201 case 0x02: /* GET AND SET EXTENDED CONTROL-BREAK CHECKING STATE*/
1205 case 0x05: /* GET BOOT DRIVE */
1207 /* c: is Wine's bootdrive */
1210 case 0x06: /* GET TRUE VERSION NUMBER */
1216 IntBarf(0x21, context
);
1221 case 0x34: /* GET ADDRESS OF INDOS FLAG */
1222 ES
= segment(heap
->InDosFlag
);
1223 BX
= offset(heap
->InDosFlag
);
1226 case 0x35: /* GET INTERRUPT VECTOR */
1227 /* Return a NULL segment selector - this will bomb,
1228 if anyone ever tries to use it */
1229 fprintf(stderr
, "int21: get interrupt vector %2x\n", AX
& 0xff);
1234 case 0x36: /* GET FREE DISK SPACE */
1235 GetFreeDiskSpace(context
);
1238 case 0x38: /* GET COUNTRY-SPECIFIC INFORMATION */
1239 AX
= 0x02; /* no country support available */
1243 case 0x39: /* "MKDIR" - CREATE SUBDIRECTORY */
1247 case 0x3a: /* "RMDIR" - REMOVE SUBDIRECTORY */
1251 case 0x3b: /* "CHDIR" - SET CURRENT DIRECTORY */
1255 case 0x3c: /* "CREAT" - CREATE OR TRUNCATE FILE */
1256 CreateFile(context
);
1259 case 0x3d: /* "OPEN" - OPEN EXISTING FILE */
1260 OpenExistingFile(context
);
1263 case 0x3e: /* "CLOSE" - CLOSE FILE */
1267 case 0x3f: /* "READ" - READ FROM FILE OR DEVICE */
1271 case 0x40: /* "WRITE" - WRITE TO FILE OR DEVICE */
1275 case 0x41: /* "UNLINK" - DELETE FILE */
1276 if (unlink( GetUnixFileName( pointer(DS
,DX
)) ) == -1) {
1286 case 0x42: /* "LSEEK" - SET CURRENT FILE POSITION */
1290 case 0x43: /* FILE ATTRIBUTES */
1294 GetFileAttribute(context
);
1302 case 0x44: /* IOCTL */
1306 ioctlGetDeviceInfo(context
);
1309 case 0x09: /* CHECK IF BLOCK DEVICE REMOTE */
1310 EDX
= (EDX
& 0xffff0000) | (1<<9) | (1<<12) | (1<<15);
1314 case 0x0b: /* SET SHARING RETRY COUNT */
1317 EAX
= (EAX
& 0xffff0000) | 0x0001;
1323 sharing_retries
= DX
;
1328 ioctlGenericBlkDevReq(context
);
1332 IntBarf(0x21, context
);
1337 case 0x45: /* "DUP" - DUPLICATE FILE HANDLE */
1338 case 0x46: /* "DUP2", "FORCEDUP" - FORCE DUPLICATE FILE HANDLE */
1343 case 0x47: /* "CWD" - GET CURRENT DIRECTORY */
1344 GetCurrentDirectory(context
);
1346 /* intlist: many Microsoft products for Windows rely on this */
1349 case 0x48: /* ALLOCATE MEMORY */
1350 case 0x49: /* FREE MEMORY */
1351 case 0x4a: /* RESIZE MEMORY BLOCK */
1352 IntBarf(0x21, context
);
1355 case 0x4b: /* "EXEC" - LOAD AND/OR EXECUTE PROGRAM */
1356 ExecProgram(context
);
1359 case 0x4c: /* "EXIT" - TERMINATE WITH RETURN CODE */
1363 case 0x4d: /* GET RETURN CODE */
1364 AL
= NoError
; /* normal exit */
1367 case 0x4e: /* "FINDFIRST" - FIND FIRST MATCHING FILE */
1371 case 0x4f: /* "FINDNEXT" - FIND NEXT MATCHING FILE */
1375 case 0x52: /* "SYSVARS" - GET LIST OF LISTS */
1378 IntBarf(0x21, context
);
1381 case 0x56: /* "RENAME" - RENAME FILE */
1382 RenameFile(context
);
1385 case 0x57: /* FILE DATE AND TIME */
1389 GetFileDateTime(context
);
1392 SetFileDateTime(context
);
1397 case 0x58: /* GET OR SET MEMORY/UMB ALLOCATION STRATEGY */
1413 case 0x5a: /* CREATE TEMPORARY FILE */
1414 CreateTempFile(context
);
1417 case 0x5b: /* CREATE NEW FILE */
1418 CreateNewFile(context
);
1421 case 0x5d: /* NETWORK */
1423 /* network software not installed */
1428 case 0x5f: /* NETWORK */
1431 case 0x07: /* ENABLE DRIVE */
1432 if (!DOS_EnableDrive(DL
))
1434 Error(InvalidDrive
, EC_MediaError
, EL_Disk
);
1444 case 0x08: /* DISABLE DRIVE */
1445 if (!DOS_DisableDrive(DL
))
1447 Error(InvalidDrive
, EC_MediaError
, EL_Disk
);
1458 /* network software not installed */
1465 case 0x60: /* "TRUENAME" - CANONICALIZE FILENAME OR PATH */
1466 strncpy(pointer(ES
,DI
), pointer(DS
,SI
), strlen(pointer(DS
,SI
)) & 0x7f);
1470 case 0x61: /* UNUSED */
1471 case 0x62: /* GET CURRENT PSP ADDRESS */
1472 case 0x63: /* UNUSED */
1473 case 0x64: /* OS/2 DOS BOX */
1474 case 0x65: /* GET EXTENDED COUNTRY INFORMATION */
1475 IntBarf(0x21, context
);
1478 case 0x66: /* GLOBAL CODE PAGE TABLE */
1492 case 0x67: /* SET HANDLE COUNT */
1496 case 0x68: /* "FFLUSH" - COMMIT FILE */
1500 case 0x69: /* DISK SERIAL NUMBER */
1504 GetDiskSerialNumber(context
);
1507 SetDiskSerialNumber(context
);
1512 case 0x6a: /* COMMIT FILE */
1516 case 0xea: /* NOVELL NETWARE - RETURN SHELL VERSION */
1520 IntBarf(0x21, context
);
1527 /**********************************************************************
1532 do_int21((struct sigcontext_struct
*) _CONTEXT
);
1533 ReturnFromRegisterFunc();
1536 void INT21_Init(void)
1541 if ((handle
= GlobalAlloc(GMEM_FIXED
,sizeof(struct DosHeap
))) == 0)
1542 myerror("out of memory");
1544 heap
= (struct DosHeap
*) GlobalLock(handle
);
1545 HEAP_Init(&DosHeapDesc
, heap
, sizeof(struct DosHeap
));
1548 heap
->InDosFlag
= 0;
1549 strcpy(heap
->biosdate
, "01/01/80");