📄 int21.c
字号:
r->x.dx = 0; /* Revision 0, no flags... */ RMREGS_CLEAR_CARRY; return; } r->h.al = 0xFF; /* Invalid subfunction */ RMREGS_SET_CARRY; return; /* DOS 2+ - Get free disk space (DL=drive number, 0=default, 1=A, etc.) */ case 0x36: { fd32_getfsfree_t fsfree; char drive[4] = " :\\"; drive[0] = fd32_get_default_drive(); if (r->h.dl) drive[0] = r->h.dl + 'A' - 1; fsfree.Size = sizeof(fd32_getfsfree_t); res = fd32_get_fsfree(drive, &fsfree); LOG_PRINTF(("INT 21h - Get free disk space for \"%s\", returns %08x\n", drive, res)); LOG_PRINTF((" Got: %lu secperclus, %lu availclus, %lu bytspersec, %lu totclus\n", fsfree.SecPerClus, fsfree.AvailClus, fsfree.BytesPerSec, fsfree.TotalClus)); if (res < 0) { r->x.ax = 0xFFFF; /* Unusual way to report error condition */ return; } r->x.ax = fsfree.SecPerClus; /* AX = Sectors per cluster */ r->x.bx = fsfree.AvailClus; /* BX = Number of free clusters */ r->x.cx = fsfree.BytesPerSec; /* CX = Bytes per sector */ r->x.dx = fsfree.TotalClus; /* DX = Total clusters on drive */ return; } /* DOS 2+ - "MKDIR" - Create subdirectory (DS:DX->ASCIZ directory name) */ case 0x39: res = fix_path(fn, (const char *) FAR2ADDR(r->x.ds, r->x.dx), sizeof(fn)); LOG_PRINTF(("INT 21h - Make directory \"%s\"\n", fn)); if (res >= 0) res = fd32_mkdir(fn); break; /* DOS 2+ - "RMDIR" - Remove subdirectory (DS:DX->ASCIZ directory name) */ case 0x3A: res = fix_path(fn, (const char *) FAR2ADDR(r->x.ds, r->x.dx), sizeof(fn)); LOG_PRINTF(("INT 21h - Remove directory \"%s\"\n", fn)); if (res >= 0) res = fd32_rmdir(fn); break; /* DOS 2+ - "CHDIR" - Set current directory (DS:DX->ASCIZ directory name) */ case 0x3B: res = fix_path(fn, (const char *) FAR2ADDR(r->x.ds, r->x.dx), sizeof(fn)); LOG_PRINTF(("INT 21h - Change directory to \"%s\"\n", fn)); if (res >= 0) res = fd32_chdir(fn); break; /* DOS 2+ - "CREAT" - Create or truncate file (DS:DX->ASCIZ file name, * CX=attributes, volume label and directory not allowed). */ case 0x3C: res = fix_path(fn, (const char *) FAR2ADDR(r->x.ds, r->x.dx), sizeof(fn)); LOG_PRINTF(("INT 21h - Creat \"%s\" with attr %04x\n", fn, r->x.cx)); if (res < 0) break; res = fd32_open(fn, O_RDWR | O_CREAT | O_TRUNC, r->x.cx, 0, NULL); res2dos(res, r); if (res >= 0) r->x.ax = (WORD) res; /* The new handle */ break; /* DOS 2+ - "OPEN" - Open existing file (DS:DX->ASCIZ file name, * AL=opening mode, CL=search attributes for server call). */ case 0x3D: res = fix_path(fn, (const char *) FAR2ADDR(r->x.ds, r->x.dx), sizeof(fn)); LOG_PRINTF(("INT 21h - Open \"%s\" with mode %02x\n", fn, r->h.al)); if (res < 0) break; res = fd32_open(fn, r->h.al, FD32_ANONE, 0, NULL); res2dos(res, r); if (res >= 0) r->x.ax = (WORD) res; /* The new handle */ break; /* DOS 2+ - "CLOSE" - Close file (BX=file handle) */ case 0x3E: LOG_PRINTF(("INT 21h - Close handle %04x\n", r->x.bx)); res = fd32_close(r->x.bx); break; /* Recent DOSes preserve AH, we are OK with this */ /* DOS 2+ - "READ" - Read from file or device (BX=file handle, * CX=bytes to read, DS:DX->transfer buffer). */ case 0x3F: res = fd32_read(r->x.bx, (void *) FAR2ADDR(r->x.ds, r->x.dx), r->x.cx); //LOG_PRINTF(("INT 21h - Read (AH=3Fh) from handle %04x (%d bytes). Res=%08xh\n", r->x.bx, r->x.cx, res)); if (res < 0) break; #if 0 /* FIXME: Can this be removed now? */ /* This is a quick'n'dirty hack to return \n after \r from stdin. */ /* It works only if console input is on handle 0 and if the number */ /* of bytes to read is greater than the first carriage return. */ /* TODO: Make this \r\n stuff functional according to the console. */ if (r->x.bx == 0) { BYTE *buf = (BYTE *) FAR2ADDR(r->x.ds, r->x.dx); if (res < r->x.cx) buf[res++] = '\n'; } #endif RMREGS_CLEAR_CARRY; r->x.ax = (WORD) res; /* bytes read */ return; /* DOS 2+ - "WRITE" - Write to file or device (BX=file handle, * CX=bytes to write, DS:DX->transfer buffer). */ case 0x40: res = fd32_write(r->x.bx, (/*const*/ void *) FAR2ADDR(r->x.ds, r->x.dx), r->x.cx); //LOG_PRINTF(("INT 21h - Write (AH=40h) to handle %04x (%d bytes). Res=%08xh\n", r->x.bx, r->x.cx, res)); res2dos(res, r); if (res >= 0) r->x.ax = (WORD) res; /* bytes written */ return; /* DOS 2+ - "UNLINK" - Delete file (DS:DX->ASCIZ file name, * CL=search attributes for server call). */ case 0x41: res = fix_path(fn, (const char *) FAR2ADDR(r->x.ds, r->x.dx), sizeof(fn)); LOG_PRINTF(("INT 21h - Delete file \"%s\"\n", fn)); if (res >= 0) res = fd32_unlink(fn, FD32_FAALL | FD32_FRNONE); break; /* DOS 2+ - "LSEEK" - Set current file position (BX=file handle, * CX:DX=offset, AL=origin). * FIXME: Replace with off_t */ case 0x42: res = fd32_lseek(r->x.bx, ((long long) r->x.cx << 8) + (long long) r->x.dx, r->h.al, &res64); res2dos(res, r); if (res >= 0) { r->x.ax = (WORD) res64; r->x.dx = (WORD) (res64 >> 16); } return; /* DOS 2+ - Get/set file attributes */ case 0x43: dos_get_and_set_attributes(r); return; /* IOCTL functions * TODO: They should be done... one day */ case 0x44: res = fd32_get_dev_info(r->x.bx); if (res < 0) { r->x.ax = DOS_EBADF; RMREGS_SET_CARRY; } else { r->x.ax = res; r->x.dx = r->x.ax; RMREGS_CLEAR_CARRY; } return; /* DOS 2+ - "DUP" - Duplicate file handle (BX=file handle) */ case 0x45: /* BX file handle */ res = fd32_dup(r->x.bx); res2dos(res, r); if (res >= 0) r->x.ax = (WORD) res; /* new handle */ return; /* DOS 2+ - "DUP2", "FORCEDUP" - Force duplicate file handle * (BX=file handle, CX=new handle). */ case 0x46: res = fd32_forcedup(r->x.bx, r->x.cx); break; /* DOS 2+ - "CWD" - Get current directory (DL=drive number, 0=default * 1=A, etc., DS:DI->64 bytes buffer for ASCIZ path name). */ case 0x47: { char drive[2] = "A"; char *c; char *dest = (char *) FAR2ADDR(r->x.ds, r->x.si); LOG_PRINTF(("INT 21h - Get current dir of drive %02x\n", r->h.dl)); drive[0] = fd32_get_default_drive(); if (r->h.dl) drive[0] = r->h.dl + 'A' - 1; res = fd32_getcwd(drive, fn); if (res < 0) break; LOG_PRINTF(("After getcwd:\"%s\"\n", fn)); /* Convert all component to 8.3 */ res = fd32_sfn_truename(fn, fn); if (res < 0) break; LOG_PRINTF(("After sfn_truename:\"%s\"\n", fn)); /* Skip drive specification and initial backslash as required from DOS */ for (c = fn; *c != '\\'; c++); strcpy(dest, c + 1); LOG_PRINTF(("Returned CWD:\"%s\"\n", dest)); r->x.ax = 0x0100; /* Undocumented success return value */ RMREGS_CLEAR_CARRY; /* TODO: Convert from UTF-8 to OEM */ return; } /* DOS 2+ - "EXEC" - Load and/or Execute program */ case 0x4B: { ExecParams *pb; char *args, *p, c[128]; int cnt, i; pb = (ExecParams *) FAR2ADDR(r->x.es, r->x.bx); /* Only AH = 0x00 - Load and Execute - is currently supported */ if (r->h.al != 0) { r->h.al = 0xFF; /* Invalid subfunction */ RMREGS_SET_CARRY; return; } p = (char *) FAR2ADDR(pb->arg_seg, pb->arg_offs); cnt = *p++; if (cnt == 0) { args = NULL; } else { for (i = 0; i < cnt; i++) { c[i] = *p++; } c[i] = 0; args = c; } res = fix_path(fn, (const char *) FAR2ADDR(r->x.ds, r->x.dx), sizeof(fn)); LOG_PRINTF(("INT 21h - Load and Execute \"%s\"\n", fn)); if (res >= 0) res = dos_exec(fn, pb->Env, args, pb->Fcb1, pb->Fcb2, &dos_return_code); break; } /* DOS 2+ - Get return code */ case 0x4D: RMREGS_CLEAR_CARRY; r->h.ah = 0; /* Only normal termination, for now... */ r->h.al = dos_return_code; dos_return_code = 0; /* DOS clears it after reading it */ return; /* DOS 2+ - "FINDFIRST" - Find first matching file (DS:DX->ASCIZ file spec, * CX=allowable attributes (archive and read only ignored), * AL=special flag for append (ignored). */ case 0x4E: res = fix_path(fn, (const char *) FAR2ADDR(r->x.ds, r->x.dx), sizeof(fn)); LOG_PRINTF(("INT 21h - Findfirst \"%s\" with attr %04x\n", fn, r->x.cx)); if (res < 0) break; res = fd32_dos_findfirst(fn, r->x.cx, current_psp->dta); LOG_PRINTF(("a\n")); res2dos(res, r); LOG_PRINTF(("b\n")); if (res == -ENOENT) r->x.ax = DOS_ENOMOREF; LOG_PRINTF(("c\n")); return; /* DOS 2+ - "FINDNEXT" - Find next matching file */ case 0x4F: LOG_PRINTF(("INT 21h - Findnext\n")); res = fd32_dos_findnext(current_psp->dta); res2dos(res, r); if (res == -ENOENT) r->x.ax = DOS_ENOMOREF; return; /* DOS 2+ - "RENAME" - Rename or move file (DS:DX->old name, * ES:DI->new name, CL=attributes for server call). */ case 0x56: { char newfn[FD32_LFNPMAX]; res = fix_path(fn, (const char *) FAR2ADDR(r->x.ds, r->x.dx), sizeof(fn)); if (res < 0) break; res = fix_path(newfn, (const char *) FAR2ADDR(r->x.es, r->x.di), sizeof(newfn)); if (res < 0) break; LOG_PRINTF(("INT 21h - Renaming \"%s\" to \"%s\"\n", fn, newfn)); res = fd32_rename(fn, newfn); break; } /* DOS 2+ - Get/set file's time stamps */ case 0x57: get_and_set_time_stamps(r); return; /* DOS 3.0+ - Create new file (DS:DX->ASCIZ file name, CX=attributes) */ case 0x5B: res = fix_path(fn, (const char *) FAR2ADDR(r->x.ds, r->x.dx), sizeof(fn)); LOG_PRINTF(("INT 21h - Creating new file (AH=5Bh) \"%s\" with attr %04x\n", fn, r->x.cx)); if (res < 0) break; res = fd32_open(fn, O_RDWR | O_CREAT | O_EXCL, r->x.cx, 0, NULL); res2dos(res, r); if (res >= 0) r->x.ax = (WORD) res; /* The new handle */ return; /* DOS 3.0+ - Get current PSP address */ case 0x62: LOG_PRINTF(("INT 21h - Get current PSP address\n")); r->x.bx = (DWORD) current_psp >> 4; return; /* DOS 3.3+ - "FFLUSH" - Commit file * and DOS 4.0+ Undocumented - Commit file (BX=file handle). */ case 0x68: case 0x6A: LOG_PRINTF(("INT 21h - fflush\n")); /* BX file handle */ res = fd32_fflush(r->x.bx); break; /* DOS 5+ Undocumented - Null function */ case 0x6B: LOG_PRINTF(("INT 21h - Null function. Hey, somebody calls it!\n")); r->h.al = 0; RMREGS_CLEAR_CARRY; return; /* DOS 4.0+ - Extended open/create file (AL=00h, BL=access and sharing mode, * BH=flags, CX=attributes for creation, DL=action, DH=00h, DS:DI->ASCIZ file name). */ case 0x6C: { int action; res = parse_open_action(r->x.dx); if (res < 0) break; action = res; res = fix_path(fn, (const char *) FAR2ADDR(r->x.ds, r->x.si), sizeof(fn)); if (res < 0) break; res = fd32_open(fn, action | (DWORD) r->x.bx, r->x.cx, 0, &action); LOG_PRINTF(("INT 21h - Extended open/create (AH=6Ch) \"%s\" res=%08xh\n", fn, res)); res2dos(res, r); if (res >= 0) { r->x.ax = (WORD) res; /* The new handle */ r->x.cx = (WORD) action; /* Action taken */ } return; } /* Long File Name functions */ case 0x71: if (use_lfn) lfn_functions(r); else { r->x.ax = 0x7100; /* Yet another convention */ RMREGS_SET_CARRY; } return; /* Windows 95 beta - "FindClose" - Terminate directory search * _Guessing_ that BX is the directory handle. */ case 0x72: res = fd32_lfn_findclose(r->x.bx); break; /* Windows 95 FAT32 services. * Only AH=03h "Get extended free space on drive" is currently supported. */ case 0x73: { ExtDiskFree *edf; fd32_getfsfree_t fsfree; LOG_PRINTF(("INT 21h - FAT32 service %02x issued\n", r->h.al)); if (r->h.al != 0x03) { r->h.al = 0xFF; /* Unimplemented subfunction */ RMREGS_SET_CARRY; return; } /* DS:DX->ASCIZ string for drive ("C:\" or "\\SERVER\Share") * ES:DI->Buffer for extended free space structure (ExtFreSpace) * CX=size of ES:DI buffer */ if (r->x.cx < sizeof(ExtDiskFree)) { r->x.ax = DOS_EBUFSMALL; RMREGS_SET_CARRY; return; } edf = (ExtDiskFree *) FAR2ADDR(r->x.es, r->x.di); if (edf->Version != 0x0000) { r->x.ax = DOS_EINVAL; RMREGS_SET_CARRY; return; } fsfree.Size = sizeof(fd32_getfsfree_t); res = fix_path(fn, (const char *) FAR2ADDR(r->x.ds, r->x.dx), sizeof(fn)); if (res < 0) break; res = fd32_get_fsfree(fn, &fsfree); if (res >= 0) { edf->Size = sizeof(ExtDiskFree); /* Currently we don't support volume compression */ edf->SecPerClus = fsfree.SecPerClus; edf->BytesPerSec = fsfree.BytesPerSec; edf->AvailClus = fsfree.AvailClus; edf->TotalClus = fsfree.TotalClus; edf->RealSecPerClus = fsfree.SecPerClus; edf->RealBytesPerSec = fsfree.BytesPerSec; edf->RealAvailClus = fsfree.AvailClus; edf->RealTotalClus = fsfree.TotalClus; } break; } /* Unsupported or invalid functions */ default: r->x.ax = DOS_ENOTSUP; RMREGS_SET_CARRY; return; } res2dos(res, r);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -