📄 int21.c
字号:
/* INT 21h handler for the FreeDOS-32 DPMI Driver * Copyright (C) 2001-2005 Salvatore ISAJA * * This file "int21.c" is part of the FreeDOS-32 DPMI Driver (the Program). * * The Program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * The Program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with the Program; see the file GPL.txt; if not, write to * the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *//* TODO: We should provide some mechanism for installing new fake interrupt handlers (like this INT 21h handler), with the possibility of recalling the old one.*/#include <ll/i386/hw-data.h>#include <ll/i386/string.h>#include <kernel.h>#include <filesys.h>#include <errno.h>#include <stubinfo.h>#include <logger.h>#include <fd32time.h>#include "rmint.h"#define DOS_API_INPUT_IS_UTF8 1#if !DOS_API_INPUT_IS_UTF8 #include <unicode/unicode.h> #include <nls/nls.h> struct nls_operations *current_cp;#endif#if defined(__GNUC__) && !defined(restrict) #define restrict __restrict__#endif/* Define the __DEBUG__ symbol in order to activate log output *///#define __DEBUG__#ifdef __DEBUG__ #define LOG_PRINTF(s) fd32_log_printf s#else #define LOG_PRINTF(s)#endif#define FAR2ADDR(seg, off) (((DWORD) seg << 4) + (DWORD) off)/* The current PSP is needed for the pointer to the DTA */extern struct psp *current_psp;int use_lfn;/* Parameter block for the dos_exec call, see INT 21h AH=4Bh */typedef struct{ WORD Env; WORD arg_offs; WORD arg_seg; DWORD Fcb1; DWORD Fcb2; DWORD Res1; DWORD Res2;}__attribute__ ((packed)) ExecParams;/* DOS return code of the last executed program */static WORD dos_return_code;/* Data structure for INT 21 AX=7303h *//* Windows95 - FAT32 - Get extended free space on drive */typedef struct{ WORD Size; /* Size of the returned structure (this one) */ WORD Version; /* Version of this structure (desired/actual) */ /* The following are *with* adjustment for compression */ DWORD SecPerClus; /* Sectors per cluster */ DWORD BytesPerSec; /* Bytes per sector */ DWORD AvailClus; /* Number of available clusters */ DWORD TotalClus; /* Total number of clusters on drive */ /* The following are *without* adjustment for compression */ DWORD RealSecPerClus; /* Number of sectors per cluster */ DWORD RealBytesPerSec; /* Bytes per sector */ DWORD RealAvailClus; /* Number of available clusters */ DWORD RealTotalClus; /* Total number of clusters on drive */ BYTE Reserved[8];}__attribute__ ((packed)) ExtDiskFree;/* DOS error codes (see RBIL table 01680) */#define DOS_ENOTSUP 0x01 /* function number invalid */#define DOS_ENOENT 0x02 /* file not found */#define DOS_ENOTDIR 0x03 /* path not found */#define DOS_EMFILE 0x04 /* too many open files */#define DOS_EACCES 0x05 /* access denied */#define DOS_EBADF 0x06 /* invalid handle */#define DOS_ENOMEM 0x08 /* insufficient memory */#define DOS_EMEMBLK 0x09 /* memory block address invalid */#define DOS_EFTYPE 0x0B /* format invalid */#define DOS_EDATA 0x0D /* data invalid */#define DOS_ENOTBLK 0x0F /* invalid drive */#define DOS_EXDEV 0x11 /* not same device */#define DOS_ENOMOREF 0x12 /* no more files */#define DOS_EROFS 0x13 /* disk write-protected */#define DOS_EUNIT 0x14 /* unknown unit */#define DOS_ENOMEDIUM 0x15 /* drive not ready */#define DOS_EIO 0x1F /* general failure */#define DOS_ENOSPC 0x27 /* insufficient disk space */#define DOS_EEXIST 0x50 /* file exists */#define DOS_EUNKNOWN 0x64 /* unknown error */#define DOS_EBUFSMALL 0x7A /* buffer too small to hold return data */#define DOS_EINVAL 0xA0 /* bad arguments */#define DOS_ENOLCK 0xB4 /* lock count has been exceeded */#define DOS_ENOEXEC 0xC1 /* bad EXE format *//* Lookup table to convert FD32 errno codes to DOS error codes *//* TODO: Fine tune the mapping using the DJGPP one as a reference */static const BYTE errno2dos[] = {/* 0 */ 0x00, DOS_EUNKNOWN, DOS_ENOENT, DOS_EUNKNOWN,/* 4 */ DOS_EUNKNOWN, DOS_EIO, DOS_EUNIT, DOS_EUNKNOWN,/* 8 */ DOS_ENOEXEC, DOS_EBADF, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 12 */ DOS_ENOMEM, DOS_EACCES, DOS_EMEMBLK, DOS_EUNIT,/* 16 */ DOS_EUNKNOWN, DOS_EEXIST, DOS_EXDEV, DOS_EUNIT,/* 20 */ DOS_ENOTDIR, DOS_EACCES, DOS_EINVAL, DOS_EMFILE,/* 24 */ DOS_EMFILE, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EACCES,/* 28 */ DOS_ENOSPC, DOS_EUNKNOWN, DOS_EROFS, DOS_EUNKNOWN,/* 32 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 36 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 40 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 44 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_ENOLCK, DOS_EUNKNOWN,/* 48 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 52 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_ENOTSUP, DOS_EUNKNOWN,/* 56 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 60 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 64 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 68 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 72 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 76 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EFTYPE,/* 80 */ DOS_EUNKNOWN, DOS_EBADF, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 84 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 88 */ DOS_ENOTSUP, DOS_EMFILE, DOS_EACCES, DOS_EBUFSMALL,/* 92 */ DOS_EACCES, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_ENOTSUP,/* 96 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 100 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 104 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 108 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 112 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 116 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 120 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 124 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 128 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EUNKNOWN,/* 132 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_ENOTSUP, DOS_ENOMEDIUM,/* 136 */ DOS_EUNKNOWN, DOS_EUNKNOWN, DOS_EDATA};/* Converts a FD32 return code (< 0 meaning error) * to a DOS return status in the specified register set. * - on error: carry flag set, error (positive) in AX * - on success: carry flag clear */static void res2dos(int res, union rmregs *r){ LOG_PRINTF(("INT 21h - res=%i\n", res)); RMREGS_CLEAR_CARRY; if (res < 0) { res = -res; RMREGS_SET_CARRY; r->x.ax = DOS_EUNKNOWN; if (res < sizeof(errno2dos)) r->x.ax = errno2dos[res]; }}/* Converts a DOS open action (see RBIL table 01770) to a libc mode. */static int parse_open_action(int dos_action){ int action = 0; if (dos_action & 0x10) action |= O_CREAT; switch (dos_action & ~0x10) { case 0x00: action |= O_EXCL; break; case 0x01: break; case 0x02: action |= O_TRUNC; break; default: action = -EINVAL; } return action;}/* Converts a path name from DOS API to UTF-8 using no more than "size" bytes. * Forward slashes '/' are converted to back slashes '\'. * Returns 0 on success, or a negative error. */static int fix_path(char *restrict dest, const char *restrict source, size_t size){ #if DOS_API_INPUT_IS_UTF8 char c; while (*source) { if (!size) return -ENAMETOOLONG; c = *(source++); if (c == '/') c = '\\'; *(dest++) = c; } #else int res = 0; wchar_t wc; while (*source) { res = current_cp->mbtowc(&wc, source, NLS_MB_MAX_LEN); if (res < 0) return res; source += res; if (wc == (wchar_t) '/') wc = (wchar_t) '\\'; res = unicode_wctoutf8(dest, wc, size); if (res < 0) return res; dest += res; size -= res; } #endif if (!size) return -ENAMETOOLONG; *dest = 0; return 0;}/* Sub-handler for DOS services "Get/set file's time stamps" * INT 21h AH=57h (BX=file handle, AL=action). */static inline void get_and_set_time_stamps(union rmregs *r){ fd32_fs_attr_t a; int res; a.Size = sizeof(fd32_fs_attr_t); switch (r->h.al) { /* Get last modification date and time */ case 0x00: /* TODO: MS-DOS returns date and time of opening for char devices */ res = fd32_get_attributes(r->x.bx, &a); if (res >= 0) { r->x.cx = a.MTime; r->x.dx = a.MDate; } break; /* Set last modification date and time */ case 0x01: res = fd32_get_attributes(r->x.bx, &a); if (res >= 0) { a.MTime = r->x.cx; a.MDate = r->x.dx; res = fd32_set_attributes(r->x.bx, &a); } break; /* Get last access date and time */ case 0x04: res = fd32_get_attributes(r->x.bx, &a); if (res >= 0) { r->x.dx = a.ADate; r->x.cx = 0x0000; /* FAT has not the last access time */ } break; /* Set last access date and time */ case 0x05: if (r->x.cx != 0x0000) { /* FAT has not the last access time */ res = -EINVAL; break; } res = fd32_get_attributes(r->x.bx, &a); if (res >= 0) { a.ADate = r->x.dx; res = fd32_set_attributes(r->x.bx, &a); } break; /* Get creation date and time */ case 0x06: res = fd32_get_attributes(r->x.bx, &a); if (res >= 0) { r->x.dx = a.CDate; r->x.cx = a.CTime; r->x.si = a.CHund; } break; /* Set creation date and time */ case 0x07: res = fd32_get_attributes(r->x.bx, &a); if (res >= 0) { a.CDate = r->x.dx; a.CTime = r->x.cx; a.CHund = r->x.si; res = fd32_set_attributes(r->x.bx, &a); } break; /* Invalid subfunctions */ default: r->h.al = 0xFF; /* Yet another convention */ RMREGS_SET_CARRY; return; } res2dos(res, r);}/* Sub-handler for DOS service "Get/set file's attributes" * INT 21h AH=43h (DS:DX->ASCIZ file name, AL=action). */static inline void dos_get_and_set_attributes(union rmregs *r){ char fn[FD32_LFNPMAX]; fd32_fs_attr_t a; int fd; int res = fix_path(fn, (const char *) FAR2ADDR(r->x.ds, r->x.dx), sizeof(fn)); if (res < 0) { res2dos(res, r); return; } fd = fd32_open(fn, O_RDONLY, FD32_ANONE, 0, NULL); if (fd < 0) /* It could be a directory... */ fd = fd32_open(fn, O_RDONLY | O_DIRECTORY, FD32_ANONE, 0, NULL); if (fd < 0) { res2dos(fd, r); return; } a.Size = sizeof(fd32_fs_attr_t); switch (r->h.al) { /* Get file attributes */ case 0x00: LOG_PRINTF(("INT 21h - Getting attributes of \"%s\"\n", fn)); res = fd32_get_attributes(fd, &a); if (res >= 0) { r->x.cx = a.Attr; r->x.ax = r->x.cx; /* DR-DOS 5.0 */ } break; /* Set file attributes */ case 0x01: /* FIXME: Should close the file if currently open in sharing-compat * mode, or generate a sharing violation critical error in * the file is currently open. * Mah! Would that be true with the new things? Mah... */ LOG_PRINTF(("INT 21h - Setting attributes of \"%s\" to %04x\n", fn, r->x.cx)); res = fd32_get_attributes(fd, &a); if (res < 0) break; /* Volume label and directory attributes cannot be changed. * To change the other attributes bits of a directory the directory * flag must be clear, though it will be set after this call. */ if ((r->x.cx & (FD32_AVOLID | FD32_ADIR)) || (a.Attr == FD32_AVOLID)) { res = -EACCES; break; } a.Attr = r->x.cx; if (a.Attr & FD32_ADIR) a.Attr = r->x.cx | FD32_ADIR; res = fd32_set_attributes(fd, &a); break; /* Invalid subfunctions */ default: fd32_close(fd); r->h.al = 0xFF; /* Yet another convention */ RMREGS_SET_CARRY; return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -