/* Copyright (C) 2011 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */ /* This is file LFILELEN.C */ /* * Copyright (c) 1994 Eli Zaretskii * * This software may be used freely so long as this copyright notice is * left intact. There is no warranty on this software. * */ #include #include #include #include #include #include #include #include #include long long lfilelength(int fhandle) { __dpmi_regs regs = {0}; unsigned short fpos_high, fpos_low; long long retval; /* DOS 7 provides a way to get the file size directly. Prefer it when available. */ if (_USE_LFN) { regs.x.flags = 1; /* Always set CF before calling a 0x71NN function. */ regs.x.ax = 0x71A6; regs.x.bx = fhandle; regs.x.ds = __tb >> 4; regs.x.dx = 0; __dpmi_int (0x21, ®s); /* It is always necessary to test if LFN function has been implemented because the assumption has been proven false that a driver will set the CF if the LFN function has not been implemented. E.g.: all DOSLFN drivers do not implement 0x71A6 and DOSLFN 0.40e does not set CF making MSDOS 6.22 fail. If FreeDOS 1.0 is used, the same LFN driver sets the CF. If the ax register contains 0x7100 then the corresponding LFN function is not implemented. If the 0x71A6 function is not supported fall back on 0x42NN. */ if (!(regs.x.flags & 1) && (regs.x.ax != 0x7100)) { /* Offset 0x24 contains the low 32-bits of the file size. Offset 0x20 contains the high 32-bits. */ long retval_l = _farpeekl (_dos_ds, __tb + 0x24); long retval_h = _farpeekl (_dos_ds, __tb + 0x20); if (retval_h < 0) { errno = EOVERFLOW; return -1; } retval = retval_l + retval_h * (1LL << 32); return retval; } } /* Remember the current file position, so we can return there later. */ regs.x.ax = 0x4201; /* set pointer from current position */ regs.x.bx = fhandle; regs.x.cx = regs.x.dx = 0; /* move 0 bytes (i.e., stay put) */ __dpmi_int(0x21, ®s); if (regs.x.flags & 1) { errno = __doserr_to_errno(regs.x.ax); return -1L; } fpos_high = regs.x.dx; /* save current position */ fpos_low = regs.x.ax; regs.x.cx = regs.x.dx = 0; regs.x.ax = 0x4202; /* set pointer 0 bytes from the end of file */ __dpmi_int(0x21, ®s); if (regs.x.flags & 1) { errno = __doserr_to_errno(regs.x.ax); return -1LL; } /* The absolute byte offset returned in DX:AX is the file size. */ retval = ( (long long)regs.x.dx << 16 ) + regs.x.ax; /* Leave things as we have found them. */ regs.x.ax = 0x4200; /* set pointer from the beginning of file */ regs.x.cx = fpos_high; regs.x.dx = fpos_low; __dpmi_int(0x21, ®s); if (regs.x.flags & 1) { errno = __doserr_to_errno(regs.x.ax); return -1L; } return retval; }