def setup_lib(self, ctx): AmigaLibrary.setup_lib(self, ctx) log_dos.info("open dos.library V%d", self.version) # init own state self.io_err = 0 self.cur_dir_lock = None self.ctx = ctx self.mem_allocs = {} self.seg_lists = {} self.matches = {} self.rdargs = {} self.dos_objs = {} # setup RootNode self.root_struct = ctx.alloc.alloc_struct("RootNode", RootNodeDef) self.access.w_s("dl_Root", self.root_struct.addr) # setup DosInfo self.dos_info = ctx.alloc.alloc_struct("DosInfo", DosInfoDef) self.root_struct.access.w_s("rn_Info", self.dos_info.addr) # setup dos list self.dos_list = DosList(ctx.alloc) baddr = self.dos_list.build_list(ctx.path_mgr) # create lock manager self.lock_mgr = LockManager(ctx.path_mgr, self.dos_list, ctx.alloc) # create file manager self.file_mgr = FileManager(ctx.path_mgr, ctx.alloc, ctx.mem) # currently we use a single fake port for all devices self.fs_handler_port = ctx.exec_lib.port_mgr.create_port( "FakeFSPort", self.file_mgr) log_dos.info("dos fs handler port: %06x" % self.fs_handler_port) self.file_mgr.setup(self.fs_handler_port)
def setup_lib(self, ctx): AmigaLibrary.setup_lib(self, ctx) log_dos.info("open dos.library V%d", self.version) # init own state self.io_err = 0 self.cur_dir_lock = None self.ctx = ctx self.mem_allocs = {} self.seg_lists = {} self.matches = {} self.rdargs = {} self.dos_objs = {} # setup RootNode self.root_struct = ctx.alloc.alloc_struct("RootNode",RootNodeDef) self.access.w_s("dl_Root",self.root_struct.addr) # setup DosInfo self.dos_info = ctx.alloc.alloc_struct("DosInfo",DosInfoDef) self.root_struct.access.w_s("rn_Info",self.dos_info.addr) # setup dos list self.dos_list = DosList(ctx.alloc) baddr = self.dos_list.build_list(ctx.path_mgr) # create lock manager self.lock_mgr = LockManager(ctx.path_mgr, self.dos_list, ctx.alloc) # create file manager self.file_mgr = FileManager(ctx.path_mgr, ctx.alloc, ctx.mem) # currently we use a single fake port for all devices self.fs_handler_port = ctx.exec_lib.port_mgr.create_port("FakeFSPort",self.file_mgr) log_dos.info("dos fs handler port: %06x" % self.fs_handler_port) self.file_mgr.setup(self.fs_handler_port)
class DosLibrary(AmigaLibrary): name = "dos.library" DOSFALSE = 0 DOSTRUE = 0xffffffff def __init__(self, mem, alloc, config): AmigaLibrary.__init__(self, self.name, DosLibraryDef, config) self.mem = mem self.alloc = alloc def setup_lib(self, ctx): AmigaLibrary.setup_lib(self, ctx) log_dos.info("open dos.library V%d", self.version) # init own state self.io_err = 0 self.cur_dir_lock = None self.ctx = ctx self.mem_allocs = {} self.seg_lists = {} self.matches = {} self.rdargs = {} self.dos_objs = {} # setup RootNode self.root_struct = ctx.alloc.alloc_struct("RootNode",RootNodeDef) self.access.w_s("dl_Root",self.root_struct.addr) # setup DosInfo self.dos_info = ctx.alloc.alloc_struct("DosInfo",DosInfoDef) self.root_struct.access.w_s("rn_Info",self.dos_info.addr) # setup dos list self.dos_list = DosList(ctx.alloc) baddr = self.dos_list.build_list(ctx.path_mgr) # create lock manager self.lock_mgr = LockManager(ctx.path_mgr, self.dos_list, ctx.alloc) # create file manager self.file_mgr = FileManager(ctx.path_mgr, ctx.alloc, ctx.mem) # currently we use a single fake port for all devices self.fs_handler_port = ctx.exec_lib.port_mgr.create_port("FakeFSPort",self.file_mgr) log_dos.info("dos fs handler port: %06x" % self.fs_handler_port) self.file_mgr.setup(self.fs_handler_port) def finish_lib(self, ctx): # free port ctx.exec_lib.port_mgr.free_port(self.fs_handler_port) # finish file manager self.file_mgr.finish() # free dos list self.dos_list.free_list() # free RootNode ctx.alloc.free_struct(self.root_struct) # free DosInfo ctx.alloc.free_struct(self.dos_info) AmigaLibrary.finish_lib(self, ctx) # ----- IoErr ----- def IoErr(self, ctx): log_dos.info("IoErr: %d (%s)" % (self.io_err, dos_error_strings[self.io_err])) return self.io_err def SetIoErr(self, ctx): old_io_err = self.io_err self.io_err = ctx.cpu.r_reg(REG_D1) log_dos.info("SetIoErr: IoErr=%d old IoErr=%d", self.io_err, old_io_err) return old_io_err def PrintFault(self, ctx): self.io_err = ctx.cpu.r_reg(REG_D1) hdr_ptr = ctx.cpu.r_reg(REG_D2) # get header string if hdr_ptr != 0: hdr = ctx.mem.access.r_cstr(hdr_ptr) else: hdr = "" # get error string if dos_error_strings.has_key(self.io_err): err_str = dos_error_strings[self.io_err] else: err_str = "??? ERROR" log_dos.info("PrintFault: code=%d header='%s' err_str='%s'", self.io_err, hdr, err_str) # write to stdout txt = "%s: %s\n" % (hdr, err_str) fh = self.file_mgr.get_output() fh.write(txt) return self.DOSTRUE # ----- dos API ----- def DateStamp(self, ctx): ds_ptr = ctx.cpu.r_reg(REG_D1) ds = AccessStruct(ctx.mem,DateStampDef,struct_addr=ds_ptr) t = time.time() at = sys_to_ami_time(t) log_dos.info("DateStamp: ptr=%06x sys_time=%d time=%s", ds_ptr, t, at) ds.w_s("ds_Days",at.tday) ds.w_s("ds_Minute",at.tmin) ds.w_s("ds_Tick",at.tick) return ds_ptr def DateToStr(self, ctx): dt_ptr = ctx.cpu.r_reg(REG_D1) dt = AccessStruct(ctx.mem,DateTimeDef,struct_addr=dt_ptr) ds_day = dt.r_s("dat_Stamp.ds_Days") ds_min = dt.r_s("dat_Stamp.ds_Minute") ds_tick = dt.r_s("dat_Stamp.ds_Tick") format = dt.r_s("dat_Format") flags = dt.r_s("dat_Flags") str_day_ptr = dt.r_s("dat_StrDay") str_date_ptr = dt.r_s("dat_StrDate") str_time_ptr = dt.r_s("dat_StrTime") at = AmiTime(ds_day, ds_min, ds_tick) st = at.to_sys_time() log_dos.info("DateToStr: ptr=%06x format=%x flags=%x day_ptr=%06x date_ptr=%06x time_ptr=%06x %s => sys_time=%d", \ dt_ptr, format, flags, str_day_ptr, str_date_ptr, str_time_ptr, at, st) t = time.gmtime(st) day_str = time.strftime("%A", t) date_str = time.strftime("%d-%m-%y", t) time_str = time.strftime("%H:%M:%S", t) log_dos.info("DateToStr: result day='%s' date='%s' time='%s'", day_str, date_str, time_str) if str_day_ptr != 0: ctx.mem.access.w_cstr(str_day_ptr, day_str) if str_date_ptr != 0: ctx.mem.access.w_cstr(str_date_ptr, date_str) if str_time_ptr != 0: ctx.mem.access.w_cstr(str_time_ptr, time_str) return self.DOSTRUE # ----- ENV: Vars ----- def GetVar(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) buff_ptr = ctx.cpu.r_reg(REG_D2) size = ctx.cpu.r_reg(REG_D3) flags = ctx.cpu.r_reg(REG_D4) if size == 0: self.io_err = ERROR_BAD_NUMBER return self.DOSFALSE name = ctx.mem.access.r_cstr(name_ptr) ctx.mem.access.w_cstr(buff_ptr, '') log_dos.info('GetVar("%s", 0x%x, %d, 0x%x) -> -1' % (name, buff_ptr, size, flags)) self.io_err = ERROR_OBJECT_NOT_FOUND return self.DOSFALSE # ----- File Ops ----- def Cli(self, ctx): cli_addr = ctx.process.get_cli_struct() log_dos.info("Cli() -> %06x" % cli_addr) return cli_addr def Input(self, ctx): fh = ctx.process.get_input() log_dos.info("Input() -> %s" % fh) return fh.b_addr def Output(self, ctx): fh = ctx.process.get_output() log_dos.info("Output() -> %s" % fh) return fh.b_addr def SelectInput(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) fh = self.file_mgr.get_by_b_addr(fh_b_addr) log_dos.info("SelectInput(fh=%s)" % fh) ctx.process.set_input(fh) def SelectOutput(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) fh = self.file_mgr.get_by_b_addr(fh_b_addr) log_dos.info("SelectOutput(fh=%s)" % fh) ctx.process.set_output(fh) def Open(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) name = ctx.mem.access.r_cstr(name_ptr) mode = ctx.cpu.r_reg(REG_D2) # decode mode if mode == 1006: mode_name = "new" f_mode = "wb+" elif mode == 1005: mode_name = "old" f_mode = "rb+" elif mode == 1004: mode_name = "r/w" f_mode = "rb+" else: mode_name = "?" fh = self.file_mgr.open(name, f_mode) log_dos.info("Open: name='%s' (%s/%d/%s) -> %s" % (name, mode_name, mode, f_mode, fh)) if fh == None: self.io_err = ERROR_OBJECT_NOT_FOUND return 0 else: return fh.b_addr def Close(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) fh = self.file_mgr.get_by_b_addr(fh_b_addr) self.file_mgr.close(fh) log_dos.info("Close: %s" % fh) return self.DOSTRUE def Read(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) buf_ptr = ctx.cpu.r_reg(REG_D2) size = ctx.cpu.r_reg(REG_D3) fh = self.file_mgr.get_by_b_addr(fh_b_addr) data = fh.read(size) ctx.mem.access.w_data(buf_ptr, data) got = len(data) log_dos.info("Read(%s, %06x, %d) -> %d" % (fh, buf_ptr, size, got)) return got def Write(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) buf_ptr = ctx.cpu.r_reg(REG_D2) size = ctx.cpu.r_reg(REG_D3) fh = self.file_mgr.get_by_b_addr(fh_b_addr) data = ctx.mem.access.r_data(buf_ptr,size) fh.write(data) got = len(data) log_dos.info("Write(%s, %06x, %d) -> %d" % (fh, buf_ptr, size, got)) return size def Seek(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) pos = ctx.cpu.r_reg(REG_D2) mode = ctx.cpu.r_reg(REG_D3) fh = self.file_mgr.get_by_b_addr(fh_b_addr) if mode == 0xffffffff: mode_str = "BEGINNING" whence = 0 elif mode == 0: mode_str = "CURRENT" whence = 1 elif mode == 1: mode_str = "END" whence = 2 else: raise UnsupportedFeatureError("Seek: mode=%d" % mode) old_pos = fh.tell() fh.seek(pos, whence) log_dos.info("Seek(%s, %06x, %s) -> old_pos=%06x" % (fh, pos, mode_str, old_pos)) return old_pos def FGetC(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) fh = self.file_mgr.get_by_b_addr(fh_b_addr) ch = fh.getc() log_dos.info("FGetC(%s) -> '%c' (%d)" % (fh, ch, ch)) return ch def FPutC(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) val = ctx.cpu.r_reg(REG_D2) fh = self.file_mgr.get_by_b_addr(fh_b_addr) log_dos.info("FPutC(%s, '%c' (%d))" % (fh, val, val)) fh.write(chr(val)) return val def UnGetC(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) val = ctx.cpu.r_reg(REG_D2) fh = self.file_mgr.get_by_b_addr(fh_b_addr) ch = fh.ungetc(val) log_dos.info("UnGetC(%s, %d) -> ch=%c (%d)" % (fh, val, ch, ch)) return ch # ----- StdOut ----- def PutStr(self, ctx): str_ptr = ctx.cpu.r_reg(REG_D1) str_dat = ctx.mem.access.r_cstr(str_ptr) # write to stdout fh = self.file_mgr.get_output() ok = fh.write(str_dat) log_dos.info("PutStr: '%s'", str_dat) return 0 # ok def VPrintf(self, ctx): format_ptr = ctx.cpu.r_reg(REG_D1) argv_ptr = ctx.cpu.r_reg(REG_D2) fmt = ctx.mem.access.r_cstr(format_ptr) # write on output fh = self.file_mgr.get_output() log_dos.info("VPrintf: format='%s' argv=%06x" % (fmt,argv_ptr)) # now decode printf ps = dos.Printf.printf_parse_string(fmt) dos.Printf.printf_read_data(ps, ctx.mem.access, argv_ptr) log_dos.debug("VPrintf: parsed format: %s",ps) result = dos.Printf.printf_generate_output(ps) # write result fh.write(result) return len(result) def VFPrintf(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) fh = self.file_mgr.get_by_b_addr(fh_b_addr) format_ptr = ctx.cpu.r_reg(REG_D2) argv_ptr = ctx.cpu.r_reg(REG_D3) fmt = ctx.mem.access.r_cstr(format_ptr) # write on output log_dos.info("VFPrintf: format='%s' argv=%06x" % (fmt,argv_ptr)) # now decode printf ps = dos.Printf.printf_parse_string(fmt) dos.Printf.printf_read_data(ps, ctx.mem.access, argv_ptr) log_dos.debug("VFPrintf: parsed format: %s",ps) result = dos.Printf.printf_generate_output(ps) # write result fh.write(result) return len(result) def VFWritef(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) fh = self.file_mgr.get_by_b_addr(fh_b_addr) fmt_ptr = ctx.cpu.r_reg(REG_D2) args_ptr = ctx.cpu.r_reg(REG_D3) fmt = ctx.mem.access.r_cstr(fmt_ptr) log_dos.info("VFWritef: fh=%s format='%s' args_ptr=%06x" % (fh, fmt, args_ptr)) out = '' pos = 0 state = '' while pos < len(fmt): ch = fmt[pos] pos = pos + 1 if state[0:0] == 'x': n = ord(ch.ascii_uppercase) if n >= ord('0') and n <= ord('9'): n = n - ord('0') elif n >= ord('A') and n <= ord('Z'): n = (n - ord('A')) + 10 else: n = 0 ch = state[1] if ch == 'T': out = out + ("%*s" % (n, ctx.mem.access.r_cstr(val))) elif ch == 'O': out = out + ("%*O" % (n, val)) elif ch == 'X': out = out + ("%*X" % (n, val)) elif ch == 'I': out = out + ("%*ld" % (n, ctypes.c_long(val).value)) elif ch == 'U': out = out + ("%*lu" % (n, ctypes.c_ulong(val).value)) else: out = out + '%' + state[1] + state[0] state = '' elif state == '%': if ch == 'S': out = out + ctx.mem.access.r_cstr(val) elif ch == 'C': out = out + chr(val & 0xff) elif ch == 'N': out = out + ("%ld", ctypes.c_long(val).value) elif ch == '$': pass elif ch == 'T' or ch == 'O' or ch == 'X' or ch == 'I' or ch == 'U': state = 'x' + ch else: state = '' out = out + '%' + ch else: if ch == '%': state = '%' val = ctx.mem.access.r32(args_ptr) args_ptr = args_ptr + 4 else: out = out + ch fh.write(out) return len(out) # ----- File Ops ----- def DeleteFile(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) name = ctx.mem.access.r_cstr(name_ptr) self.io_err = self.file_mgr.delete(name) log_dos.info("DeleteFile: '%s': err=%s" % (name, self.io_err)) if self.io_err == NO_ERROR: return self.DOSTRUE else: return self.DOSFALSE def Rename(self, ctx): old_name_ptr = ctx.cpu.r_reg(REG_D1) old_name = ctx.mem.access.r_cstr(old_name_ptr) new_name_ptr = ctx.cpu.r_reg(REG_D2) new_name = ctx.mem.access.r_cstr(new_name_ptr) self.io_err = self.file_mgr.rename(old_name, new_name) log_dos.info("Rename: '%s' -> '%s': err=%s" % (old_name, new_name, self.io_err)) if self.io_err == NO_ERROR: return self.DOSTRUE else: return self.DOSFALSE def SetProtection(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) name = ctx.mem.access.r_cstr(name_ptr) mask = ctx.cpu.r_reg(REG_D2) self.io_err = self.file_mgr.set_protection(name, mask) log_dos.info("SetProtection: '%s' mask=%04x: err=%s", name, mask, self.io_err) if self.io_err == NO_ERROR: return self.DOSTRUE else: return self.DOSFALSE def IsInteractive(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) fh = self.file_mgr.get_by_b_addr(fh_b_addr) res = fh.is_interactive() log_dos.info("IsInteractive(%s): %s" % (fh, res)) if res: return self.DOSTRUE else: return self.DOSFALSE def IsFileSystem(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) name = ctx.mem.access.r_cstr(name_ptr) res = self.file_mgr.is_file_system(name) log_dos.info("IsFileSystem('%s'): %s" % (name, res)) if res: return self.DOSTRUE else: return self.DOSFALSE # ----- Locks ----- def Lock(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) name = ctx.mem.access.r_cstr(name_ptr) mode = ctx.cpu.r_reg(REG_D2) if mode == 0xffffffff: lock_exclusive = True elif mode == 0xfffffffe: lock_exclusive = False else: raise UnsupportedFeatureError("Lock: mode=%x" % mode) lock = self.lock_mgr.create_lock(name, lock_exclusive) log_dos.info("Lock: '%s' exc=%s -> %s" % (name, lock_exclusive, lock)) if lock == None: self.io_err = ERROR_OBJECT_NOT_FOUND return 0 else: return lock.b_addr def UnLock(self, ctx): lock_b_addr = ctx.cpu.r_reg(REG_D1) if lock_b_addr == 0: log_dos.info("UnLock: NULL") else: lock = self.lock_mgr.get_by_b_addr(lock_b_addr) log_dos.info("UnLock: %s" % (lock)) self.lock_mgr.release_lock(lock) def DupLock(self, ctx): lock_b_addr = ctx.cpu.r_reg(REG_D1) lock = self.lock_mgr.get_by_b_addr(lock_b_addr) dup_lock = self.lock_mgr.create_lock(lock.ami_path, False) log_dos.info("DupLock: %s -> %s",lock, dup_lock) self.io_err = NO_ERROR return dup_lock.b_addr def Examine(self, ctx): lock_b_addr = ctx.cpu.r_reg(REG_D1) fib_ptr = ctx.cpu.r_reg(REG_D2) lock = self.lock_mgr.get_by_b_addr(lock_b_addr) log_dos.info("Examine: %s fib=%06x" % (lock, fib_ptr)) fib = AccessStruct(ctx.mem,FileInfoBlockDef,struct_addr=fib_ptr) self.io_err = lock.examine_lock(fib) if self.io_err == NO_ERROR: return self.DOSTRUE else: return self.DOSFALSE def ExNext(self, ctx): lock_b_addr = ctx.cpu.r_reg(REG_D1) fib_ptr = ctx.cpu.r_reg(REG_D2) lock = self.lock_mgr.get_by_b_addr(lock_b_addr) log_dos.info("ExNext: %s fib=%06x" % (lock, fib_ptr)) fib = AccessStruct(ctx.mem,FileInfoBlockDef,struct_addr=fib_ptr) self.io_err = lock.examine_next(fib) if self.io_err == NO_ERROR: return self.DOSTRUE else: return self.DOSFALSE def ParentDir(self, ctx): lock_b_addr = ctx.cpu.r_reg(REG_D1) lock = self.lock_mgr.get_by_b_addr(lock_b_addr) parent_lock = self.lock_mgr.create_parent_lock(lock) log_dos.info("ParentDir: %s -> %s" % (lock, parent_lock)) if parent_lock != None: return parent_lock.b_addr else: return 0 def CurrentDir(self, ctx): lock_b_addr = ctx.cpu.r_reg(REG_D1) old_lock = self.cur_dir_lock if lock_b_addr == 0: new_lock = None else: new_lock = self.lock_mgr.get_by_b_addr(lock_b_addr) self.cur_dir_lock = new_lock log_dos.info("CurrentDir(b@%x): %s -> %s" % (lock_b_addr, old_lock, new_lock)) # set current path in path mgr if new_lock != None: ctx.path_mgr.set_cur_path(new_lock.ami_path) else: ctx.path_mgr.set_default_cur_path() if old_lock == None: return 0 else: return old_lock.b_addr def NameFromLock(self, ctx): lock_b_addr = ctx.cpu.r_reg(REG_D1) buf = ctx.cpu.r_reg(REG_D2) buf_len = ctx.cpu.r_reg(REG_D3) if lock_b_addr == 0: name = "SYS:" lock = None else: lock = self.lock_mgr.get_by_b_addr(lock_b_addr) name = lock.ami_path log_dos.info("NameFromLock(%x,%d): %s -> %s", buf, buf_len, lock, name) if len(name) >= buf_len: self.io_err = ERROR_LINE_TOO_LONG return self.DOSFALSE else: ctx.mem.access.w_cstr(buf, name) return self.DOSTRUE def CreateDir(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) name = ctx.mem.access.r_cstr(name_ptr) err = self.file_mgr.create_dir(name) if err != NO_ERROR: self.io_err = err return 0 else: lock = self.lock_mgr.create_lock(name, True) log_dos.info("CreateDir: '%s' -> %s" % (name, lock)) if lock == None: self.io_err = ERROR_OBJECT_NOT_FOUND return 0 else: return lock.b_addr # ----- DevProc ----- def GetDeviceProc(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) last_devproc = ctx.cpu.r_reg(REG_D2) name = ctx.mem.access.r_cstr(name_ptr) # get volume of path abs_name = ctx.path_mgr.ami_abs_path(name) volume = ctx.path_mgr.ami_volume_of_path(abs_name) vol_lock = self.lock_mgr.create_lock(volume+":", False) fs_port = self.file_mgr.get_fs_handler_port() addr = self._alloc_mem("DevProc:%s" % name, DevProcDef.get_size()) log_dos.info("GetDeviceProc: name='%s' devproc=%06x -> volume=%s devproc=%06x", name, last_devproc, volume, addr) devproc = AccessStruct(self.ctx.mem,DevProcDef,struct_addr=addr) devproc.w_s('dvp_Port', fs_port) devproc.w_s('dvp_Lock', vol_lock.b_addr) self.io_err = NO_ERROR return addr def FreeDeviceProc(self, ctx): addr = ctx.cpu.r_reg(REG_D1) self._free_mem(addr) log_dos.info("FreeDeviceProc: devproc=%06x", addr) # ----- Matcher ----- def MatchFirst(self, ctx): pat_ptr = ctx.cpu.r_reg(REG_D1) pat = ctx.mem.access.r_cstr(pat_ptr) anchor_ptr = ctx.cpu.r_reg(REG_D2) anchor = AccessStruct(self.ctx.mem,AnchorPathDef,struct_addr=anchor_ptr) # create MatchFirstNext instance mfn = MatchFirstNext(ctx.path_mgr, self.lock_mgr, pat, anchor) log_dos.info("MatchFirst: pat='%s' anchor=%06x strlen=%d flags=%02x-> ok=%s" \ % (pat, anchor_ptr, mfn.str_len, mfn.flags, mfn.ok)) if not mfn.ok: self.io_err = ERROR_BAD_TEMPLATE return self.io_err log_dos.debug("MatchFirst: %s" % mfn.matcher) # try first match self.io_err = mfn.first(ctx) if self.io_err == NO_ERROR: log_dos.info("MatchFirst: found name='%s' path='%s' -> parent lock %s, io_err=%d", mfn.name, mfn.path, mfn.dir_lock, self.io_err) self.matches[anchor_ptr] = mfn # no entry found or error elif self.io_err == ERROR_OBJECT_NOT_FOUND: log_dos.info("MatchFirst: none found") self.matches[anchor_ptr] = mfn else: log_dos.info("MatchFirst: error: %d", self.io_err) return self.io_err def MatchNext(self, ctx): anchor_ptr = ctx.cpu.r_reg(REG_D1) log_dos.info("MatchNext: anchor=%06x" % (anchor_ptr)) # retrieve match if not self.matches.has_key(anchor_ptr): raise VamosInternalError("MatchNext: No matcher found for %06x" % anchor_ptr) mfn = self.matches[anchor_ptr] # has matches? if mfn != None: self.io_err = mfn.next(ctx) if self.io_err == NO_ERROR: log_dos.info("MatchNext: found name='%s' path=%s -> parent lock %s, io_err=%d", mfn.name, mfn.path, mfn.dir_lock, self.io_err) elif self.io_err == ERROR_NO_MORE_ENTRIES: log_dos.info("MatchNext: no more entries!") else: log_dos.info("MatchNext: error: %d", self.io_err) return self.io_err def MatchEnd(self, ctx): anchor_ptr = ctx.cpu.r_reg(REG_D1) log_dos.info("MatchEnd: anchor=%06x " % (anchor_ptr)) # retrieve match if not self.matches.has_key(anchor_ptr): raise VamosInternalError("MatchEnd: No matcher found for %06x" % anchor_ptr) mfn = self.matches[anchor_ptr] del self.matches[anchor_ptr] if mfn != None: mfn.end(ctx) # ----- Pattern Parsing and Matching ----- def ParsePattern(self, ctx, ignore_case=False): src_ptr = ctx.cpu.r_reg(REG_D1) dst_ptr = ctx.cpu.r_reg(REG_D2) dst_len = ctx.cpu.r_reg(REG_D3) src = ctx.mem.access.r_cstr(src_ptr) pat = pattern_parse(src, ignore_case=ignore_case) log_dos.info("ParsePattern: src=%s ignore_case=%s -> pat=%s",src, ignore_case, pat) if pat == None: self.io_err = ERROR_BAD_TEMPLATE return -1 else: self.io_err = NO_ERROR pat_str = pat.pat_str if len(pat_str) >= dst_len: return -1 else: ctx.mem.access.w_cstr(dst_ptr, pat_str) if pat.has_wildcard: return 1 else: return 0 def ParsePatternNoCase(self, ctx): return self.ParsePattern(ctx, ignore_case=True) def MatchPattern(self, ctx, ignore_case=False): pat_ptr = ctx.cpu.r_reg(REG_D1) txt_ptr = ctx.cpu.r_reg(REG_D2) pat = ctx.mem.access.r_cstr(pat_ptr) txt = ctx.mem.access.r_cstr(txt_ptr) match = pattern_match(pat, txt) log_dos.info("MatchPattern: pat=%s txt=%s ignore_case=%s -> match=%s", pat, txt, ignore_case, match) if match: return -1 else: return 0 def MatchPatternNoCase(self, ctx): return self.MatchPattern(ctx, ignore_case=True) # ----- Args ----- def ReadArgs(self, ctx): template_ptr = ctx.cpu.r_reg(REG_D1) template = ctx.mem.access.r_cstr(template_ptr) array_ptr = ctx.cpu.r_reg(REG_D2) rdargs_ptr = ctx.cpu.r_reg(REG_D3) # get args from process bin_args = ctx.process.bin_args log_dos.info("ReadArgs: args=%s template='%s' array_ptr=%06x rdargs_ptr=%06x" % (bin_args, template, array_ptr, rdargs_ptr)) # try to parse argument string args = Args() args.parse_template(template) args.prepare_input(ctx.mem.access,array_ptr) ok = args.parse_string(bin_args) if not ok: self.io_err = args.error log_dos.info("ReadArgs: not matched -> io_err=%d/%s",self.io_err, dos_error_strings[self.io_err]) return 0 log_dos.debug("matched template: %s",args.get_result()) # calc size of result size = args.calc_result_size() log_dos.debug("longs=%d chars=%d size=%d" % (args.num_longs,args.num_chars,size)) # alloc result mem (extra longs and cstrs) if size > 0: addr = self._alloc_mem("ReadArgs(@%06x)" % self.get_callee_pc(ctx),size) else: addr = 0 # fill result array and memory args.generate_result(ctx.mem.access,addr,array_ptr) # alloc RD_Args if rdargs_ptr == 0: rdargs = ctx.alloc.alloc_struct("RDArgs", RDArgsDef) own = True else: rdargs = ctx.alloc.map_struct("RDArgs", rdargs_ptr, RDArgsDef) own = False rdargs.access.w_s('RDA_Buffer',addr) rdargs.access.w_s('RDA_BufSiz',size) # store rdargs self.rdargs[rdargs.addr] = (rdargs, own) # result self.io_err = NO_ERROR log_dos.info("ReadArgs: matched! result_mem=%06x rdargs=%s", addr, rdargs) return rdargs.addr def FreeArgs(self, ctx): rdargs_ptr = ctx.cpu.r_reg(REG_D1) log_dos.info("FreeArgs: %06x" % rdargs_ptr) # find rdargs if not self.rdargs.has_key(rdargs_ptr): raise VamosInternalError("Can't find RDArgs: %06x" % rdargs_ptr) rdargs, own = self.rdargs[rdargs_ptr] del self.rdargs[rdargs_ptr] # clean up rdargs addr = rdargs.access.r_s('RDA_Buffer') if addr != 0: self._free_mem(addr) # free our memory if own: self.alloc.free_struct(rdargs) def cs_get(self, ctx): if self.cs_input: ch = self.cs_input.getc() else: if self.cs_curchr < self.cs_length: ch = ctx.mem.access.r8(self.cs_buffer + self.cs_curchr) self.cs_curchr = self.cs_curchr + 1 else: ch = -1 return ch def cs_unget(self, ctx): if self.cs_input: self.cs_input.ungetc(-1) else: self.cs_curchr = self.cs_curchr - 1 def ReadItem(self, ctx): buff_ptr = ctx.cpu.r_reg(REG_D1) maxchars = ctx.cpu.r_reg(REG_D2) csource_ptr = ctx.cpu.r_reg(REG_D3) log_dos.info("ReadItem: buff_ptr=%06x maxchars=%d csource_ptr=%06x" % (buff_ptr, maxchars, csource_ptr)) if (csource_ptr): csource = ctx.alloc.map_struct("CSource", csource_ptr, CSourceDef) self.cs_input = None self.cs_buffer = csource.access.r_s('CS_Buffer') self.cs_length = csource.access.r_s('CS_Length') self.cs_curchr = csource.access.r_s('CS_CurChr') else: self.cs_input = ctx.process.get_input() if buff_ptr == 0: return 0 # ITEM_NOTHING # Well Known Bug: buff[0] = 0, even if maxchars == 0 ctx.mem.access.w8(buff_ptr, 0) # Skip leading whitespace while True: ch = self.cs_get(ctx) if ch != ord(" ") and ch != ord("\t"): break if ch == 0 or ch == ord("\n") or ch < 0 or ch == ord(";"): if ch >= 0: self.cs_unget(ctx) return 0 # ITEM_NOTHING if ch == ord("="): return -2 # ITEM_EQUAL if ch == ord("\""): while True: if maxchars <= 0: ctx.mem.access.w8(buff_ptr - 1, 0) return 0 # ITEM_NOTHING maxchars = maxchars - 1 ch = self.cs_get(ctx) if ch == ord("*"): ch = self.cs_get(ctx) if ch == 0 or ch == ord("\n") or ch < 0: self.cs_unget(ctx) ctx.mem.access.w8(buff_ptr, 0) return -1 # ITEM_ERROR elif ch == ord("n") or ch == ord("N"): ch = ord("\n") elif ch == ord("e") or ch == ord("E"): ch = 0x1b elif ch == 0 or ch == ord("\n") or ch < 0: self.cs_ungetc(ctx) ctx.mem.access.w8(buff_ptr, 0) return -1 # ITEM_ERROR elif ch == ord("\""): ctx.mem.access.w8(buff_ptr, 0) return 2 # ITEM_QUOTED ctx.mem.access.w8(buff_ptr, ch) buff_ptr = buff_ptr + 1 pass else: if maxchars <= 0: ctx.mem.access.w8(buff_ptr - 1, 0) return -1 # ITEM_ERROR maxchars = maxchars - 1 ctx.mem.access.w8(buff_ptr, ch) buff_ptr = buff_ptr + 1 while True: if maxchars <= 0: ctx.mem.access.w8(buff_ptr - 1, 0) return -1 # ITEM_ERROR maxchar = maxchars - 1 ch = self.cs_get(ctx) if ch == 0 or ch == ord("\n") or ch == ord(" ") or ch == ord("\t") or ch == ord("=") or ch < 0: # Know Bug: Don't UNGET for a space or equals sign if ch != ord("=") and ch != ord(" ") and ch != ord("\t"): self.cs_unget(ctx) ctx.mem.access.w8(buff_ptr, 0) return 1 # ITEM_UNQUOTED ctx.mem.access.w8(buff_ptr, ch) buff_ptr = buff_ptr + 1 # ----- System/Execute ----- def SystemTagList(self, ctx): cmd_ptr = ctx.cpu.r_reg(REG_D1) tagitem_ptr = ctx.cpu.r_reg(REG_D2) cmd = ctx.mem.access.r_cstr(cmd_ptr) tag_list = taglist_parse_tagitem_ptr(ctx.mem, tagitem_ptr, DosTags) log_dos.info("SystemTagList: cmd='%s' tags=%s", cmd, tag_list) # parse "command line" cl = CommandLine() if not cl.parse_string(cmd): log_dos.info("SystemTagList: error parsing command: '%s'", cmd) return 10 # RETURN_ERROR args = cl.args if len(args) == 0: log_dos.info("SystemTagList: error parsing command: '%s'", cmd) return 10 # RETURN_ERROR bin = args[0] args = args[1:] # TODO: redirs log_dos.info("SystemTagList: bin='%s' args=%s", bin, args) # create a process and run it... proc = Process(ctx, bin, args) if not proc.ok: log_dos.warn("SystemTagList: can't create process for '%s' args=%s", bin, args) return 0xffffffff ctx.start_sub_process(proc) def LoadSeg(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) name = ctx.mem.access.r_cstr(name_ptr) seg_list = self.ctx.seg_loader.load_seg(name) if seg_list == None: log_dos.warn("LoadSeg: '%s' -> not found!" % (name)) return 0 else: log_dos.warn("LoadSeg: '%s' -> %s" % (name, seg_list)) b_addr = seg_list.b_addr self.seg_lists[b_addr] = seg_list return b_addr def UnLoadSeg(self, ctx): b_addr = ctx.cpu.r_reg(REG_D1) if not self.seg_lists.has_key(b_addr): raise VamosInternalError("Unknown LoadSeg seg_list: b_addr=%06x" % b_addr) else: seg_list = self.seg_lists[b_addr] del self.seg_lists[b_addr] self.ctx.seg_loader.unload_seg(seg_list) # ----- Path Helper ----- def FilePart(self, ctx): addr = ctx.cpu.r_reg(REG_D1) path = ctx.mem.access.r_cstr(addr) pos = dos.PathPart.file_part(path) if pos < len(path): log_dos.info("FilePart: path='%s' -> result='%s'", path, path[pos:]) else: log_dos.info("FilePart: path='%s' -> pos=NULL", path) return addr + pos def PathPart(self, ctx): addr = ctx.cpu.r_reg(REG_D1) path = ctx.mem.access.r_cstr(addr) pos = dos.PathPart.path_part(path) if pos < len(path): log_dos.info("PathPart: path='%s' -> result='%s'", path, path[pos:]) else: log_dos.info("PathPart: path='%s' -> pos=NULL", path) return addr + pos def AddPart(self, ctx): dn_addr = ctx.cpu.r_reg(REG_D1) fn_addr = ctx.cpu.r_reg(REG_D2) size = ctx.cpu.r_reg(REG_D3) dn = ctx.mem.access.r_cstr(dn_addr) fn = ctx.mem.access.r_cstr(fn_addr) np = dos.PathPart.add_part(dn,fn,size) log_dos.info("AddPart: dn='%s' fn='%s' size=%d -> np='%s'", dn, fn, size, np) if np != None: ctx.mem.access.w_cstr(dn_addr, np) return self.DOSTRUE else: return self.DOSFALSE # ----- DosObjects ----- def AllocDosObject(self, ctx): obj_type = ctx.cpu.r_reg(REG_D1) tags_ptr = ctx.cpu.r_reg(REG_D2) if obj_type == 0: # DOS_FILEHANDLE name = "DOS_FILEHANDLE" struct_def = FileHandleDef elif obj_type == 1: # DOS_EXALLCONTROL name = "DOS_EXALLCONTROL" struct_def = None elif obj_type == 2: # DOS_FIB name = "DOS_FIB" struct_def = FileInfoBlockDef elif obj_type == 3: # DOS_STDPKT name = "DOS_STDPKT" struct_def = DosPacketDef elif obj_type == 4: # DOS_CLI name = "DOS_CLI" struct_def = CLIDef elif obj_type == 5: # DOS_RDARGS name = "DOS_RDARGS" struct_def = RDArgsDef else: log_dos.error("AllocDosObject: invalid type=%d", obj_type) return 0 if struct_def is None: log_dos.warn("AllocDosObject: unsupported type=%d/%s", obj_type, name) return 0 # allocate struct dos_obj = ctx.alloc.alloc_struct(name, struct_def) log_dos.info("AllocDosObject: type=%d/%s tags_ptr=%08x -> dos_obj=%s", obj_type, name, tags_ptr, dos_obj) # store struct ptr = dos_obj.addr self.dos_objs[ptr] = (dos_obj, obj_type) # pre fill struct if obj_type == 0: dos_obj.access.w_s('fh_Pos',0xffffffff) dos_obj.access.w_s('fh_End',0xffffffff) elif obj_type == 4: raise UnsupportedFeatureError("AllocDosObject: DOS_CLI fill TBD") return ptr def FreeDosObject(self, ctx): obj_type = ctx.cpu.r_reg(REG_D1) ptr = ctx.cpu.r_reg(REG_D2) # retrieve struct if ptr in self.dos_objs: entry = self.dos_objs[ptr] del self.dos_objs[ptr] # check type if obj_type != entry[1]: log_dos.warn("FreeDosObject: type mismatch %d != %d", obj_type, entry[1]) # free struct ctx.alloc.free_struct(entry[0]) else: log_dos.error("FreeDosObject: type=%d ptr=%08x -> NOT FOUND!", obj_type, ptr) # ----- Helpers ----- def _alloc_mem(self, name, size): mem = self.alloc.alloc_memory(name,size) self.mem_allocs[mem.addr] = mem return mem.addr def _free_mem(self, addr): if self.mem_allocs.has_key(addr): mem = self.mem_allocs[addr] self.alloc.free_memory(mem) del self.mem_allocs[addr] else: raise VamosInternalError("Invalid DOS free mem: %06x" % addr)
class DosLibrary(AmigaLibrary): name = "dos.library" DOSFALSE = 0 DOSTRUE = 0xffffffff def __init__(self, mem, alloc, config): AmigaLibrary.__init__(self, self.name, DosLibraryDef, config) self.mem = mem self.alloc = alloc def setup_lib(self, ctx): AmigaLibrary.setup_lib(self, ctx) log_dos.info("open dos.library V%d", self.version) # init own state self.io_err = 0 self.cur_dir_lock = None self.ctx = ctx self.mem_allocs = {} self.seg_lists = {} self.matches = {} self.rdargs = {} self.dos_objs = {} # setup RootNode self.root_struct = ctx.alloc.alloc_struct("RootNode", RootNodeDef) self.access.w_s("dl_Root", self.root_struct.addr) # setup DosInfo self.dos_info = ctx.alloc.alloc_struct("DosInfo", DosInfoDef) self.root_struct.access.w_s("rn_Info", self.dos_info.addr) # setup dos list self.dos_list = DosList(ctx.alloc) baddr = self.dos_list.build_list(ctx.path_mgr) # create lock manager self.lock_mgr = LockManager(ctx.path_mgr, self.dos_list, ctx.alloc) # create file manager self.file_mgr = FileManager(ctx.path_mgr, ctx.alloc, ctx.mem) # currently we use a single fake port for all devices self.fs_handler_port = ctx.exec_lib.port_mgr.create_port( "FakeFSPort", self.file_mgr) log_dos.info("dos fs handler port: %06x" % self.fs_handler_port) self.file_mgr.setup(self.fs_handler_port) def finish_lib(self, ctx): # free port ctx.exec_lib.port_mgr.free_port(self.fs_handler_port) # finish file manager self.file_mgr.finish() # free dos list self.dos_list.free_list() # free RootNode ctx.alloc.free_struct(self.root_struct) # free DosInfo ctx.alloc.free_struct(self.dos_info) AmigaLibrary.finish_lib(self, ctx) # ----- IoErr ----- def IoErr(self, ctx): log_dos.info("IoErr: %d (%s)" % (self.io_err, dos_error_strings[self.io_err])) return self.io_err def SetIoErr(self, ctx): old_io_err = self.io_err self.io_err = ctx.cpu.r_reg(REG_D1) log_dos.info("SetIoErr: IoErr=%d old IoErr=%d", self.io_err, old_io_err) return old_io_err def PrintFault(self, ctx): self.io_err = ctx.cpu.r_reg(REG_D1) hdr_ptr = ctx.cpu.r_reg(REG_D2) # get header string if hdr_ptr != 0: hdr = ctx.mem.access.r_cstr(hdr_ptr) else: hdr = "" # get error string if dos_error_strings.has_key(self.io_err): err_str = dos_error_strings[self.io_err] else: err_str = "??? ERROR" log_dos.info("PrintFault: code=%d header='%s' err_str='%s'", self.io_err, hdr, err_str) # write to stdout txt = "%s: %s\n" % (hdr, err_str) fh = self.file_mgr.get_output() fh.write(txt) return self.DOSTRUE # ----- dos API ----- def DateStamp(self, ctx): ds_ptr = ctx.cpu.r_reg(REG_D1) ds = AccessStruct(ctx.mem, DateStampDef, struct_addr=ds_ptr) t = time.time() at = sys_to_ami_time(t) log_dos.info("DateStamp: ptr=%06x sys_time=%d time=%s", ds_ptr, t, at) ds.w_s("ds_Days", at.tday) ds.w_s("ds_Minute", at.tmin) ds.w_s("ds_Tick", at.tick) return ds_ptr def DateToStr(self, ctx): dt_ptr = ctx.cpu.r_reg(REG_D1) dt = AccessStruct(ctx.mem, DateTimeDef, struct_addr=dt_ptr) ds_day = dt.r_s("dat_Stamp.ds_Days") ds_min = dt.r_s("dat_Stamp.ds_Minute") ds_tick = dt.r_s("dat_Stamp.ds_Tick") format = dt.r_s("dat_Format") flags = dt.r_s("dat_Flags") str_day_ptr = dt.r_s("dat_StrDay") str_date_ptr = dt.r_s("dat_StrDate") str_time_ptr = dt.r_s("dat_StrTime") at = AmiTime(ds_day, ds_min, ds_tick) st = at.to_sys_time() log_dos.info("DateToStr: ptr=%06x format=%x flags=%x day_ptr=%06x date_ptr=%06x time_ptr=%06x %s => sys_time=%d", \ dt_ptr, format, flags, str_day_ptr, str_date_ptr, str_time_ptr, at, st) t = time.gmtime(st) day_str = time.strftime("%A", t) date_str = time.strftime("%d-%m-%y", t) time_str = time.strftime("%H:%M:%S", t) log_dos.info("DateToStr: result day='%s' date='%s' time='%s'", day_str, date_str, time_str) if str_day_ptr != 0: ctx.mem.access.w_cstr(str_day_ptr, day_str) if str_date_ptr != 0: ctx.mem.access.w_cstr(str_date_ptr, date_str) if str_time_ptr != 0: ctx.mem.access.w_cstr(str_time_ptr, time_str) return self.DOSTRUE # ----- ENV: Vars ----- def GetVar(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) buff_ptr = ctx.cpu.r_reg(REG_D2) size = ctx.cpu.r_reg(REG_D3) flags = ctx.cpu.r_reg(REG_D4) if size == 0: self.io_err = ERROR_BAD_NUMBER return self.DOSFALSE name = ctx.mem.access.r_cstr(name_ptr) ctx.mem.access.w_cstr(buff_ptr, '') log_dos.info('GetVar("%s", 0x%x, %d, 0x%x) -> -1' % (name, buff_ptr, size, flags)) self.io_err = ERROR_OBJECT_NOT_FOUND return self.DOSFALSE # ----- File Ops ----- def Cli(self, ctx): cli_addr = ctx.process.get_cli_struct() log_dos.info("Cli() -> %06x" % cli_addr) return cli_addr def Input(self, ctx): fh = ctx.process.get_input() log_dos.info("Input() -> %s" % fh) return fh.b_addr def Output(self, ctx): fh = ctx.process.get_output() log_dos.info("Output() -> %s" % fh) return fh.b_addr def SelectInput(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) fh = self.file_mgr.get_by_b_addr(fh_b_addr) log_dos.info("SelectInput(fh=%s)" % fh) ctx.process.set_input(fh) def SelectOutput(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) fh = self.file_mgr.get_by_b_addr(fh_b_addr) log_dos.info("SelectOutput(fh=%s)" % fh) ctx.process.set_output(fh) def Open(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) name = ctx.mem.access.r_cstr(name_ptr) mode = ctx.cpu.r_reg(REG_D2) # decode mode if mode == 1006: mode_name = "new" f_mode = "wb+" elif mode == 1005: mode_name = "old" f_mode = "rb+" elif mode == 1004: mode_name = "r/w" f_mode = "rb+" else: mode_name = "?" fh = self.file_mgr.open(name, f_mode) log_dos.info("Open: name='%s' (%s/%d/%s) -> %s" % (name, mode_name, mode, f_mode, fh)) if fh == None: self.io_err = ERROR_OBJECT_NOT_FOUND return 0 else: return fh.b_addr def Close(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) fh = self.file_mgr.get_by_b_addr(fh_b_addr) self.file_mgr.close(fh) log_dos.info("Close: %s" % fh) return self.DOSTRUE def Read(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) buf_ptr = ctx.cpu.r_reg(REG_D2) size = ctx.cpu.r_reg(REG_D3) fh = self.file_mgr.get_by_b_addr(fh_b_addr) data = fh.read(size) ctx.mem.access.w_data(buf_ptr, data) got = len(data) log_dos.info("Read(%s, %06x, %d) -> %d" % (fh, buf_ptr, size, got)) return got def Write(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) buf_ptr = ctx.cpu.r_reg(REG_D2) size = ctx.cpu.r_reg(REG_D3) fh = self.file_mgr.get_by_b_addr(fh_b_addr) data = ctx.mem.access.r_data(buf_ptr, size) fh.write(data) got = len(data) log_dos.info("Write(%s, %06x, %d) -> %d" % (fh, buf_ptr, size, got)) return size def Seek(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) pos = ctx.cpu.r_reg(REG_D2) mode = ctx.cpu.r_reg(REG_D3) fh = self.file_mgr.get_by_b_addr(fh_b_addr) if mode == 0xffffffff: mode_str = "BEGINNING" whence = 0 elif mode == 0: mode_str = "CURRENT" whence = 1 elif mode == 1: mode_str = "END" whence = 2 else: raise UnsupportedFeatureError("Seek: mode=%d" % mode) old_pos = fh.tell() fh.seek(pos, whence) log_dos.info("Seek(%s, %06x, %s) -> old_pos=%06x" % (fh, pos, mode_str, old_pos)) return old_pos def FGetC(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) fh = self.file_mgr.get_by_b_addr(fh_b_addr) ch = fh.getc() log_dos.info("FGetC(%s) -> '%c' (%d)" % (fh, ch, ch)) return ch def FPutC(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) val = ctx.cpu.r_reg(REG_D2) fh = self.file_mgr.get_by_b_addr(fh_b_addr) log_dos.info("FPutC(%s, '%c' (%d))" % (fh, val, val)) fh.write(chr(val)) return val def UnGetC(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) val = ctx.cpu.r_reg(REG_D2) fh = self.file_mgr.get_by_b_addr(fh_b_addr) ch = fh.ungetc(val) log_dos.info("UnGetC(%s, %d) -> ch=%c (%d)" % (fh, val, ch, ch)) return ch # ----- StdOut ----- def PutStr(self, ctx): str_ptr = ctx.cpu.r_reg(REG_D1) str_dat = ctx.mem.access.r_cstr(str_ptr) # write to stdout fh = self.file_mgr.get_output() ok = fh.write(str_dat) log_dos.info("PutStr: '%s'", str_dat) return 0 # ok def VPrintf(self, ctx): format_ptr = ctx.cpu.r_reg(REG_D1) argv_ptr = ctx.cpu.r_reg(REG_D2) fmt = ctx.mem.access.r_cstr(format_ptr) # write on output fh = self.file_mgr.get_output() log_dos.info("VPrintf: format='%s' argv=%06x" % (fmt, argv_ptr)) # now decode printf ps = dos.Printf.printf_parse_string(fmt) dos.Printf.printf_read_data(ps, ctx.mem.access, argv_ptr) log_dos.debug("VPrintf: parsed format: %s", ps) result = dos.Printf.printf_generate_output(ps) # write result fh.write(result) return len(result) def VFPrintf(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) fh = self.file_mgr.get_by_b_addr(fh_b_addr) format_ptr = ctx.cpu.r_reg(REG_D2) argv_ptr = ctx.cpu.r_reg(REG_D3) fmt = ctx.mem.access.r_cstr(format_ptr) # write on output log_dos.info("VFPrintf: format='%s' argv=%06x" % (fmt, argv_ptr)) # now decode printf ps = dos.Printf.printf_parse_string(fmt) dos.Printf.printf_read_data(ps, ctx.mem.access, argv_ptr) log_dos.debug("VFPrintf: parsed format: %s", ps) result = dos.Printf.printf_generate_output(ps) # write result fh.write(result) return len(result) def VFWritef(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) fh = self.file_mgr.get_by_b_addr(fh_b_addr) fmt_ptr = ctx.cpu.r_reg(REG_D2) args_ptr = ctx.cpu.r_reg(REG_D3) fmt = ctx.mem.access.r_cstr(fmt_ptr) log_dos.info("VFWritef: fh=%s format='%s' args_ptr=%06x" % (fh, fmt, args_ptr)) out = '' pos = 0 state = '' while pos < len(fmt): ch = fmt[pos] pos = pos + 1 if state[0:0] == 'x': n = ord(ch.ascii_uppercase) if n >= ord('0') and n <= ord('9'): n = n - ord('0') elif n >= ord('A') and n <= ord('Z'): n = (n - ord('A')) + 10 else: n = 0 ch = state[1] if ch == 'T': out = out + ("%*s" % (n, ctx.mem.access.r_cstr(val))) elif ch == 'O': out = out + ("%*O" % (n, val)) elif ch == 'X': out = out + ("%*X" % (n, val)) elif ch == 'I': out = out + ("%*ld" % (n, ctypes.c_long(val).value)) elif ch == 'U': out = out + ("%*lu" % (n, ctypes.c_ulong(val).value)) else: out = out + '%' + state[1] + state[0] state = '' elif state == '%': if ch == 'S': out = out + ctx.mem.access.r_cstr(val) elif ch == 'C': out = out + chr(val & 0xff) elif ch == 'N': out = out + ("%ld", ctypes.c_long(val).value) elif ch == '$': pass elif ch == 'T' or ch == 'O' or ch == 'X' or ch == 'I' or ch == 'U': state = 'x' + ch else: state = '' out = out + '%' + ch else: if ch == '%': state = '%' val = ctx.mem.access.r32(args_ptr) args_ptr = args_ptr + 4 else: out = out + ch fh.write(out) return len(out) # ----- File Ops ----- def DeleteFile(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) name = ctx.mem.access.r_cstr(name_ptr) self.io_err = self.file_mgr.delete(name) log_dos.info("DeleteFile: '%s': err=%s" % (name, self.io_err)) if self.io_err == NO_ERROR: return self.DOSTRUE else: return self.DOSFALSE def Rename(self, ctx): old_name_ptr = ctx.cpu.r_reg(REG_D1) old_name = ctx.mem.access.r_cstr(old_name_ptr) new_name_ptr = ctx.cpu.r_reg(REG_D2) new_name = ctx.mem.access.r_cstr(new_name_ptr) self.io_err = self.file_mgr.rename(old_name, new_name) log_dos.info("Rename: '%s' -> '%s': err=%s" % (old_name, new_name, self.io_err)) if self.io_err == NO_ERROR: return self.DOSTRUE else: return self.DOSFALSE def SetProtection(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) name = ctx.mem.access.r_cstr(name_ptr) mask = ctx.cpu.r_reg(REG_D2) self.io_err = self.file_mgr.set_protection(name, mask) log_dos.info("SetProtection: '%s' mask=%04x: err=%s", name, mask, self.io_err) if self.io_err == NO_ERROR: return self.DOSTRUE else: return self.DOSFALSE def IsInteractive(self, ctx): fh_b_addr = ctx.cpu.r_reg(REG_D1) fh = self.file_mgr.get_by_b_addr(fh_b_addr) res = fh.is_interactive() log_dos.info("IsInteractive(%s): %s" % (fh, res)) if res: return self.DOSTRUE else: return self.DOSFALSE def IsFileSystem(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) name = ctx.mem.access.r_cstr(name_ptr) res = self.file_mgr.is_file_system(name) log_dos.info("IsFileSystem('%s'): %s" % (name, res)) if res: return self.DOSTRUE else: return self.DOSFALSE # ----- Locks ----- def Lock(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) name = ctx.mem.access.r_cstr(name_ptr) mode = ctx.cpu.r_reg(REG_D2) if mode == 0xffffffff: lock_exclusive = True elif mode == 0xfffffffe: lock_exclusive = False else: raise UnsupportedFeatureError("Lock: mode=%x" % mode) lock = self.lock_mgr.create_lock(name, lock_exclusive) log_dos.info("Lock: '%s' exc=%s -> %s" % (name, lock_exclusive, lock)) if lock == None: self.io_err = ERROR_OBJECT_NOT_FOUND return 0 else: return lock.b_addr def UnLock(self, ctx): lock_b_addr = ctx.cpu.r_reg(REG_D1) if lock_b_addr == 0: log_dos.info("UnLock: NULL") else: lock = self.lock_mgr.get_by_b_addr(lock_b_addr) log_dos.info("UnLock: %s" % (lock)) self.lock_mgr.release_lock(lock) def DupLock(self, ctx): lock_b_addr = ctx.cpu.r_reg(REG_D1) lock = self.lock_mgr.get_by_b_addr(lock_b_addr) dup_lock = self.lock_mgr.create_lock(lock.ami_path, False) log_dos.info("DupLock: %s -> %s", lock, dup_lock) self.io_err = NO_ERROR return dup_lock.b_addr def Examine(self, ctx): lock_b_addr = ctx.cpu.r_reg(REG_D1) fib_ptr = ctx.cpu.r_reg(REG_D2) lock = self.lock_mgr.get_by_b_addr(lock_b_addr) log_dos.info("Examine: %s fib=%06x" % (lock, fib_ptr)) fib = AccessStruct(ctx.mem, FileInfoBlockDef, struct_addr=fib_ptr) self.io_err = lock.examine_lock(fib) if self.io_err == NO_ERROR: return self.DOSTRUE else: return self.DOSFALSE def ExNext(self, ctx): lock_b_addr = ctx.cpu.r_reg(REG_D1) fib_ptr = ctx.cpu.r_reg(REG_D2) lock = self.lock_mgr.get_by_b_addr(lock_b_addr) log_dos.info("ExNext: %s fib=%06x" % (lock, fib_ptr)) fib = AccessStruct(ctx.mem, FileInfoBlockDef, struct_addr=fib_ptr) self.io_err = lock.examine_next(fib) if self.io_err == NO_ERROR: return self.DOSTRUE else: return self.DOSFALSE def ParentDir(self, ctx): lock_b_addr = ctx.cpu.r_reg(REG_D1) lock = self.lock_mgr.get_by_b_addr(lock_b_addr) parent_lock = self.lock_mgr.create_parent_lock(lock) log_dos.info("ParentDir: %s -> %s" % (lock, parent_lock)) if parent_lock != None: return parent_lock.b_addr else: return 0 def CurrentDir(self, ctx): lock_b_addr = ctx.cpu.r_reg(REG_D1) old_lock = self.cur_dir_lock if lock_b_addr == 0: new_lock = None else: new_lock = self.lock_mgr.get_by_b_addr(lock_b_addr) self.cur_dir_lock = new_lock log_dos.info("CurrentDir(b@%x): %s -> %s" % (lock_b_addr, old_lock, new_lock)) # set current path in path mgr if new_lock != None: ctx.path_mgr.set_cur_path(new_lock.ami_path) else: ctx.path_mgr.set_default_cur_path() if old_lock == None: return 0 else: return old_lock.b_addr def NameFromLock(self, ctx): lock_b_addr = ctx.cpu.r_reg(REG_D1) buf = ctx.cpu.r_reg(REG_D2) buf_len = ctx.cpu.r_reg(REG_D3) if lock_b_addr == 0: name = "SYS:" lock = None else: lock = self.lock_mgr.get_by_b_addr(lock_b_addr) name = lock.ami_path log_dos.info("NameFromLock(%x,%d): %s -> %s", buf, buf_len, lock, name) if len(name) >= buf_len: self.io_err = ERROR_LINE_TOO_LONG return self.DOSFALSE else: ctx.mem.access.w_cstr(buf, name) return self.DOSTRUE def CreateDir(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) name = ctx.mem.access.r_cstr(name_ptr) err = self.file_mgr.create_dir(name) if err != NO_ERROR: self.io_err = err return 0 else: lock = self.lock_mgr.create_lock(name, True) log_dos.info("CreateDir: '%s' -> %s" % (name, lock)) if lock == None: self.io_err = ERROR_OBJECT_NOT_FOUND return 0 else: return lock.b_addr # ----- DevProc ----- def GetDeviceProc(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) last_devproc = ctx.cpu.r_reg(REG_D2) name = ctx.mem.access.r_cstr(name_ptr) # get volume of path abs_name = ctx.path_mgr.ami_abs_path(name) volume = ctx.path_mgr.ami_volume_of_path(abs_name) vol_lock = self.lock_mgr.create_lock(volume + ":", False) fs_port = self.file_mgr.get_fs_handler_port() addr = self._alloc_mem("DevProc:%s" % name, DevProcDef.get_size()) log_dos.info( "GetDeviceProc: name='%s' devproc=%06x -> volume=%s devproc=%06x", name, last_devproc, volume, addr) devproc = AccessStruct(self.ctx.mem, DevProcDef, struct_addr=addr) devproc.w_s('dvp_Port', fs_port) devproc.w_s('dvp_Lock', vol_lock.b_addr) self.io_err = NO_ERROR return addr def FreeDeviceProc(self, ctx): addr = ctx.cpu.r_reg(REG_D1) self._free_mem(addr) log_dos.info("FreeDeviceProc: devproc=%06x", addr) # ----- Matcher ----- def MatchFirst(self, ctx): pat_ptr = ctx.cpu.r_reg(REG_D1) pat = ctx.mem.access.r_cstr(pat_ptr) anchor_ptr = ctx.cpu.r_reg(REG_D2) anchor = AccessStruct(self.ctx.mem, AnchorPathDef, struct_addr=anchor_ptr) # create MatchFirstNext instance mfn = MatchFirstNext(ctx.path_mgr, self.lock_mgr, pat, anchor) log_dos.info("MatchFirst: pat='%s' anchor=%06x strlen=%d flags=%02x-> ok=%s" \ % (pat, anchor_ptr, mfn.str_len, mfn.flags, mfn.ok)) if not mfn.ok: self.io_err = ERROR_BAD_TEMPLATE return self.io_err log_dos.debug("MatchFirst: %s" % mfn.matcher) # try first match self.io_err = mfn.first(ctx) if self.io_err == NO_ERROR: log_dos.info( "MatchFirst: found name='%s' path='%s' -> parent lock %s, io_err=%d", mfn.name, mfn.path, mfn.dir_lock, self.io_err) self.matches[anchor_ptr] = mfn # no entry found or error elif self.io_err == ERROR_OBJECT_NOT_FOUND: log_dos.info("MatchFirst: none found") self.matches[anchor_ptr] = mfn else: log_dos.info("MatchFirst: error: %d", self.io_err) return self.io_err def MatchNext(self, ctx): anchor_ptr = ctx.cpu.r_reg(REG_D1) log_dos.info("MatchNext: anchor=%06x" % (anchor_ptr)) # retrieve match if not self.matches.has_key(anchor_ptr): raise VamosInternalError("MatchNext: No matcher found for %06x" % anchor_ptr) mfn = self.matches[anchor_ptr] # has matches? if mfn != None: self.io_err = mfn.next(ctx) if self.io_err == NO_ERROR: log_dos.info( "MatchNext: found name='%s' path=%s -> parent lock %s, io_err=%d", mfn.name, mfn.path, mfn.dir_lock, self.io_err) elif self.io_err == ERROR_NO_MORE_ENTRIES: log_dos.info("MatchNext: no more entries!") else: log_dos.info("MatchNext: error: %d", self.io_err) return self.io_err def MatchEnd(self, ctx): anchor_ptr = ctx.cpu.r_reg(REG_D1) log_dos.info("MatchEnd: anchor=%06x " % (anchor_ptr)) # retrieve match if not self.matches.has_key(anchor_ptr): raise VamosInternalError("MatchEnd: No matcher found for %06x" % anchor_ptr) mfn = self.matches[anchor_ptr] del self.matches[anchor_ptr] if mfn != None: mfn.end(ctx) # ----- Pattern Parsing and Matching ----- def ParsePattern(self, ctx, ignore_case=False): src_ptr = ctx.cpu.r_reg(REG_D1) dst_ptr = ctx.cpu.r_reg(REG_D2) dst_len = ctx.cpu.r_reg(REG_D3) src = ctx.mem.access.r_cstr(src_ptr) pat = pattern_parse(src, ignore_case=ignore_case) log_dos.info("ParsePattern: src=%s ignore_case=%s -> pat=%s", src, ignore_case, pat) if pat == None: self.io_err = ERROR_BAD_TEMPLATE return -1 else: self.io_err = NO_ERROR pat_str = pat.pat_str if len(pat_str) >= dst_len: return -1 else: ctx.mem.access.w_cstr(dst_ptr, pat_str) if pat.has_wildcard: return 1 else: return 0 def ParsePatternNoCase(self, ctx): return self.ParsePattern(ctx, ignore_case=True) def MatchPattern(self, ctx, ignore_case=False): pat_ptr = ctx.cpu.r_reg(REG_D1) txt_ptr = ctx.cpu.r_reg(REG_D2) pat = ctx.mem.access.r_cstr(pat_ptr) txt = ctx.mem.access.r_cstr(txt_ptr) match = pattern_match(pat, txt) log_dos.info("MatchPattern: pat=%s txt=%s ignore_case=%s -> match=%s", pat, txt, ignore_case, match) if match: return -1 else: return 0 def MatchPatternNoCase(self, ctx): return self.MatchPattern(ctx, ignore_case=True) # ----- Args ----- def ReadArgs(self, ctx): template_ptr = ctx.cpu.r_reg(REG_D1) template = ctx.mem.access.r_cstr(template_ptr) array_ptr = ctx.cpu.r_reg(REG_D2) rdargs_ptr = ctx.cpu.r_reg(REG_D3) # get args from process bin_args = ctx.process.bin_args log_dos.info( "ReadArgs: args=%s template='%s' array_ptr=%06x rdargs_ptr=%06x" % (bin_args, template, array_ptr, rdargs_ptr)) # try to parse argument string args = Args() args.parse_template(template) args.prepare_input(ctx.mem.access, array_ptr) ok = args.parse_string(bin_args) if not ok: self.io_err = args.error log_dos.info("ReadArgs: not matched -> io_err=%d/%s", self.io_err, dos_error_strings[self.io_err]) return 0 log_dos.debug("matched template: %s", args.get_result()) # calc size of result size = args.calc_result_size() log_dos.debug("longs=%d chars=%d size=%d" % (args.num_longs, args.num_chars, size)) # alloc result mem (extra longs and cstrs) if size > 0: addr = self._alloc_mem("ReadArgs(@%06x)" % self.get_callee_pc(ctx), size) else: addr = 0 # fill result array and memory args.generate_result(ctx.mem.access, addr, array_ptr) # alloc RD_Args if rdargs_ptr == 0: rdargs = ctx.alloc.alloc_struct("RDArgs", RDArgsDef) own = True else: rdargs = ctx.alloc.map_struct("RDArgs", rdargs_ptr, RDArgsDef) own = False rdargs.access.w_s('RDA_Buffer', addr) rdargs.access.w_s('RDA_BufSiz', size) # store rdargs self.rdargs[rdargs.addr] = (rdargs, own) # result self.io_err = NO_ERROR log_dos.info("ReadArgs: matched! result_mem=%06x rdargs=%s", addr, rdargs) return rdargs.addr def FreeArgs(self, ctx): rdargs_ptr = ctx.cpu.r_reg(REG_D1) log_dos.info("FreeArgs: %06x" % rdargs_ptr) # find rdargs if not self.rdargs.has_key(rdargs_ptr): raise VamosInternalError("Can't find RDArgs: %06x" % rdargs_ptr) rdargs, own = self.rdargs[rdargs_ptr] del self.rdargs[rdargs_ptr] # clean up rdargs addr = rdargs.access.r_s('RDA_Buffer') if addr != 0: self._free_mem(addr) # free our memory if own: self.alloc.free_struct(rdargs) def cs_get(self, ctx): if self.cs_input: ch = self.cs_input.getc() else: if self.cs_curchr < self.cs_length: ch = ctx.mem.access.r8(self.cs_buffer + self.cs_curchr) self.cs_curchr = self.cs_curchr + 1 else: ch = -1 return ch def cs_unget(self, ctx): if self.cs_input: self.cs_input.ungetc(-1) else: self.cs_curchr = self.cs_curchr - 1 def ReadItem(self, ctx): buff_ptr = ctx.cpu.r_reg(REG_D1) maxchars = ctx.cpu.r_reg(REG_D2) csource_ptr = ctx.cpu.r_reg(REG_D3) log_dos.info("ReadItem: buff_ptr=%06x maxchars=%d csource_ptr=%06x" % (buff_ptr, maxchars, csource_ptr)) if (csource_ptr): csource = ctx.alloc.map_struct("CSource", csource_ptr, CSourceDef) self.cs_input = None self.cs_buffer = csource.access.r_s('CS_Buffer') self.cs_length = csource.access.r_s('CS_Length') self.cs_curchr = csource.access.r_s('CS_CurChr') else: self.cs_input = ctx.process.get_input() if buff_ptr == 0: return 0 # ITEM_NOTHING # Well Known Bug: buff[0] = 0, even if maxchars == 0 ctx.mem.access.w8(buff_ptr, 0) # Skip leading whitespace while True: ch = self.cs_get(ctx) if ch != ord(" ") and ch != ord("\t"): break if ch == 0 or ch == ord("\n") or ch < 0 or ch == ord(";"): if ch >= 0: self.cs_unget(ctx) return 0 # ITEM_NOTHING if ch == ord("="): return -2 # ITEM_EQUAL if ch == ord("\""): while True: if maxchars <= 0: ctx.mem.access.w8(buff_ptr - 1, 0) return 0 # ITEM_NOTHING maxchars = maxchars - 1 ch = self.cs_get(ctx) if ch == ord("*"): ch = self.cs_get(ctx) if ch == 0 or ch == ord("\n") or ch < 0: self.cs_unget(ctx) ctx.mem.access.w8(buff_ptr, 0) return -1 # ITEM_ERROR elif ch == ord("n") or ch == ord("N"): ch = ord("\n") elif ch == ord("e") or ch == ord("E"): ch = 0x1b elif ch == 0 or ch == ord("\n") or ch < 0: self.cs_ungetc(ctx) ctx.mem.access.w8(buff_ptr, 0) return -1 # ITEM_ERROR elif ch == ord("\""): ctx.mem.access.w8(buff_ptr, 0) return 2 # ITEM_QUOTED ctx.mem.access.w8(buff_ptr, ch) buff_ptr = buff_ptr + 1 pass else: if maxchars <= 0: ctx.mem.access.w8(buff_ptr - 1, 0) return -1 # ITEM_ERROR maxchars = maxchars - 1 ctx.mem.access.w8(buff_ptr, ch) buff_ptr = buff_ptr + 1 while True: if maxchars <= 0: ctx.mem.access.w8(buff_ptr - 1, 0) return -1 # ITEM_ERROR maxchar = maxchars - 1 ch = self.cs_get(ctx) if ch == 0 or ch == ord("\n") or ch == ord(" ") or ch == ord( "\t") or ch == ord("=") or ch < 0: # Know Bug: Don't UNGET for a space or equals sign if ch != ord("=") and ch != ord(" ") and ch != ord("\t"): self.cs_unget(ctx) ctx.mem.access.w8(buff_ptr, 0) return 1 # ITEM_UNQUOTED ctx.mem.access.w8(buff_ptr, ch) buff_ptr = buff_ptr + 1 # ----- System/Execute ----- def SystemTagList(self, ctx): cmd_ptr = ctx.cpu.r_reg(REG_D1) tagitem_ptr = ctx.cpu.r_reg(REG_D2) cmd = ctx.mem.access.r_cstr(cmd_ptr) tag_list = taglist_parse_tagitem_ptr(ctx.mem, tagitem_ptr, DosTags) log_dos.info("SystemTagList: cmd='%s' tags=%s", cmd, tag_list) # parse "command line" cl = CommandLine() if not cl.parse_string(cmd): log_dos.info("SystemTagList: error parsing command: '%s'", cmd) return 10 # RETURN_ERROR args = cl.args if len(args) == 0: log_dos.info("SystemTagList: error parsing command: '%s'", cmd) return 10 # RETURN_ERROR bin = args[0] args = args[1:] # TODO: redirs log_dos.info("SystemTagList: bin='%s' args=%s", bin, args) # create a process and run it... proc = Process(ctx, bin, args) if not proc.ok: log_dos.warn( "SystemTagList: can't create process for '%s' args=%s", bin, args) return 0xffffffff ctx.start_sub_process(proc) def LoadSeg(self, ctx): name_ptr = ctx.cpu.r_reg(REG_D1) name = ctx.mem.access.r_cstr(name_ptr) seg_list = self.ctx.seg_loader.load_seg(name) if seg_list == None: log_dos.warn("LoadSeg: '%s' -> not found!" % (name)) return 0 else: log_dos.warn("LoadSeg: '%s' -> %s" % (name, seg_list)) b_addr = seg_list.b_addr self.seg_lists[b_addr] = seg_list return b_addr def UnLoadSeg(self, ctx): b_addr = ctx.cpu.r_reg(REG_D1) if not self.seg_lists.has_key(b_addr): raise VamosInternalError("Unknown LoadSeg seg_list: b_addr=%06x" % b_addr) else: seg_list = self.seg_lists[b_addr] del self.seg_lists[b_addr] self.ctx.seg_loader.unload_seg(seg_list) # ----- Path Helper ----- def FilePart(self, ctx): addr = ctx.cpu.r_reg(REG_D1) path = ctx.mem.access.r_cstr(addr) pos = dos.PathPart.file_part(path) if pos < len(path): log_dos.info("FilePart: path='%s' -> result='%s'", path, path[pos:]) else: log_dos.info("FilePart: path='%s' -> pos=NULL", path) return addr + pos def PathPart(self, ctx): addr = ctx.cpu.r_reg(REG_D1) path = ctx.mem.access.r_cstr(addr) pos = dos.PathPart.path_part(path) if pos < len(path): log_dos.info("PathPart: path='%s' -> result='%s'", path, path[pos:]) else: log_dos.info("PathPart: path='%s' -> pos=NULL", path) return addr + pos def AddPart(self, ctx): dn_addr = ctx.cpu.r_reg(REG_D1) fn_addr = ctx.cpu.r_reg(REG_D2) size = ctx.cpu.r_reg(REG_D3) dn = ctx.mem.access.r_cstr(dn_addr) fn = ctx.mem.access.r_cstr(fn_addr) np = dos.PathPart.add_part(dn, fn, size) log_dos.info("AddPart: dn='%s' fn='%s' size=%d -> np='%s'", dn, fn, size, np) if np != None: ctx.mem.access.w_cstr(dn_addr, np) return self.DOSTRUE else: return self.DOSFALSE # ----- DosObjects ----- def AllocDosObject(self, ctx): obj_type = ctx.cpu.r_reg(REG_D1) tags_ptr = ctx.cpu.r_reg(REG_D2) if obj_type == 0: # DOS_FILEHANDLE name = "DOS_FILEHANDLE" struct_def = FileHandleDef elif obj_type == 1: # DOS_EXALLCONTROL name = "DOS_EXALLCONTROL" struct_def = None elif obj_type == 2: # DOS_FIB name = "DOS_FIB" struct_def = FileInfoBlockDef elif obj_type == 3: # DOS_STDPKT name = "DOS_STDPKT" struct_def = DosPacketDef elif obj_type == 4: # DOS_CLI name = "DOS_CLI" struct_def = CLIDef elif obj_type == 5: # DOS_RDARGS name = "DOS_RDARGS" struct_def = RDArgsDef else: log_dos.error("AllocDosObject: invalid type=%d", obj_type) return 0 if struct_def is None: log_dos.warn("AllocDosObject: unsupported type=%d/%s", obj_type, name) return 0 # allocate struct dos_obj = ctx.alloc.alloc_struct(name, struct_def) log_dos.info("AllocDosObject: type=%d/%s tags_ptr=%08x -> dos_obj=%s", obj_type, name, tags_ptr, dos_obj) # store struct ptr = dos_obj.addr self.dos_objs[ptr] = (dos_obj, obj_type) # pre fill struct if obj_type == 0: dos_obj.access.w_s('fh_Pos', 0xffffffff) dos_obj.access.w_s('fh_End', 0xffffffff) elif obj_type == 4: raise UnsupportedFeatureError("AllocDosObject: DOS_CLI fill TBD") return ptr def FreeDosObject(self, ctx): obj_type = ctx.cpu.r_reg(REG_D1) ptr = ctx.cpu.r_reg(REG_D2) # retrieve struct if ptr in self.dos_objs: entry = self.dos_objs[ptr] del self.dos_objs[ptr] # check type if obj_type != entry[1]: log_dos.warn("FreeDosObject: type mismatch %d != %d", obj_type, entry[1]) # free struct ctx.alloc.free_struct(entry[0]) else: log_dos.error("FreeDosObject: type=%d ptr=%08x -> NOT FOUND!", obj_type, ptr) # ----- Helpers ----- def _alloc_mem(self, name, size): mem = self.alloc.alloc_memory(name, size) self.mem_allocs[mem.addr] = mem return mem.addr def _free_mem(self, addr): if self.mem_allocs.has_key(addr): mem = self.mem_allocs[addr] self.alloc.free_memory(mem) del self.mem_allocs[addr] else: raise VamosInternalError("Invalid DOS free mem: %06x" % addr)