From ff06a1643ff1addb3a772953f57c70e37f3db185 Mon Sep 17 00:00:00 2001 From: Andrew Bird Date: Fri, 1 Mar 2024 13:17:47 +0000 Subject: [PATCH] lfn: Implement int21/71a0 get volume information If the volume is local then return suitable information, as either FAT or FAT32. Currently FDPP and FreeDOS don't support LFN natively, so values are chosen to reflect that. If DOSLFN is loaded then its own handler will used in preference. If the disk is remote then query the respective redirector via int2f/11a0 (an extension) for the relevant values. If the redirector dosen't support the extension, then we pretend that the kernel doesn't support int21/71a0. --- hdr/xstructs.h | 15 ++++++++++++ kernel/inthndlr.c | 23 +++++++++++++++++++ kernel/network.c | 32 ++++++++++++++++++++++++++ kernel/newstuff.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++ kernel/proto.h | 2 ++ 5 files changed, 130 insertions(+) diff --git a/hdr/xstructs.h b/hdr/xstructs.h index 71931d9c..d7e0f48d 100644 --- a/hdr/xstructs.h +++ b/hdr/xstructs.h @@ -83,4 +83,19 @@ struct xdpbforformat { }; ANNOTATE_SIZE(struct xdpbforformat, 0x18); +struct xgetvolumeinfo { + UBYTE version; + UBYTE size; /* size of this structure */ + UBYTE namelen; /* length of file system type name */ + UBYTE pad; + struct { + UWORD std; /* 15..0 as per RBIL */ + UWORD ext; /* 31..16 for extension */ + } PACKED flags; + UWORD maxfilenamelen; + UWORD maxpathlen; + char name[16]; /* file system type name */ +} PACKED; +ANNOTATE_SIZE(struct xgetvolumeinfo, 28); + COUNT DosGetExtFree(__FAR(BYTE) DriveString, __FAR(struct xfreespace) xfsp); diff --git a/kernel/inthndlr.c b/kernel/inthndlr.c index 28c38e52..8e925cf9 100644 --- a/kernel/inthndlr.c +++ b/kernel/inthndlr.c @@ -1582,6 +1582,29 @@ VOID ASMCFUNC int21_service(iregs FAR * r) goto unsupp; break; } + + case 0xa0: { + char FAR *path = MK_FP(lr.DS, lr.DX); + char FAR *name = MK_FP(lr.ES, lr.DI); + UBYTE bufsiz = lr.CX; + UWORD vals[3]; + COUNT rc; + + rc = DosGetVolumeInfo(path, bufsiz, vals, name); + if (rc == SUCCESS) { + r->BX = vals[0]; /* standard flags */ + r->CX = vals[1]; /* max length of file name [usually 255] */ + r->DX = vals[2]; /* max length of path [usually 260] */ + CLEAR_CARRY_FLAG(); + } else if (rc == DE_INVLDBUF) { + SET_CARRY_FLAG(); + } else { + goto unsupp; + } + r->AX = rc; + goto real_exit; + } + default: goto unsupp; } diff --git a/kernel/network.c b/kernel/network.c index d8c4a0c7..54593429 100644 --- a/kernel/network.c +++ b/kernel/network.c @@ -155,3 +155,35 @@ BYTE remote_getfree_11a3(void FAR *cds, void *dst) udst[4] = regs.si; return SUCCESS; } + +BYTE remote_getvolumeinfo(UBYTE drive, UBYTE bufsiz, void *dst_r, char FAR *dst_s) +{ + UWORD *udst = (UWORD *)dst_r; + iregs regs = {}; + struct xgetvolumeinfo s; + struct xgetvolumeinfo FAR *p; + + p = MK_FAR(s); + + regs.a.x = 0x11a0; + regs.c.x = sizeof(s); + regs.d.b.l = drive; + regs.d.b.h = 1; /* we'd like a version one structure returned */ + regs.es = FP_SEG_OBJ(®s, p); + regs.di = FP_OFF_OBJ(®s, p); + + regs.flags = FLG_CARRY; + call_intr(0x2f, MK_FAR_SCP(regs)); + if ((regs.flags & FLG_CARRY) || (regs.a.x != 0x1c01)) + return DE_INVLDFUNC; + + if (bufsiz < s.namelen + 1) + return DE_INVLDBUF; + + udst[0] = s.flags.std; + udst[1] = s.flags.ext; + udst[2] = s.maxfilenamelen; + udst[3] = s.maxpathlen; + n_fmemcpy(dst_s, s.name, s.namelen + 1); + return SUCCESS; +} diff --git a/kernel/newstuff.c b/kernel/newstuff.c index 97c02473..bcbb4532 100644 --- a/kernel/newstuff.c +++ b/kernel/newstuff.c @@ -634,3 +634,61 @@ COUNT truename(__XFAR(const char) src, char FAR *dest, COUNT mode) tn_printf(("Physical path: \"%s\"\n", GET_PTR(dest))); return result; } + +COUNT DosGetVolumeInfo(const char FAR *DriveString, UBYTE bufsiz, UWORD *outv, char FAR *name) +{ + struct dpb FAR *dpbp; + struct cds FAR *cdsp; + UBYTE drive = 0xff; + COUNT rc; + + /* + DriveString should be in form of "C:\" + */ + if (!DriveString) + return DE_INVLDDRV; + + if (DriveString[0] && DriveString[1] == ':') + { + drive = DosUpFChar(DriveString[0]) - 'A'; + cdsp = get_cds(drive); + } + else + cdsp = NULL; + + if (cdsp == NULL) /* either error, really bad string, or network name */ + return DE_INVLDDRV; + + if (cdsp->cdsFlags & CDSNETWDRV) /* Try redirector extension */ + { + UWORD rg[4]; + rc = remote_getvolumeinfo(drive, bufsiz, rg, name); + if (rc == SUCCESS) + { + outv[0] = rg[0]; + /* caller doesn't need extended flags */ + outv[1] = rg[2]; + outv[2] = rg[3]; + } + return rc; + } + + /* local drive */ + dpbp = cdsp->cdsDpb; + if (dpbp == NULL || media_check(dpbp) < 0) + return DE_INVLDDRV; + + if (bufsiz < sizeof("FAT32")) + return DE_INVLDBUF; + + outv[0] = 0; // std flags + outv[1] = 12; // max filename length (includes '.') + outv[2] = 67; // max pathname length (includes 'C:') + + if (ISFAT32(dpbp)) + n_fmemcpy(name, "FAT32", sizeof("FAT32")); + else + n_fmemcpy(name, "FAT", sizeof("FAT")); + + return SUCCESS; +} diff --git a/kernel/proto.h b/kernel/proto.h index 5436390e..06dfe4f8 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -120,6 +120,7 @@ COUNT DosDelete(__FAR(const char) path, int attrib); COUNT DosRename(__FAR(const char) path1,__FAR(const char) path2); COUNT DosRenameTrue(__FAR(const char) path1, __FAR(const char) path2, int attrib); COUNT DosMkRmdir(__FAR(const char) dir, int action); +COUNT DosGetVolumeInfo(__FAR(const char) DriveString, UBYTE bufsiz, UWORD *outv, __FAR(char) name); __FAR(struct dhdr)IsDevice(__XFAR(const char) FileName); #define IsShareInstalled(recheck) TRUE COUNT DosLockUnlock(COUNT hndl, LONG pos, LONG len, COUNT unlock); @@ -410,6 +411,7 @@ BYTE remote_qualify_filename(__FAR(char) dst, __FAR(const char) src); #define remote_rw(cmd,s,arg) network_redirector_mx(cmd, s, arg) BYTE remote_getfree(__FAR(void) cds, void *dst); BYTE remote_getfree_11a3(__FAR(void) cds, void *dst); +BYTE remote_getvolumeinfo(UBYTE drive, UBYTE bufsiz, void *dst_r, __FAR(char) dst_s); UDWORD remote_lseek(__FAR(void) sft, DWORD new_pos); UWORD remote_getfattr(void); #define remote_setfattr(attr) (WORD)network_redirector_mx(REM_SETATTR, NULL, attr)