2 * (c) 1993, 1994 Erik Bos
14 #include <sys/types.h>
23 #include "registers.h"
25 #include "prototypes.h"
28 /* #define DEBUG_INT */
31 WORD ExtendedError
, CodePage
= 437;
32 BYTE ErrorClass
, Action
, ErrorLocus
;
40 static struct DosHeap
*heap
;
42 WORD sharing_retries
= 3; /* number of retries at sharing violation */
43 WORD sharing_pause
= 1; /* pause between retries */
45 extern char TempDirectory
[];
47 static int Error(int e
, int class, int el
)
50 Action
= SA_Ask4Retry
;
57 void errno_to_doserr(void)
61 Error (ShareViolation
, EC_Temporary
, EL_Unknown
);
64 Error (InvalidHandle
, EC_AppError
, EL_Unknown
);
67 Error (DiskFull
, EC_MediaError
, EL_Disk
);
72 Error (WriteProtected
, EC_AccessDenied
, EL_Unknown
);
75 Error (LockViolation
, EC_AccessDenied
, EL_Unknown
);
78 Error (FileNotFound
, EC_NotFound
, EL_Unknown
);
81 Error (CanNotMakeDir
, EC_AccessDenied
, EL_Unknown
);
85 Error (NoMoreFiles
, EC_MediaError
, EL_Unknown
);
88 Error (FileExists
, EC_Exists
, EL_Disk
);
91 fprintf(stderr
, "int21: unknown errno %d!\n", errno
);
92 Error (GeneralFailure
, EC_SystemFailure
, EL_Unknown
);
98 static void Barf(struct sigcontext_struct *context)
100 fprintf(stdnimp, "int21: unknown/not implemented parameters:\n");
101 fprintf(stdnimp, "int21: AX %04x, BX %04x, CX %04x, DX %04x, "
102 "SI %04x, DI %04x, DS %04x, ES %04x\n",
103 AX, BX, CX, DX, SI, DI, DS, ES);
107 void ChopOffWhiteSpace(char *string
)
111 for (length
= strlen(string
) ; length
; length
--)
112 if (string
[length
] == ' ')
113 string
[length
] = '\0';
116 static void CreateBPB(int drive
, BYTE
*data
)
121 setword(&data
[3], 0);
123 setword(&data
[6], 240);
124 setword(&data
[8], 64000);
126 setword(&data
[0x0b], 40);
127 setword(&data
[0x0d], 56);
128 setword(&data
[0x0f], 2);
129 setword(&data
[0x11], 0);
130 setword(&data
[0x1f], 800);
132 setword(&data
[0x22], 1);
133 } else { /* 1.44mb */
136 setword(&data
[3], 0);
138 setword(&data
[6], 240);
139 setword(&data
[8], 2880);
141 setword(&data
[0x0b], 6);
142 setword(&data
[0x0d], 18);
143 setword(&data
[0x0f], 2);
144 setword(&data
[0x11], 0);
145 setword(&data
[0x1f], 80);
147 setword(&data
[0x22], 2);
151 static void GetFreeDiskSpace(struct sigcontext_struct
*context
)
157 drive
= DOS_GetDefaultDrive();
161 if (!DOS_ValidDrive(drive
)) {
162 Error(InvalidDrive
, EC_MediaError
, EL_Disk
);
167 if (!DOS_GetFreeSpace(drive
, &size
, &available
)) {
168 Error(GeneralFailure
, EC_MediaError
, EL_Disk
);
176 BX
= (available
/ (CX
* AX
));
177 DX
= (size
/ (CX
* AX
));
181 static void GetDriveAllocInfo(struct sigcontext_struct
*context
)
183 long size
, available
;
186 if (!DOS_ValidDrive(DL
)) {
190 Error (InvalidDrive
, EC_MediaError
, EL_Disk
);
194 if (!DOS_GetFreeSpace(DL
, &size
, &available
)) {
195 Error(GeneralFailure
, EC_MediaError
, EL_Disk
);
202 EDX
= (size
/ (CX
* AX
));
206 DS
= segment(mediaID
);
207 BX
= offset(mediaID
);
211 static void GetDefDriveAllocInfo(struct sigcontext_struct
*context
)
213 DX
= DOS_GetDefaultDrive();
214 GetDriveAllocInfo(context
);
217 static void GetDrivePB(struct sigcontext_struct
*context
)
219 Error (InvalidDrive
, EC_MediaError
, EL_Disk
);
221 /* I'm sorry but I only got networked drives :-) */
224 static void ReadFile(struct sigcontext_struct
*context
)
229 /* can't read from stdout / stderr */
230 if ((BX
== 1) || (BX
== 2)) {
231 Error (InvalidHandle
, EL_Unknown
, EC_Unknown
);
237 ptr
= SAFEMAKEPTR (DS
,DX
);
245 size
= read(BX
, ptr
, CX
);
258 static void WriteFile(struct sigcontext_struct
*context
)
263 ptr
= SAFEMAKEPTR (DS
,DX
);
266 Error (InvalidHandle
, EC_Unknown
, EL_Unknown
);
273 for (x
= 0;x
!= CX
;x
++) {
274 dprintf_int(stddeb
, "%c", *ptr
++);
282 size
= write(BX
, ptr
, CX
);
284 Error (WriteFault
, EC_Unknown
, EL_Unknown
);
301 static void SeekFile(struct sigcontext_struct
*context
)
303 off_t status
, fileoffset
;
306 case 1: fileoffset
= SEEK_CUR
;
308 case 2: fileoffset
= SEEK_END
;
311 case 0: fileoffset
= SEEK_SET
;
314 status
= lseek(BX
, (CX
<< 16) + DX
, fileoffset
);
317 AL
= ExtendedError
; SetCflag
;
321 AX
= (status
& 0xffff);
322 DX
= ((status
>> 16) & 0xffff);
327 static void ioctlGetDeviceInfo(struct sigcontext_struct
*context
)
340 if (fstat(BX
, &sbuf
) < 0)
342 IntBarf(0x21, context
);
348 /* This isn't the right answer, but should be close enough. */
355 static void ioctlGenericBlkDevReq(struct sigcontext_struct
*context
)
357 BYTE
*dataptr
= SAFEMAKEPTR(DS
, DX
);
361 drive
= DOS_GetDefaultDrive();
365 if (!DOS_ValidDrive(drive
)) {
372 IntBarf(0x21, context
);
376 case 0x60: /* get device parameters */
377 /* used by w4wgrp's winfile */
378 memset(dataptr
, 0, 0x26);
380 dataptr
[6] = 0; /* media type */
383 dataptr
[1] = 0x05; /* fixed disk */
384 setword(&dataptr
[2], 0x01); /* non removable */
385 setword(&dataptr
[4], 0x300); /* # of cylinders */
389 dataptr
[1] = 0x07; /* block dev, floppy */
390 setword(&dataptr
[2], 0x02); /* removable */
391 setword(&dataptr
[4], 80); /* # of cylinders */
393 CreateBPB(drive
, &dataptr
[7]);
397 IntBarf(0x21, context
);
401 static void GetSystemDate(struct sigcontext_struct
*context
)
407 now
= localtime(<ime
);
409 CX
= now
->tm_year
+ 1900;
410 DX
= ((now
->tm_mon
+ 1) << 8) | now
->tm_mday
;
414 static void GetSystemTime(struct sigcontext_struct
*context
)
419 gettimeofday(&tv
,NULL
); /* Note use of gettimeofday(), instead of time() */
420 now
= localtime(&tv
.tv_sec
);
422 CX
= (now
->tm_hour
<<8) | now
->tm_min
;
423 DX
= (now
->tm_sec
<<8) | tv
.tv_usec
/10000;
424 /* Note hundredths of seconds */
427 static void GetExtendedErrorInfo(struct sigcontext_struct
*context
)
430 BX
= (ErrorClass
<< 8) | Action
;
431 CH
= ErrorLocus
<< 8;
434 static void CreateFile(struct sigcontext_struct
*context
)
438 if ((handle
= open(DOS_GetUnixFileName( SAFEMAKEPTR(DS
,DX
)),
439 O_CREAT
| O_TRUNC
| O_RDWR
)) == -1) {
446 EAX
= (EAX
& 0xffff0000) | handle
;
450 void OpenExistingFile(struct sigcontext_struct
*context
)
471 if ((handle
= open(DOS_GetUnixFileName(SAFEMAKEPTR(DS
,DX
)), mode
)) == -1) {
480 case 0x00: /* compatability mode */
481 case 0x40: /* DENYNONE */
485 case 0x30: /* DENYREAD */
487 "OpenExistingFile (%s): DENYREAD changed to DENYALL\n",
489 case 0x10: /* DENYALL */
493 case 0x20: /* DENYWRITE */
504 int result
,retries
=sharing_retries
;
506 result
= flock(handle
, lock
| LOCK_NB
);
507 if ( retries
&& (!result
) )
510 for(i
=0;i
<32768*((int)sharing_pause
);i
++)
511 result
++; /* stop the optimizer */
512 for(i
=0;i
<32768*((int)sharing_pause
);i
++)
516 while( (!result
) && (!(retries
--)) );
521 EAX
= (EAX
& 0xffffff00) | ExtendedError
;
530 EAX
= (EAX
& 0xffff0000) | handle
;
534 static void CloseFile(struct sigcontext_struct
*context
)
536 if (close(BX
) == -1) {
547 static void RenameFile(struct sigcontext_struct
*context
)
549 char *newname
, *oldname
;
551 dprintf_int(stddeb
,"int21: renaming %s to %s\n",
552 SAFEMAKEPTR(DS
,DX
), SAFEMAKEPTR(ES
,DI
) );
554 oldname
= DOS_GetUnixFileName( SAFEMAKEPTR(DS
,DX
) );
555 newname
= DOS_GetUnixFileName( SAFEMAKEPTR(ES
,DI
) );
557 rename( oldname
, newname
);
562 static void MakeDir(struct sigcontext_struct
*context
)
566 dprintf_int(stddeb
,"int21: makedir %s\n", SAFEMAKEPTR(DS
,DX
) );
568 if ((dirname
= DOS_GetUnixFileName( SAFEMAKEPTR(DS
,DX
) ))== NULL
) {
574 if (mkdir(dirname
,0) == -1) {
582 static void ChangeDir(struct sigcontext_struct
*context
)
585 char *dirname
= SAFEMAKEPTR(DS
,DX
);
586 drive
= DOS_GetDefaultDrive();
587 dprintf_int(stddeb
,"int21: changedir %s\n", dirname
);
588 if (dirname
!= NULL
&& dirname
[1] == ':') {
589 drive
= toupper(dirname
[0]) - 'A';
592 if (!DOS_ChangeDir(drive
, dirname
))
599 static void RemoveDir(struct sigcontext_struct
*context
)
603 dprintf_int(stddeb
,"int21: removedir %s\n", SAFEMAKEPTR(DS
,DX
) );
605 if ((dirname
= DOS_GetUnixFileName( SAFEMAKEPTR(DS
,DX
) ))== NULL
) {
612 if (strcmp(unixname,DosDrives[drive].CurrentDirectory)) {
613 AL = CanNotRemoveCwd;
617 if (rmdir(dirname
) == -1) {
624 static void ExecProgram(struct sigcontext_struct
*context
)
626 execl("wine", DOS_GetUnixFileName( SAFEMAKEPTR(DS
,DX
)) );
629 static void FindNext(struct sigcontext_struct
*context
)
631 struct dosdirent
*dp
;
633 memcpy(&dp
, dta
+0x0d, sizeof(dp
));
636 if ((dp
= DOS_readdir(dp
)) == NULL
) {
637 Error(NoMoreFiles
, EC_MediaError
, EL_Disk
);
642 } /* while (*(dta + 0x0c) != dp->attribute);*/
643 while ( ( dp
->search_attribute
& dp
->attribute
) != dp
->attribute
);
645 *(dta
+ 0x15) = dp
->attribute
;
646 setword(&dta
[0x16], 0x1234); /* time */
647 setword(&dta
[0x18], 0x1234); /* date */
648 setdword(&dta
[0x1a], dp
->filesize
);
649 strncpy(dta
+ 0x1e, dp
->filename
, 13);
656 static void FindFirst(struct sigcontext_struct
*context
)
658 BYTE drive
, *path
= SAFEMAKEPTR(DS
, DX
);
659 struct dosdirent
*dp
;
661 if ((*path
)&&(path
[1] == ':')) {
662 drive
= (islower(*path
) ? toupper(*path
) : *path
) - 'A';
664 if (!DOS_ValidDrive(drive
)) {
665 Error(InvalidDrive
, EC_MediaError
, EL_Disk
);
671 drive
= DOS_GetDefaultDrive();
674 memset(dta
+ 1 , '?', 11);
675 *(dta
+ 0x0c) = ECX
& (FA_LABEL
| FA_DIREC
);
677 if (ECX
& FA_LABEL
) {
678 /* return volume label */
680 if (DOS_GetVolumeLabel(drive
) != NULL
)
681 strncpy(dta
+ 0x1e, DOS_GetVolumeLabel(drive
), 8);
688 if ((dp
= DOS_opendir(path
)) == NULL
) {
689 Error(PathNotFound
, EC_MediaError
, EL_Disk
);
695 dp
->search_attribute
= ECX
& (FA_LABEL
| FA_DIREC
);
696 memcpy(dta
+ 0x0d, &dp
, sizeof(dp
));
700 static void GetFileDateTime(struct sigcontext_struct
*context
)
703 struct stat filestat
;
706 if ((filename
= DOS_GetUnixFileName( SAFEMAKEPTR(DS
,DX
) ))== NULL
) {
711 stat(filename
, &filestat
);
713 now
= localtime (&filestat
.st_mtime
);
715 CX
= ((now
->tm_hour
* 0x2000) + (now
->tm_min
* 0x20) + now
->tm_sec
/2);
716 DX
= ((now
->tm_year
* 0x200) + (now
->tm_mon
* 0x20) + now
->tm_mday
);
721 static void SetFileDateTime(struct sigcontext_struct
*context
)
724 struct utimbuf filetime
;
726 filename
= DOS_GetUnixFileName( SAFEMAKEPTR(DS
,DX
) );
728 filetime
.actime
= 0L;
729 filetime
.modtime
= filetime
.actime
;
731 utime(filename
, &filetime
);
735 static void CreateTempFile(struct sigcontext_struct
*context
)
740 sprintf(temp
,"%s\\win%d.tmp",TempDirectory
,(int) getpid());
742 dprintf_int(stddeb
,"CreateTempFile %s\n",temp
);
744 handle
= open(DOS_GetUnixFileName(temp
), O_CREAT
| O_TRUNC
| O_RDWR
);
752 strcpy(SAFEMAKEPTR(DS
,DX
), temp
);
758 static void CreateNewFile(struct sigcontext_struct
*context
)
762 if ((handle
= open(DOS_GetUnixFileName( SAFEMAKEPTR(DS
,DX
) ), O_CREAT
| O_EXCL
| O_RDWR
)) == -1) {
772 static void GetCurrentDirectory(struct sigcontext_struct
*context
)
777 drive
= DOS_GetDefaultDrive();
781 if (!DOS_ValidDrive(drive
)) {
787 strcpy(SAFEMAKEPTR(DS
,SI
), DOS_GetCurrentDir(drive
) );
791 static void GetDiskSerialNumber(struct sigcontext_struct
*context
)
794 BYTE
*dataptr
= SAFEMAKEPTR(DS
, DX
);
798 drive
= DOS_GetDefaultDrive();
802 if (!DOS_ValidDrive(drive
)) {
808 DOS_GetSerialNumber(drive
, &serialnumber
);
811 setdword(&dataptr
[2], serialnumber
);
812 strncpy(dataptr
+ 6, DOS_GetVolumeLabel(drive
), 8);
813 strncpy(dataptr
+ 0x11, "FAT16 ", 8);
819 static void SetDiskSerialNumber(struct sigcontext_struct
*context
)
822 BYTE
*dataptr
= SAFEMAKEPTR(DS
, DX
);
826 drive
= DOS_GetDefaultDrive();
830 if (!DOS_ValidDrive(drive
)) {
836 serialnumber
= dataptr
[1] + (dataptr
[2] << 8) + (dataptr
[3] << 16) +
839 DOS_SetSerialNumber(drive
, serialnumber
);
844 static void DumpFCB(BYTE
*fcb
)
850 for (y
= 0; y
!=2 ; y
++) {
851 for (x
= 0; x
!=15;x
++)
852 dprintf_int(stddeb
, "%02x ", *fcb
++);
853 dprintf_int(stddeb
,"\n");
857 /* microsoft's programmers should be shot for using CP/M style int21
858 calls in Windows for Workgroup's winfile.exe */
860 static void FindFirstFCB(struct sigcontext_struct
*context
)
862 BYTE
*fcb
= SAFEMAKEPTR(DS
, DX
);
863 struct fcb
*standard_fcb
;
864 struct fcb
*output_fcb
;
872 standard_fcb
= (struct fcb
*)(fcb
+ 7);
873 output_fcb
= (struct fcb
*)(dta
+ 7);
878 standard_fcb
= (struct fcb
*)fcb
;
879 output_fcb
= (struct fcb
*)dta
;
882 if (standard_fcb
->drive
)
884 drive
= standard_fcb
->drive
- 1;
885 if (!DOS_ValidDrive(drive
))
887 Error (InvalidDrive
, EC_MediaError
, EL_Disk
);
893 drive
= DOS_GetDefaultDrive();
895 output_fcb
->drive
= drive
;
899 if (*(fcb
+6) & FA_LABEL
) /* return volume label */
902 memset(&output_fcb
->name
, ' ', 11);
903 if (DOS_GetVolumeLabel(drive
) != NULL
)
905 strncpy(output_fcb
->name
, DOS_GetVolumeLabel(drive
), 11);
912 strncpy(output_fcb
->name
, standard_fcb
->name
, 11);
914 *(dta
+6) = ( *(fcb
+6) & (!FA_DIREC
));
916 sprintf(path
,"%c:*.*",drive
+'A');
917 if ((output_fcb
->directory
= DOS_opendir(path
))==NULL
)
919 Error (PathNotFound
, EC_MediaError
, EL_Disk
);
927 static void DeleteFileFCB(struct sigcontext_struct
*context
)
929 BYTE
*fcb
= SAFEMAKEPTR(DS
, DX
);
931 struct dosdirent
*dp
;
932 char temp
[256], *ptr
;
939 drive
= DOS_GetDefaultDrive();
941 strcpy(temp
, DOS_GetCurrentDir(drive
));
943 strncat(temp
, fcb
+ 1, 8);
944 ChopOffWhiteSpace(temp
);
945 strncat(temp
, fcb
+ 9, 3);
946 ChopOffWhiteSpace(temp
);
948 if ((dp
= DOS_opendir(temp
)) == NULL
) {
949 Error(InvalidDrive
, EC_MediaError
, EL_Disk
);
954 strcpy(temp
, DOS_GetCurrentDir(drive
) );
957 ptr
= temp
+ strlen(temp
);
959 while (DOS_readdir(dp
) != NULL
)
961 strcpy(ptr
, dp
->filename
);
962 dprintf_int(stddeb
, "int21: delete file %s\n", temp
);
963 /* unlink(DOS_GetUnixFileName(temp)); */
969 static void RenameFileFCB(struct sigcontext_struct
*context
)
971 BYTE
*fcb
= SAFEMAKEPTR(DS
, DX
);
973 struct dosdirent
*dp
;
974 char temp
[256], oldname
[256], newname
[256], *oldnameptr
, *newnameptr
;
981 drive
= DOS_GetDefaultDrive();
983 strcpy(temp
, DOS_GetCurrentDir(drive
));
985 strncat(temp
, fcb
+ 1, 8);
986 ChopOffWhiteSpace(temp
);
987 strncat(temp
, fcb
+ 9, 3);
988 ChopOffWhiteSpace(temp
);
990 if ((dp
= DOS_opendir(temp
)) == NULL
) {
991 Error(InvalidDrive
, EC_MediaError
, EL_Disk
);
996 strcpy(oldname
, DOS_GetCurrentDir(drive
) );
997 strcat(oldname
, "\\");
998 oldnameptr
= oldname
+ strlen(oldname
);
1000 strcpy(newname
, DOS_GetCurrentDir(drive
) );
1001 strcat(newname
, "\\");
1002 newnameptr
= newname
+ strlen(newname
);
1004 while (DOS_readdir(dp
) != NULL
)
1006 strcpy(oldnameptr
, dp
->filename
);
1007 strcpy(newnameptr
, fcb
+ 1);
1008 dprintf_int(stddeb
, "int21: renamefile %s -> %s\n",
1017 static void fLock (struct sigcontext_struct
* context
)
1020 int result
,retries
=sharing_retries
;
1022 f
.l_start
= MAKELONG(DX
,CX
);
1023 f
.l_len
= MAKELONG(DI
,SI
);
1027 switch ( AX
& 0xff )
1029 case 0x00: /* LOCK */
1033 case 0x01: /* UNLOCK */
1038 EAX
= (EAX
& 0xffff0000) | 0x0001;
1044 result
= fcntl(BX
,F_SETLK
,&f
);
1045 if ( retries
&& (!result
) )
1048 for(i
=0;i
<32768*((int)sharing_pause
);i
++)
1049 result
++; /* stop the optimizer */
1050 for(i
=0;i
<32768*((int)sharing_pause
);i
++)
1054 while( (!result
) && (!(retries
--)) );
1059 EAX
= (EAX
& 0xffffff00) | ExtendedError
;
1069 static void GetFileAttribute (struct sigcontext_struct
* context
)
1071 char *filename
= SAFEMAKEPTR (DS
,DX
);
1075 res
= stat(DOS_GetUnixFileName(filename
), &s
);
1079 EAX
= (EAX
& 0xffffff00) | ExtendedError
;
1085 if (S_ISDIR(s
.st_mode
))
1087 if ((S_IWRITE
& s
.st_mode
) != S_IWRITE
)
1090 ECX
= (ECX
& 0xffff0000) | cx
;
1097 /************************************************************************/
1099 int do_int21(struct sigcontext_struct
* context
)
1101 if (debugging_relay
)
1103 fprintf(stddeb
,"int21: AX %04x, BX %04x, CX %04x, DX %04x, "
1104 "SI %04x, DI %04x, DS %04x, ES %04x\n",
1105 AX
, BX
, CX
, DX
, SI
, DI
, DS
, ES
);
1110 GetExtendedErrorInfo(context
);
1118 case 0x00: /* TERMINATE PROGRAM */
1121 case 0x01: /* READ CHARACTER FROM STANDARD INPUT, WITH ECHO */
1122 case 0x02: /* WRITE CHARACTER TO STANDARD OUTPUT */
1123 case 0x03: /* READ CHARACTER FROM STDAUX */
1124 case 0x04: /* WRITE CHARACTER TO STDAUX */
1125 case 0x05: /* WRITE CHARACTER TO PRINTER */
1126 case 0x06: /* DIRECT CONSOLE IN/OUTPUT */
1127 case 0x07: /* DIRECT CHARACTER INPUT, WITHOUT ECHO */
1128 case 0x08: /* CHARACTER INPUT WITHOUT ECHO */
1129 case 0x09: /* WRITE STRING TO STANDARD OUTPUT */
1130 case 0x0a: /* BUFFERED INPUT */
1131 case 0x0b: /* GET STDIN STATUS */
1132 case 0x0c: /* FLUSH BUFFER AND READ STANDARD INPUT */
1133 case 0x0f: /* OPEN FILE USING FCB */
1134 case 0x10: /* CLOSE FILE USING FCB */
1135 case 0x12: /* FIND NEXT MATCHING FILE USING FCB */
1136 case 0x14: /* SEQUENTIAL READ FROM FCB FILE */
1137 case 0x15: /* SEQUENTIAL WRITE TO FCB FILE */
1138 case 0x16: /* CREATE OR TRUNCATE FILE USING FCB */
1139 case 0x21: /* READ RANDOM RECORD FROM FCB FILE */
1140 case 0x22: /* WRITE RANDOM RECORD TO FCB FILE */
1141 case 0x23: /* GET FILE SIZE FOR FCB */
1142 case 0x24: /* SET RANDOM RECORD NUMBER FOR FCB */
1143 case 0x26: /* CREATE NEW PROGRAM SEGMENT PREFIX */
1144 case 0x27: /* RANDOM BLOCK READ FROM FCB FILE */
1145 case 0x28: /* RANDOM BLOCK WRITE TO FCB FILE */
1146 case 0x29: /* PARSE FILENAME INTO FCB */
1147 case 0x2e: /* SET VERIFY FLAG */
1148 IntBarf(0x21, context
);
1151 case 0x18: /* NULL FUNCTIONS FOR CP/M COMPATIBILITY */
1155 case 0x2b: /* SET SYSTEM DATE */
1156 case 0x2d: /* SET SYSTEM TIME */
1157 case 0x37: /* "SWITCHAR" - GET SWITCH CHARACTER
1158 "SWITCHAR" - SET SWITCH CHARACTER
1159 "AVAILDEV" - SPECIFY \DEV\ PREFIX USE */
1160 case 0x54: /* GET VERIFY FLAG */
1161 case 0x6b: /* NULL FUNCTION */
1162 IntBarf(0x21, context
);
1166 case 0x5c: /* "FLOCK" - RECORD LOCKING */
1170 case 0x0d: /* DISK BUFFER FLUSH */
1171 ResetCflag
; /* dos 6+ only */
1174 case 0x0e: /* SELECT DEFAULT DRIVE */
1175 if (!DOS_ValidDrive(DL
)) {
1176 Error (InvalidDrive
, EC_MediaError
, EL_Disk
);
1179 DOS_SetDefaultDrive(DL
);
1180 AX
= MAX_DOS_DRIVES
;
1185 case 0x11: /* FIND FIRST MATCHING FILE USING FCB */
1186 FindFirstFCB(context
);
1189 case 0x13: /* DELETE FILE USING FCB */
1190 DeleteFileFCB(context
);
1193 case 0x17: /* RENAME FILE USING FCB */
1194 RenameFileFCB(context
);
1197 case 0x19: /* GET CURRENT DEFAULT DRIVE */
1198 AL
= DOS_GetDefaultDrive();
1202 case 0x1a: /* SET DISK TRANSFER AREA ADDRESS */
1203 dta
= SAFEMAKEPTR(DS
, DX
);
1206 case 0x1b: /* GET ALLOCATION INFORMATION FOR DEFAULT DRIVE */
1207 GetDefDriveAllocInfo(context
);
1210 case 0x1c: /* GET ALLOCATION INFORMATION FOR SPECIFIC DRIVE */
1211 GetDriveAllocInfo(context
);
1214 case 0x1f: /* GET DRIVE PARAMETER BLOCK FOR DEFAULT DRIVE */
1215 GetDrivePB(context
);
1218 case 0x25: /* SET INTERRUPT VECTOR */
1219 /* Ignore any attempt to set a segment vector */
1220 dprintf_int(stdnimp
,
1221 "int21: set interrupt vector %2x (%04x:%04x)\n",
1225 case 0x2a: /* GET SYSTEM DATE */
1226 GetSystemDate(context
);
1229 case 0x2c: /* GET SYSTEM TIME */
1230 GetSystemTime(context
);
1233 case 0x2f: /* GET DISK TRANSFER AREA ADDRESS */
1238 case 0x30: /* GET DOS VERSION */
1240 BX
= 0x0012; /* 0x123456 is Wine's serial # */
1244 case 0x31: /* TERMINATE AND STAY RESIDENT */
1245 IntBarf(0x21, context
);
1248 case 0x32: /* GET DOS DRIVE PARAMETER BLOCK FOR SPECIFIC DRIVE */
1249 GetDrivePB(context
);
1252 case 0x33: /* MULTIPLEXED */
1254 case 0x00: /* GET CURRENT EXTENDED BREAK STATE */
1259 case 0x01: /* SET EXTENDED BREAK STATE */
1262 case 0x02: /* GET AND SET EXTENDED CONTROL-BREAK CHECKING STATE*/
1266 case 0x05: /* GET BOOT DRIVE */
1268 /* c: is Wine's bootdrive */
1271 case 0x06: /* GET TRUE VERSION NUMBER */
1277 IntBarf(0x21, context
);
1282 case 0x34: /* GET ADDRESS OF INDOS FLAG */
1283 ES
= segment(heap
->InDosFlag
);
1284 BX
= offset(heap
->InDosFlag
);
1287 case 0x35: /* GET INTERRUPT VECTOR */
1288 /* Return a NULL segment selector - this will bomb,
1289 if anyone ever tries to use it */
1290 dprintf_int(stdnimp
, "int21: get interrupt vector %2x\n",
1296 case 0x36: /* GET FREE DISK SPACE */
1297 GetFreeDiskSpace(context
);
1300 case 0x38: /* GET COUNTRY-SPECIFIC INFORMATION */
1301 AX
= 0x02; /* no country support available */
1305 case 0x39: /* "MKDIR" - CREATE SUBDIRECTORY */
1309 case 0x3a: /* "RMDIR" - REMOVE SUBDIRECTORY */
1313 case 0x3b: /* "CHDIR" - SET CURRENT DIRECTORY */
1317 case 0x3c: /* "CREAT" - CREATE OR TRUNCATE FILE */
1318 CreateFile(context
);
1321 case 0x3d: /* "OPEN" - OPEN EXISTING FILE */
1322 OpenExistingFile(context
);
1325 case 0x3e: /* "CLOSE" - CLOSE FILE */
1329 case 0x3f: /* "READ" - READ FROM FILE OR DEVICE */
1333 case 0x40: /* "WRITE" - WRITE TO FILE OR DEVICE */
1337 case 0x41: /* "UNLINK" - DELETE FILE */
1338 if (unlink( DOS_GetUnixFileName( SAFEMAKEPTR(DS
,DX
)) ) == -1) {
1348 case 0x42: /* "LSEEK" - SET CURRENT FILE POSITION */
1352 case 0x43: /* FILE ATTRIBUTES */
1356 GetFileAttribute(context
);
1364 case 0x44: /* IOCTL */
1368 ioctlGetDeviceInfo(context
);
1371 case 0x09: /* CHECK IF BLOCK DEVICE REMOTE */
1372 EDX
= (EDX
& 0xffff0000) | (1<<9) | (1<<12) | (1<<15);
1376 case 0x0b: /* SET SHARING RETRY COUNT */
1379 EAX
= (EAX
& 0xffff0000) | 0x0001;
1385 sharing_retries
= DX
;
1390 ioctlGenericBlkDevReq(context
);
1394 IntBarf(0x21, context
);
1399 case 0x45: /* "DUP" - DUPLICATE FILE HANDLE */
1400 case 0x46: /* "DUP2", "FORCEDUP" - FORCE DUPLICATE FILE HANDLE */
1405 case 0x47: /* "CWD" - GET CURRENT DIRECTORY */
1406 GetCurrentDirectory(context
);
1408 /* intlist: many Microsoft products for Windows rely on this */
1411 case 0x48: /* ALLOCATE MEMORY */
1412 case 0x49: /* FREE MEMORY */
1413 case 0x4a: /* RESIZE MEMORY BLOCK */
1414 IntBarf(0x21, context
);
1417 case 0x4b: /* "EXEC" - LOAD AND/OR EXECUTE PROGRAM */
1418 ExecProgram(context
);
1421 case 0x4c: /* "EXIT" - TERMINATE WITH RETURN CODE */
1425 case 0x4d: /* GET RETURN CODE */
1426 AL
= NoError
; /* normal exit */
1429 case 0x4e: /* "FINDFIRST" - FIND FIRST MATCHING FILE */
1433 case 0x4f: /* "FINDNEXT" - FIND NEXT MATCHING FILE */
1437 case 0x52: /* "SYSVARS" - GET LIST OF LISTS */
1440 IntBarf(0x21, context
);
1443 case 0x56: /* "RENAME" - RENAME FILE */
1444 RenameFile(context
);
1447 case 0x57: /* FILE DATE AND TIME */
1451 GetFileDateTime(context
);
1454 SetFileDateTime(context
);
1459 case 0x58: /* GET OR SET MEMORY/UMB ALLOCATION STRATEGY */
1475 case 0x5a: /* CREATE TEMPORARY FILE */
1476 CreateTempFile(context
);
1479 case 0x5b: /* CREATE NEW FILE */
1480 CreateNewFile(context
);
1483 case 0x5d: /* NETWORK */
1485 /* network software not installed */
1490 case 0x5f: /* NETWORK */
1493 case 0x07: /* ENABLE DRIVE */
1494 if (!DOS_EnableDrive(DL
))
1496 Error(InvalidDrive
, EC_MediaError
, EL_Disk
);
1506 case 0x08: /* DISABLE DRIVE */
1507 if (!DOS_DisableDrive(DL
))
1509 Error(InvalidDrive
, EC_MediaError
, EL_Disk
);
1520 /* network software not installed */
1527 case 0x60: /* "TRUENAME" - CANONICALIZE FILENAME OR PATH */
1528 strncpy(SAFEMAKEPTR(ES
,DI
), SAFEMAKEPTR(DS
,SI
), strlen(SAFEMAKEPTR(DS
,SI
)) & 0x7f);
1532 case 0x61: /* UNUSED */
1533 case 0x62: /* GET CURRENT PSP ADDRESS */
1534 case 0x63: /* UNUSED */
1535 case 0x64: /* OS/2 DOS BOX */
1536 case 0x65: /* GET EXTENDED COUNTRY INFORMATION */
1537 IntBarf(0x21, context
);
1540 case 0x66: /* GLOBAL CODE PAGE TABLE */
1554 case 0x67: /* SET HANDLE COUNT */
1558 case 0x68: /* "FFLUSH" - COMMIT FILE */
1562 case 0x69: /* DISK SERIAL NUMBER */
1566 GetDiskSerialNumber(context
);
1569 SetDiskSerialNumber(context
);
1574 case 0x6a: /* COMMIT FILE */
1578 case 0xea: /* NOVELL NETWARE - RETURN SHELL VERSION */
1582 IntBarf(0x21, context
);
1589 /**********************************************************************
1594 do_int21((struct sigcontext_struct
*) _CONTEXT
);
1595 ReturnFromRegisterFunc();
1598 void INT21_Init(void)
1603 if ((handle
= GlobalAlloc(GMEM_FIXED
,sizeof(struct DosHeap
))) == 0)
1604 myerror("out of memory");
1606 heap
= (struct DosHeap
*) GlobalLock(handle
);
1607 HEAP_Init(&DosHeapDesc
, heap
, sizeof(struct DosHeap
));
1610 heap
->InDosFlag
= 0;
1611 strcpy(heap
->biosdate
, "01/01/80");