12 #include <sys/mount.h>
25 static char Copyright
[] = "int21.c, copyright Erik Bos, 1993";
27 extern struct DosDriveStruct DosDrives
[];
28 extern int CurrentDrive
;
29 extern void ParseDOSFileName();
33 WORD ExtendedError
, CodePage
= 437;
34 BYTE ErrorClass
, Action
, ErrorLocus
;
36 void Error(int e
, int class, int el
)
40 Action
= SA_Ask4Retry
;
44 void GetFreeDiskSpace(struct sigcontext_struct
*context
)
53 drive
= (DX
& 0xff) - 1;
55 if (!ValidDrive(drive
)) {
56 Error(InvalidDrive
, EC_MediaError
, EL_Disk
);
62 if (statfs(DosDrives
[drive
].RootDirectory
, &info
) < 0) {
63 fprintf(stderr
,"cannot do statfs(%s)\n",DosDrives
[drive
].RootDirectory
);
64 Error(GeneralFailure
, EC_MediaError
, EL_Disk
);
69 size
= info
.f_bsize
* info
.f_blocks
/ 1024;
70 avail
= info
.f_bavail
* info
.f_bsize
/ 1024;
73 fprintf(stderr
,"statfs: size: %8d avail: %8d\n",size
,avail
);
76 AX
= SectorsPerCluster
;
79 BX
= (avail
/ (CX
* AX
));
80 DX
= (size
/ (CX
* AX
));
85 void SetDefaultDrive(struct sigcontext_struct
*context
)
87 if ((DX
& 0xff) < MAX_DRIVES
) {
88 CurrentDrive
= DX
& 0xff;
90 AX
|= MAX_DRIVES
; /* # of valid drive letters */
93 Error (InvalidDrive
, EC_MediaError
, EL_Disk
);
96 void GetDefaultDrive(struct sigcontext_struct
*context
)
103 void GetDriveAllocInfo(struct sigcontext_struct
*context
)
112 if (!ValidDrive(drive
)) {
113 AX
= SectorsPerCluster
;
116 Error (InvalidDrive
, EC_MediaError
, EL_Disk
);
121 if (statfs(DosDrives
[drive
].RootDirectory
, &info
) < 0) {
122 fprintf(stderr
,"cannot do statfs(%s)\n",DosDrives
[drive
].RootDirectory
);
123 Error(GeneralFailure
, EC_MediaError
, EL_Disk
);
128 size
= info
.f_bsize
* info
.f_blocks
/ 1024;
131 fprintf(stderr
,"statfs: size: %8d\n",size
);
134 AX
= SectorsPerCluster
;
136 DX
= (size
/ (CX
* AX
));
140 DS
= segment(mediaID
);
141 BX
= offset(mediaID
);
146 void GetDefDriveAllocInfo(struct sigcontext_struct
*context
)
149 GetDriveAllocInfo(context
);
152 void GetDrivePB(struct sigcontext_struct
*context
)
154 Error (InvalidDrive
, EC_MediaError
, EL_Disk
);
155 AX
= 0xff; /* I'm sorry but I only got networked drives :-) */
158 void ReadFile(struct sigcontext_struct
*context
)
163 /* can't read from stdout / stderr */
165 if (((BX
& 0xffff) == 1) ||((BX
& 0xffff) == 2)) {
166 Error (InvalidHandle
, EL_Unknown
, EC_Unknown
);
172 ptr
= (char *) pointer (DS
,DX
);
174 if ((BX
& 0xffff) == 0) {
181 size
= read(BX
, ptr
, CX
);
183 Error (ReadFault
, EC_Unknown
, EL_Unknown
);
191 Error (ShareViolation
, EC_Temporary
, EL_Unknown
);
194 Error (InvalidHandle
, EC_AppError
, EL_Unknown
);
197 Error (GeneralFailure
, EC_SystemFailure
, EL_Unknown
);
210 void WriteFile(struct sigcontext_struct
*context
)
215 ptr
= (char *) pointer (DS
,DX
);
217 if ((BX
& 0xffff) == 0) {
218 Error (InvalidHandle
, EC_Unknown
, EL_Unknown
);
224 if ((BX
& 0xffff) < 3) {
225 for (x
= 0;x
!= CX
;x
++) {
226 fprintf(stderr
, "%c", *ptr
++);
234 size
= write(BX
, ptr
, CX
);
236 Error (WriteFault
, EC_Unknown
, EL_Unknown
);
244 Error (ShareViolation
, EC_Temporary
, EL_Unknown
);
247 Error (InvalidHandle
, EC_AppError
, EL_Unknown
);
250 Error (DiskFull
, EC_MediaError
, EL_Disk
);
253 Error (GeneralFailure
, EC_SystemFailure
, EL_Unknown
);
266 void UnlinkFile(struct sigcontext_struct
*context
)
268 char UnixFileName
[256];
271 ParseDOSFileName(UnixFileName
, (char *) pointer(DS
,DX
), &drive
);
274 status
= unlink((char *) pointer(DS
,DX
));
280 Error (WriteProtected
, EC_AccessDenied
, EL_Unknown
);
283 Error (LockViolation
, EC_AccessDenied
, EL_Unknown
);
286 Error (ShareViolation
, EC_Temporary
, EL_Unknown
);
289 Error (FileNotFound
, EC_NotFound
, EL_Unknown
);
292 Error (GeneralFailure
, EC_SystemFailure
, EL_Unknown
);
304 void SeekFile(struct sigcontext_struct
*context
)
306 char UnixFileName
[256];
307 int drive
, handle
, status
, fileoffset
;
310 ParseDOSFileName(UnixFileName
, (char *) pointer(DS
,DX
), &drive
);
314 case 1: fileoffset
= SEEK_CUR
;
316 case 2: fileoffset
= SEEK_END
;
319 case 0: fileoffset
= SEEK_SET
;
322 status
= lseek(BX
, (CX
* 0x100) + DX
, fileoffset
);
326 Error (InvalidHandle
, EC_AppError
, EL_Unknown
);
329 Error (DataInvalid
, EC_AppError
, EL_Unknown
);
332 Error (GeneralFailure
, EC_SystemFailure
, EL_Unknown
);
344 void GetFileAttributes(struct sigcontext_struct
*context
)
346 char UnixFileName
[256];
349 ParseDOSFileName(UnixFileName
, (char *) pointer(DS
,DX
), &drive
);
357 void SetFileAttributes(struct sigcontext_struct
*context
)
362 void DosIOCTL(struct sigcontext_struct
*context
)
368 void DupeFileHandle(struct sigcontext_struct
*context
)
374 void GetSystemDate(struct sigcontext_struct
*context
)
380 now
= localtime(<ime
);
382 CX
= now
->tm_year
+ 1900;
383 DX
= ((now
->tm_mon
+ 1) << 8) | now
->tm_mday
;
388 void GetSystemTime(struct sigcontext_struct
*context
)
394 now
= localtime(<ime
);
396 CX
= (now
->tm_hour
<< 8) | now
->tm_min
;
397 DX
= now
->tm_sec
<< 8;
400 void GetExtendedErrorInfo(struct sigcontext_struct
*context
)
403 BX
= (0x100 * ErrorClass
) | Action
;
405 CX
|= (0x100 * ErrorLocus
);
408 void GetInDosFlag(struct sigcontext_struct
*context
)
410 const BYTE InDosFlag
= 0;
412 ES
= segment(InDosFlag
);
413 BX
= offset(InDosFlag
);
416 void CreateFile(struct sigcontext_struct
*context
)
418 char UnixFileName
[256];
421 ParseDOSFileName(UnixFileName
, (char *) pointer(DS
,DX
), &drive
);
424 handle
= open(UnixFileName
, O_CREAT
| O_TRUNC
);
431 Error (WriteProtected
, EC_AccessDenied
, EL_Unknown
);
434 Error (CanNotMakeDir
, EC_AccessDenied
, EL_Unknown
);
438 Error (NoMoreFiles
, EC_MediaError
, EL_Unknown
);
440 Error (FileExists
, EC_Exists
, EL_Disk
);
443 Error (DiskFull
, EC_MediaError
, EL_Disk
);
446 Error (GeneralFailure
, EC_SystemFailure
, EL_Unknown
);
460 void OpenExistingFile(struct sigcontext_struct
*context
)
462 char UnixFileName
[256];
465 ParseDOSFileName(UnixFileName
, (char *) pointer(DS
,DX
), &drive
);
468 handle
= open(UnixFileName
, O_RDWR
);
475 Error (WriteProtected
, EC_AccessDenied
, EL_Unknown
);
478 Error (CanNotMakeDir
, EC_AccessDenied
, EL_Unknown
);
482 Error (NoMoreFiles
, EC_MediaError
, EL_Unknown
);
484 Error (FileExists
, EC_Exists
, EL_Disk
);
487 Error (DiskFull
, EC_MediaError
, EL_Disk
);
490 Error (FileNotFound
, EC_MediaError
, EL_Disk
);
493 Error (GeneralFailure
, EC_SystemFailure
, EL_Unknown
);
507 void CloseFile(struct sigcontext_struct
*context
)
509 if (close(BX
) == -1) {
512 Error (InvalidHandle
, EC_AppError
, EL_Unknown
);
515 Error (GeneralFailure
, EC_SystemFailure
, EL_Unknown
);
527 void RenameFile(struct sigcontext_struct
*context
)
529 rename((char *) pointer(DS
,DX
), (char *) pointer(ES
,DI
));
533 void GetTrueFileName(struct sigcontext_struct
*context
)
535 strncpy((char *) pointer(ES
,DI
), (char *) pointer(DS
,SI
), strlen((char *) pointer(DS
,SI
)) & 0x7f);
539 void MakeDir(struct sigcontext_struct
*context
)
545 dirname
= (char *) pointer(DS
,DX
);
547 ParseDOSFileName(unixname
,dirname
,&drive
);
550 if (mkdir(unixname
,0) == -1) {
558 void ChangeDir(struct sigcontext_struct
*context
)
564 dirname
= (char *) pointer(DS
,DX
);
566 ParseDOSFileName(unixname
,dirname
,&drive
);
569 strcpy(unixname
,DosDrives
[drive
].CurrentDirectory
);
574 void RemoveDir(struct sigcontext_struct
*context
)
580 dirname
= (char *) pointer(DS
,DX
);
582 ParseDOSFileName(unixname
,dirname
,&drive
);
585 if (strcmp(unixname
,DosDrives
[drive
].CurrentDirectory
)) {
586 AX
= CanNotRemoveCwd
;
591 fprintf(stderr
,"rmdir %s\n",unixname
);
594 if (rmdir(unixname
) == -1) {
595 AX
= CanNotMakeDir
; /* HUH ?*/
602 void AllocateMemory(struct sigcontext_struct
*context
)
606 if ((ptr
= (void *) memalign((size_t) (BX
* 0x10), 0x10)) == NULL
) {
608 BX
= 0x0; /* out of memory */
611 AX
= segment((unsigned long) ptr
);
615 void FreeMemory(struct sigcontext_struct
*context
)
617 free((void *)(ES
* 0x10));
621 void ResizeMemoryBlock(struct sigcontext_struct
*context
)
625 if ((ptr
= (void *) realloc((void *)(ES
* 0x10), (size_t) BX
* 0x10)) == NULL
) {
627 BX
= 0x0; /* out of memory */
630 BX
= segment((unsigned long) ptr
);
634 void ExecProgram(struct sigcontext_struct
*context
)
636 execl("wine",(char *) pointer(DS
,DX
));
639 void GetReturnCode(struct sigcontext_struct
*context
)
641 AX
= NoError
; /* normal exit */
644 void FindFirst(struct sigcontext_struct
*context
)
649 void FindNext(struct sigcontext_struct
*context
)
654 void GetSysVars(struct sigcontext_struct
*context
)
660 void GetFileDateTime(struct sigcontext_struct
*context
)
665 struct stat filestat
;
668 dirname
= (char *) pointer(DS
,DX
);
669 ParseDOSFileName(unixname
, dirname
, &drive
);
672 stat(unixname
, &filestat
);
674 now
= localtime (&filestat
.st_mtime
);
676 CX
= (now
->tm_hour
* 0x2000) + (now
->tm_min
* 0x20) + now
->tm_sec
/2;
677 DX
= (now
->tm_year
* 0x200) + (now
->tm_mon
* 0x20) + now
->tm_mday
;
683 void SetFileDateTime(struct sigcontext_struct
*context
)
688 struct utimbuf filetime
;
690 dirname
= (char *) pointer(DS
,DX
);
692 ParseDOSFileName(unixname
, dirname
, &drive
);
695 filetime
.actime
= 0L;
696 filetime
.modtime
= filetime
.actime
;
698 utime(unixname
,&filetime
);
703 void CreateTempFile(struct sigcontext_struct
*context
)
705 char UnixFileName
[256],TempString
[256];
708 ParseDOSFileName(UnixFileName
, (char *) pointer(DS
,DX
), &drive
);
710 sprintf(TempString
,"%s%s%d",UnixFileName
,"eb",(int) getpid());
713 handle
= open(TempString
, O_CREAT
| O_TRUNC
| O_RDWR
);
721 strcpy((char *) pointer(DS
,DX
), UnixFileName
);
728 void CreateNewFile(struct sigcontext_struct
*context
)
730 char UnixFileName
[256];
733 ParseDOSFileName(UnixFileName
, (char *) pointer(DS
,DX
), &drive
);
736 handle
= open(UnixFileName
, O_CREAT
| O_TRUNC
| O_RDWR
);
749 void FileLock(struct sigcontext_struct
*context
)
754 void GetExtendedCountryInfo(struct sigcontext_struct
*context
)
759 int ValidDrive(int d
)
764 void GetCurrentDirectory(struct sigcontext_struct
*context
)
769 if ((DX
& 0xff) == 0)
770 drive
= CurrentDrive
;
772 drive
= (DX
& 0xff)-1;
774 if (!ValidDrive(drive
)) {
780 strcpy((char *) pointer(DS
,SI
), DosDrives
[drive
].CurrentDirectory
);
785 void GetCurrentPSP(struct sigcontext_struct
*context
)
790 void GetDiskSerialNumber(struct sigcontext_struct
*context
)
793 struct diskinfo
*ptr
;
796 drive
= CurrentDrive
;
798 drive
= (BX
& 0xff)-1;
800 if (!ValidDrive(drive
)) {
807 ptr
=(struct diskinfo
*) pointer(DS
,SI
);
810 ptr
->serialnumber
= 0xEBEBEB00 | drive
;
811 strcpy(ptr
->label
,"NO NAME ");
812 strcpy(ptr
->fstype
,"FAT16 ");
819 void SetDiskSerialNumber(struct sigcontext_struct
*context
)
826 void CommitFile(struct sigcontext_struct
*context
)
831 /************************************************************************/
833 int do_int21(struct sigcontext_struct
* context
){
836 fprintf(stderr
,"int21: doing AX=%4x BX=%4x CX=%4x DX=%4x\n",
837 AX
& 0xffff,BX
& 0xffff,CX
& 0xffff,DX
& 0xffff);
839 ah
= (AX
>> 8) & 0xff;
842 GetExtendedErrorInfo(context
);
850 case 0x00: /* TERMINATE PROGRAM */
853 case 0x01: /* READ CHARACTER FROM STANDARD INPUT, WITH ECHO */
854 case 0x02: /* WRITE CHARACTER TO STANDARD OUTPUT */
855 case 0x03: /* READ CHARACTER FROM STDAUX */
856 case 0x04: /* WRITE CHARACTER TO STDAUX */
857 case 0x05: /* WRITE CHARACTER TO PRINTER */
858 case 0x06: /* DIRECT CONSOLE IN/OUTPUT */
859 case 0x07: /* DIRECT CHARACTER INPUT, WITHOUT ECHO */
860 case 0x08: /* CHARACTER INPUT WITHOUT ECHO */
861 case 0x09: /* WRITE STRING TO STANDARD OUTPUT */
862 case 0x0a: /* BUFFERED INPUT */
863 case 0x0b: /* GET STDIN STATUS */
864 case 0x0c: /* FLUSH BUFFER AND READ STANDARD INPUT */
865 case 0x0d: /* DISK BUFFER FLUSH */
868 /* no FCB support for CP/M hackers */
870 case 0x0f: /* OPEN FILE USING FCB */
871 case 0x10: /* CLOSE FILE USING FCB */
872 case 0x11: /* FIND FIRST MATCHING FILE USING FCB */
873 case 0x12: /* FIND NEXT MATCHING FILE USING FCB */
874 case 0x13: /* DELETE FILE USING FCB */
875 case 0x14: /* SEQUENTIAL READ FROM FCB FILE */
876 case 0x15: /* SEQUENTIAL WRITE TO FCB FILE */
877 case 0x16: /* CREATE OR TRUNCATE FILE USING FCB */
878 case 0x17: /* RENAME FILE USING FCB */
879 case 0x1a: /* SET DISK TRANSFER AREA ADDRESS */
880 case 0x21: /* READ RANDOM RECORD FROM FCB FILE */
881 case 0x22: /* WRITE RANDOM RECORD TO FCB FILE */
882 case 0x23: /* GET FILE SIZE FOR FCB */
883 case 0x24: /* SET RANDOM RECORD NUMBER FOR FCB */
884 case 0x27: /* RANDOM BLOCK READ FROM FCB FILE */
885 case 0x28: /* RANDOM BLOCK WRITE TO FCB FILE */
886 case 0x29: /* PARSE FILENAME INTO FCB */
887 case 0x2f: /* GET DISK TRANSFER AREA ADDRESS */
889 case 0x2e: /* SET VERIFY FLAG */
892 case 0x18: /* NULL FUNCTIONS FOR CP/M COMPATIBILITY */
896 case 0x2b: /* SET SYSTEM DATE */
897 case 0x2d: /* SET SYSTEM TIME */
898 case 0x37: /* "SWITCHAR" - GET SWITCH CHARACTER
899 "SWITCHAR" - SET SWITCH CHARACTER
900 "AVAILDEV" - SPECIFY \DEV\ PREFIX USE */
901 case 0x54: /* GET VERIFY FLAG */
902 case 0x61: /* UNUSED */
903 case 0x6b: /* NULL FUNCTION */
907 case 0x67: /* SET HANDLE COUNT */
911 case 0x0e: /* SELECT DEFAULT DRIVE */
912 SetDefaultDrive(context
);
915 case 0x19: /* GET CURRENT DEFAULT DRIVE */
916 GetDefaultDrive(context
);
919 case 0x1b: /* GET ALLOCATION INFORMATION FOR DEFAULT DRIVE */
920 GetDefDriveAllocInfo(context
);
923 case 0x1c: /* GET ALLOCATION INFORMATION FOR SPECIFIC DRIVE */
924 GetDriveAllocInfo(context
);
927 case 0x1f: /* GET DRIVE PARAMETER BLOCK FOR DEFAULT DRIVE */
928 case 0x32: /* GET DOS DRIVE PARAMETER BLOCK FOR SPECIFIC DRIVE */
932 case 0x25: /* SET INTERRUPT VECTOR */
933 /* Ignore any attempt to set a segment vector */
936 case 0x26: /* CREATE NEW PROGRAM SEGMENT PREFIX */
939 case 0x2a: /* GET SYSTEM DATE */
940 GetSystemDate(context
);
943 case 0x2c: /* GET SYSTEM TIME */
944 GetSystemTime(context
);
947 case 0x30: /* GET DOS VERSION */
948 AX
= DosVersion
; /* Hey folks, this is DOS V3.3! */
949 BX
= 0x0012; /* 0x123456 is Wine's serial # */
953 case 0x31: /* TERMINATE AND STAY RESIDENT */
956 case 0x33: /* MULTIPLEXED */
958 case 0x00: /* GET CURRENT EXTENDED BREAK STATE */
963 case 0x01: /* SET EXTENDED BREAK STATE */
966 case 0x02: /* GET AND SET EXTENDED CONTROL-BREAK CHECKING STATE */
970 case 0x05: /* GET BOOT DRIVE */
972 DX
|= 2; /* c: is Wine's bootdrive */
975 case 0x06: /* GET TRUE VERSION NUMBER */
984 case 0x34: /* GET ADDRESS OF INDOS FLAG */
985 GetInDosFlag(context
);
988 case 0x35: /* GET INTERRUPT VECTOR */
989 /* Return a NULL segment selector - this will bomb,
990 if anyone ever tries to use it */
995 case 0x36: /* GET FREE DISK SPACE */
996 GetFreeDiskSpace(context
);
999 case 0x38: /* GET COUNTRY-SPECIFIC INFORMATION */
1001 AX
|= 0x02; /* no country support available */
1005 case 0x39: /* "MKDIR" - CREATE SUBDIRECTORY */
1009 case 0x3a: /* "RMDIR" - REMOVE SUBDIRECTORY */
1013 case 0x3b: /* "CHDIR" - SET CURRENT DIRECTORY */
1017 case 0x3c: /* "CREAT" - CREATE OR TRUNCATE FILE */
1018 CreateFile(context
);
1021 case 0x3d: /* "OPEN" - OPEN EXISTING FILE */
1022 OpenExistingFile(context
);
1025 case 0x3e: /* "CLOSE" - CLOSE FILE */
1026 case 0x68: /* "FFLUSH" - COMMIT FILE */
1027 case 0x6a: /* COMMIT FILE */
1032 case 0x3f: /* "READ" - READ FROM FILE OR DEVICE */
1036 case 0x40: /* "WRITE" - WRITE TO FILE OR DEVICE */
1040 case 0x41: /* "UNLINK" - DELETE FILE */
1041 UnlinkFile(context
);
1044 case 0x42: /* "LSEEK" - SET CURRENT FILE POSITION */
1048 case 0x43: /* FILE ATTRIBUTES */
1049 switch (AX
& 0xff) {
1051 GetFileAttributes(context
);
1054 SetFileAttributes(context
);
1059 case 0x44: /* IOCTL */
1063 case 0x45: /* "DUP" - DUPLICATE FILE HANDLE */
1064 case 0x46: /* "DUP2", "FORCEDUP" - FORCE DUPLICATE FILE HANDLE */
1065 DupeFileHandle(context
);
1068 case 0x47: /* "CWD" - GET CURRENT DIRECTORY */
1069 GetCurrentDirectory(context
);
1070 AX
= 0x0100; /* many Microsoft products for Windows rely
1074 case 0x48: /* ALLOCATE MEMORY */
1075 AllocateMemory(context
);
1078 case 0x49: /* FREE MEMORY */
1079 FreeMemory(context
);
1082 case 0x4a: /* RESIZE MEMORY BLOCK */
1083 ResizeMemoryBlock(context
);
1086 case 0x4b: /* "EXEC" - LOAD AND/OR EXECUTE PROGRAM */
1087 ExecProgram(context
);
1090 case 0x4c: /* "EXIT" - TERMINATE WITH RETURN CODE */
1093 case 0x4d: /* GET RETURN CODE */
1094 GetReturnCode(context
);
1097 case 0x4e: /* "FINDFIRST" - FIND FIRST MATCHING FILE */
1101 case 0x4f: /* "FINDNEXT" - FIND NEXT MATCHING FILE */
1105 case 0x52: /* "SYSVARS" - GET LIST OF LISTS */
1106 GetSysVars(context
);
1109 case 0x56: /* "RENAME" - RENAME FILE */
1110 RenameFile(context
);
1113 case 0x57: /* FILE DATE AND TIME */
1114 switch (AX
& 0xff) {
1116 GetFileDateTime(context
);
1119 SetFileDateTime(context
);
1124 case 0x58: /* GET OR SET MEMORY/UMB ALLOCATION STRATEGY */
1125 switch (AX
& 0xff) {
1139 case 0x59: /* GET EXTENDED ERROR INFO */
1140 GetExtendedErrorInfo(context
);
1143 case 0x5a: /* CREATE TEMPORARY FILE */
1144 CreateTempFile(context
);
1147 case 0x5b: /* CREATE NEW FILE */
1148 CreateNewFile(context
);
1151 case 0x5c: /* "FLOCK" - RECORD LOCKING */
1155 case 0x5d: /* NETWORK */
1159 AX
|= NoNetwork
; /* network software not installed */
1163 case 0x60: /* "TRUENAME" - CANONICALIZE FILENAME OR PATH */
1164 GetTrueFileName(context
);
1167 case 0x62: /* GET CURRENT PSP ADDRESS */
1168 GetCurrentPSP(context
);
1171 case 0x65: /* GET EXTENDED COUNTRY INFORMATION */
1172 GetExtendedCountryInfo(context
);
1175 case 0x66: /* GLOBAL CODE PAGE TABLE */
1176 switch (AX
& 0xff) {
1189 case 0x69: /* DISK SERIAL NUMBER */
1190 switch (AX
& 0xff) {
1192 GetDiskSerialNumber(context
);
1195 SetDiskSerialNumber(context
);
1201 fprintf(stderr
,"Unable to handle int 0x21 %x\n", context
->sc_eax
);