Skip to content

Commit

Permalink
lfn: Implement int21/71a0 get volume information
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
andrewbird committed Mar 9, 2024
1 parent fce9118 commit ac4a683
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 0 deletions.
15 changes: 15 additions & 0 deletions hdr/xstructs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
23 changes: 23 additions & 0 deletions kernel/inthndlr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
24 changes: 24 additions & 0 deletions kernel/network.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,27 @@ BYTE remote_getfree_11a3(void FAR *cds, void *dst)
udst[4] = regs.si;
return SUCCESS;
}

BYTE remote_getvolumeinfo(UBYTE drive, struct xgetvolumeinfo *s_ptr)
{
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(&regs, p);
regs.di = FP_OFF_OBJ(&regs, p);

regs.flags = FLG_CARRY;
call_intr(0x2f, MK_FAR_SCP(regs));
if ((regs.flags & FLG_CARRY) || (regs.a.x != 0x1c01))
return DE_INVLDFUNC;

*s_ptr = s;
return SUCCESS;
}
60 changes: 60 additions & 0 deletions kernel/newstuff.c
Original file line number Diff line number Diff line change
Expand Up @@ -634,3 +634,63 @@ 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 */
{
struct xgetvolumeinfo xg;
rc = remote_getvolumeinfo(drive, &xg);
if (rc == SUCCESS)
{
outv[0] = xg.flags.std;
outv[1] = xg.maxfilenamelen;
outv[2] = xg.maxpathlen;
if (bufsiz < xg.namelen + 1)
return DE_INVLDBUF;
n_fmemcpy(name, xg.name, xg.namelen + 1);
}
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;
}
2 changes: 2 additions & 0 deletions kernel/proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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, struct xgetvolumeinfo *s_ptr);
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)
Expand Down

0 comments on commit ac4a683

Please sign in to comment.