;Lange Dateinamen unter nacktem DOS
;Noch zu tun:
;"verl„ngerte" Sektoren und Untersttzung von Sektorl„nge 128..4096 Bytes
;Umbenennen gleiche Datei
;korrektes L”schen mit Wildcards
;HeapWalker
;N: Most Protected Mode DOS extenders doesn't translate the LFN API to
; Real Mode. (When running Windows9x, Windows makes that task, effectively
; disabling the DOS extender.)
; For DPMI programs, it is up to the programmer to translate these DOS
; calls to Real Mode, using DPMI services at INT31. Best solution would
; be a DLL that makes this task at load time, hooking the protected mode
; INT21 chain.
; When running Windows3 in Enhanced Mode,
; DOSLFN auto-loads an LFNXLAT.386 VxD that translates these APIs.
; With this VxD, there is no need for translation for Windows programs.
; Unfortunately, Win32s programs cannot see long file names,
; unless someone publish a great patch of one Win32s DLL.
; The rarely used Standard Mode should be configured to load the DLL
; (above mentioned) at startup - but DOSLFN requires a 386 itself.
%NOLIST
include prolog.asm
public COMentry ;damit's mit SoftICE klappt
P386
JUMPS
REQfunc equ 7146h ;in AX
REQcode equ 9877h ;in DX
ANScode equ 8766h ;in AX; DX=Segmentadresse
DEFHEAPSIZE = 1000 ;fr einige FindInfos
DEFHEAPSIZE_CD = 2000 ;dazu eine durchschnittliche .JLT-Datei
FDChangeTime = 3*18 ;Neue DPB einlesen nach 3 Sekunden Inaktivit„t
CDChangeTime = 7*18 ;dauert naturgem„á viel l„nger,
;auch das Einlesen der ersten CD-Sektoren und der Link-Tabelle
macro INT3
ifdef DEBUG
INT 3
endif
endm
;********************
;** DOS structures **
;********************
struc tExDPB ;structure returned by INT21/AH=32, valid: DOS 4.0+
Drive db ? ;{0=A}
UnitNo db ? ;number of device driver unit
SecLen dw ? ;{Bytes pro Sektor}
HiSec db ? ;{Anzahl Sektoren pro Cluster -1, 2**n-1}
Shift db ? ;{Verschiebung n}
ResSec dw ? ;{Reservierte Sektoren am Anfang des Laufwerks}
FATs db ? ;{Anzahl der FATs}
RootEn dw ? ;{Anzahl Wurzelverzeichniseintr„ge}
UsrSec dw ? ;{1. Sektor mit Userdaten}
HiClus dw ? ;{Anzahl Cluster -1}
SecFAT dw ? ;{Sektoren pro FAT}
SecDir dw ? ;{Sektornummer 1.Dir}
unused db 5 dup (?) ;Luft zum FAT32-DPB, der beginnt ab Ofs.24
;from here starts extended trail from INT21/AH=73
dpb_flags db ?
next_dpb dd ? ;Pointer
start_search_cluster dw ?
free_clusters dd ?
mirroring dw ?
file_system_info_sector dw ?
backup_boot_sector dw ?
first_sector dd ?
max_cluster dd ?
sectors_per_fat dd ?
root_cluster dd ?
free_space_cluster dd ?
filler db ? ;"gerade" Strukturl„nge!
ends
struc tRWRec ;DOS structure for reading and writing sectors
sect dd ? ;sector number, allowing partitions up to 2 Terabyte
numb dw ? ;sector count
addr dd ? ;FAR address of sector data
ends
struc TSearchRec ;DOS legacy search record, returned at INT21/AH=4E&4F
;N: All undocumented fields are not used to maintain compatibility with
; non-MS clones of DOS or some TSRs
Drive db ? ;bit7 set at network drives and FAT32, undocumented
SName db 8 dup (?)
SExt db 3 dup (?)
SAttr db ?
DirNo dw ?
union
struc
Clus dw ?
Res dd ?
ends
struc
Clus32 dd ? ;on FAT32
DirNoHi dw ? ;eventually high part of DirNo?
ends
ends
Attr db ? ;here the documented part begins
Time dd ?
fsize dd ?
FName db 13 dup (?) ;in DOS form, with dot if extension follows
ends
;N: Length "undocumented" = 21 bytes, "documented" = 22 bytes
struc TW32FindData ;DOS new and Win32 search record, at INT21/AX=714E&4F
;N: This is the same structure as WIN32_FIND_DATA, but file names will return
; in OEM character set rather than ANSI
attr dd ? ;bits 0..6: like DOS, bit 8: temporary (not used)
timec dq ? ;file creation time FAT stepping: 10 ms
timea dq ? ;last access time FAT stepping: 1 day
timem dq ? ;last modification time FAT stepping: 2 s
;On CDFS, all times have 1 s stepping
sizeh dd ? ;(not used) high part of file length (in wrong order)
sizel dd ? ;file length (FAT, CDFS: up to 2GB)
res dq ? ;maybe compressed file length? inode number? security?
lname db 260 dup (?) ;long name (LFN), alone if short
sname db 13 dup (?) ;short name (SFN), also called "alias"
ends
struc tErrInfo ;for Set_Error_Info INT21/AX=5D0A DS:DX=pointer
err_AX dw ?
err_BX dw ?
err_CX dw ?
err_DX dw ?
err_SI dw ?
err_DI dw ?
err_DS dw ?
err_ES dw ?
res dw ?
cid dw ? ;computer ID (0 for localhost)
pid dw ? ;process ID (same as PSP)
ends
struc tWinStart ;Format of Windows (W3) Startup Information Structure
ver_major db ? ;major version of info structure (3)
ver_minor db ? ;minor version of info structure (0)
next dd ? ;pointer to next tWinStart structure or 0000h:0000h
vxd_fname dd ? ;pointer to ASCIZ name of virtual device file or zero
vxd_rdata dd ? ;virtual device reference data
idata dd ? ;pointer to instance data records
ends
;*************************
;** FAT/CDFS structures **
;*************************
struc tDirEnt ;legacy directory entry on FAT media (FAT12, FAT16, FAT32)}
;source: Ralf Brown Interrupt List, SIZE=32
;N: First character (byte) has special meaning:
; 00: no more following DirEnts (a new cluster will be filled with zeroes)
; 05: first character is E5
; E5: deleted entry, undeleted DirEnts may follow
FName db 11 dup (?) ;FCB form without dot, upper-case letters
Attr db ?
resv db ? ;Win95: Null (maybe high part of file size)
timeC10ms db ? ;Win95: 10ms additional value to timeC [0..199]
timeC dd ? ;Win95: creation time (all local time)
timeA dw ? ;Win95: last access date
ClusH dw ? ;FAT32: high part of first cluster
timeM dd ? ;modification time
ClusL dw ? ;first cluster, FAT32: low part of first cluster
fsize dd ? ;file size
ends
struc TLfnDirEnt ;FAT LFN directory entry structure, SIZE=32
;N: The NameX protions of this structure are not directly used;
; they are addressed by "LODSW" and the gaps skipped by "ADD SI,space"
count db ? ;Bit 0..5: number (1+), Bit 6=last entry
Name1 dw 5 dup (?) ;five Unicode name characters
Attr dw ? ;always 000Fh
check db ? ;SFN checksum link
Name2 dw 6 dup (?) ;six Unicode name characters
Clus1 dw ? ;always zero
Name3 dw 2 dup (?) ;two Unicode name characters
ends
struc TCD_DirEnt ;CD (ISO and Joliet) directory entry structure
;N: A bunch of entries are ignored, SIZE>=34
r db ? ;the number of bytes in this record
ea db ? ;number of sectors in extended attribute record, zero
sect dd ? ;Logical Block Number of file start
sectm dd ? ;same for Motorola
fsize dd ? ;file or directory length in bytes, always divisable
;by sector size (2048) for directory length
fsizem dd ? ;same for Motorola
year db ? ;years past 1900 (all local time)
month db ? ;1 = January
day db ? ;1 = 1.
hour db ? ;0..23
minu db ? ;0..59
seco db ? ;0..59, mostly an even number(?)
tz db ? ;time zone of local time, signed, 15min, +east, -west
flags db ? ;attributes, Bit0=hidden, Bit1=Dir, Bit7=more DirEnts
;(Bit 7 is not correct on most CDs)
isiz db ? ;for interleaving, unused
igap db ? ;for interleaving, unused
vsn dw ? ;volume sequence number, unused
vsnm dw ?
fnamelen db ? ;file name length in Bytes (always even if Unicode,
; except for "." and ".." entries)
fname db ? ;file name (Motorola byte order if Unicode)
ends
;********************************
;** DOSLFN internal structures **
;********************************
;N: These structures are used inside DOSLFNs heap
;== part 1: DriveInfo data ==
IF 0
;bits for following <dtype>
DTM_mask =7 ;lower three bits are for general mode switch
DTM_FB =0 ;no bit set if FallBack
DTM_FAT =1 ;001 if FAT mode
DTM_ISO =2 ;010 if ISO mode
DTM_JOL =3 ;011 if Joliet mode, other codes are for future:
DTM_PT =4 ;100 PipeThrough (For this drive, there is an
; underlying LFN API, e.g. NTFSREAD)
;DTM_X =5 ;101 extfs2 (Linux) via LTOOLS
;DTM_UDF =6 ;110 UDF (Universal Disc Format, DVD)
;DTM_LFNBK =7 ;111 LFNBK file based LFN support - or some network
DT_Joliet =1 ;if not, take LFNs from ISO (these may also be long)
DT_CDFS =2 ;bit 1 acts as CDFS switch too
DT_BigDos =8 ;use extended INT25/26 interface
DT_FAT16 =16 ;FAT quantity, otherwise, it's FAT12
DT_FAT32 =32 ;don't use INT25/26, use INT21/AH=73 instead
;DT_SmartOS =64 ;set if OS already remove LFNs (MS-DOS7+) - no dtype!
DT_Locked =128 ;set if drive was locked (for writing, MS-DOS7+)
;N: Depending on DTM_mask'ed value if <dtype>, DOSLFN works in nearly
; complete different modi
; * FAT mode for diskettes and hard drives (even a ZIP drive uses FAT)
; * CD mode (rarely used) for ISO CDs with "long" ISO file names
; * Joliet mode, typical for Windows9x CDs
; * fall-back mode for all other drives
; This mode does not only map LFN_FindFirst/Next to its
; legacy companion, it also makes the extended pattern matching.
; Equally, LFN_Delete may delete multiple files using wildcards
; calling "legacy delete" multiple times.
; From the view of a programmer, it is very nice to have an LFN API
; on _all_ drives, and there is no need to make ugly cases.
; Note that also Win9x does wrap e.g. DOS network drives (Novell Lite)
; with its LFN API - therefore, FallBack is a "must" for compatibility.
; However, it conflicts with actual versions of NTFSREAD.
; Another useful mode would be an LFNBK mode, simply using a file
; for keeping long file names - this would instantly work on all drives.
struc TDI_FAT
shift db ? ;shift count for sector->cluster
shift2 db ? ;shift count for byte->sector (always 9)
fatsec dd ? ;first sector of active FAT
dirsec dd ? ;sector of root directory
usrsec dd ? ;sector of first cluster (ie cluster # 2)
lastsec dd ? ;last valid sector of user data
ends
ENDIF
struc TDI_ISO
voldesc dd ? ;volume descriptor
rootdir dd ? ;root directory sector
rootlen dw ? ;count of root directory sectors
ends
struc TDI_JOL
isotree TDI_ISO <?> ;same as above
joltree TDI_ISO <?> ;same as above for the Joliet tree
linktbl dw ? ;pointer to link table (keep trees together)
ends
IF 0
struc TDI ;linked structure for all media ("Drive Info")
next dw ? ;NEXT pointer into LocalHeap, zero if last
prev dw ?
time dw ? ;for discarding after a while (removable media only)
drive db ? ;drive number (0=A:)
dtype db ? ;control flags (DT_xxx constants)
secsiz dw ? ;sector size (DOSLFN is able to process any size?)
union
fat TDI_FAT <> ;additional data for FAT media
iso TDI_ISO <> ;additional data for ISO media
jol TDI_JOL <> ;additional data for Joliet media
ends
ends
;N: drive information is kept in a cache of 2..4 entries. Otherwise,
; copy actions (between different drives) would often retrieve the
; drive info, and clumsy-DOS seems to always read in boot area
ENDIF
;== part 2: SectorCache data ==
IF 0
struc TSC ;linked "sector cache" entry; sector data follows!
next dw ? ;NEXT pointer into LocalHeap, zero if last
prev dw ?
secnum dd ? ;sector number (of first sector)
count db ? ;sector count (always 1)
drive db ? ;drive number (0=A:)
dirty dw ? ;16 "dirty" (="modified") bits for up to 16 sectors
ends
;N: sector data is held in cache because MS-DOS doesn't cache anything,
; even when SmartDrv is loaded, when direct disc access is detected.
; Especially CD access is too slow without internal cacheing of at least
; two sectors. The LocalHeap is used up for cacheing until no more
; memory is available. All other memory allocations free least-recently
; used SectorCache entries to get necessary space.
ENDIF
;== part 3: FindHandle data ==
struc TFI_FAT ;size=6
entry dw ? ;offset from start of sector to current DirEnt
sect dd ? ;sector number of current DirEnt
ends
struc TFI_ISO ;size=8
entry dw ? ;offset from start of sector to current DirEnt
sect dd ? ;sector number of current DirEnt
count dw ? ;number of sectors to end of directory
ends
struc TFI_JOL ;size=22
i TFI_ISO <> ;same as above
j TFI_ISO <> ;same for Joliet tree
restart dd ? ;search-restart SFN sector
restlen dw ? ;search-restart SFN directory length
ends
;N: For Joliet, many additional fields are necessary to make a round-robin
; SFN match possible. Searching is primary done with LFN, and then
; the next matching SFN will be taken. If no such SFN is found, searching
; restarts at start of directory (using <restart> and <restlen> fields)
; until found. If there is no match too, simply the following entry
; is used. A match is when two DirEnts have the same start sectors
; (if file) or matching start sectors (via LinkTable, if directory).
; This complicated processing is necessary because entry order of LFN
; and SFN entries are not always the same.
; Limitation of <count> to a word seems to be not so bad; if some dude
; reach it, he has more than 500 000 files in one directory
struc TFI_FB ;size=21
dta db 21 dup (?) ;space for undocumented DTA part
ends
struc TFI ;interal representation of FindHandle ("FindInfo")
magic db ? ;MagicByte (to detect invalid handles)
drive db ? ;drive number (0=A:)
attr dw ? ;Search (LowByte) and MustMatch (HighByte) attributes
union
fb TFI_FB <> ;additional for FallBack
fat TFI_FAT <> ;additional for FAT
iso TFI_ISO <> ;additional for ISO
jol TFI_JOL <> ;additional for Joliet
ends
fflags db ? ;file flags (only DotAtEnd flag is used)
;N: fflags cannot be adressed easily. Structure fill and read-out
; is intended using LODSx and STOSx, respective.
;N: The file match pattern follows, but if it had a dot (.) at end,
; these dot is stripped from pattern and DotAtEnd flag is set
; due to special meaning of such a pattern
;N: For FallBack, also the file match pattern follows, but is only
; necessary if File_Flag_Is_LFN or _Char_High bits are in fflags
ends
IF 1
struc tFindInfo ;als interne Repr„sentation von FindHandle
usage db ? ;MagicByte
drive db ? ;Laufwerk
attr dw ? ;Attribute
entry dw ? ;Eintrags-Nr. (DirEnt-Zeiger)
sect dd ? ;Sektor-Nummer
cd_entry dw ? ;Joliet-DirEnt-Zeiger
cd_sect dd ? ;Joliet-Sektor-Nummer
fflags db ? ;File_Flags (nur DotAtEnd wesentlich?)
;anschlieáend Maske
ends
struc tFB_FindInfo
usage db ? ;ein anderes MagicByte
undoc db 21 dup (?) ;"undokumentierter" DTA-Bereich
mmattr db ? ;Attribut (CX beim Aufruf)
fflags db ? ;(nicht mehr wesentlich: File_Flag_DotAtEnd)
;anschlieáend: Maske
;(nur n”tig wenn File_Flag_Is_LFN oder Char_High)
ends
MAGIC_hFind =0ACh ;Magic-Byte fr gltiges Find-Handle
MAGIC_FB_hFind =0ADh ;dito fr Rckfallmodus
ENDIF
;== part 4: FastOpen data ==
IF 0
struc TFO ;linked structure for FastOpen
next dw ?
prev dw ?
drive db ? ;0=A:
ends
;N: FastOpen is absolutely necessary for reasonable speed.
; For multi-drive and copy-on-single-drive support, FastOpen
; is now organized as a cache with multiple entries.
ENDIF
;== done with the 4 parts ==
;N: All caches are organized as linked lists with most-recently used
; entries on head and least-recently used entries at tail of the lists.
; A cache hit moves the matched entry onto queue's head and updates
; the time stamp. Otherwise, a new structure is put onto head, and
; trailing entries may discarded to maintain maximum entry count
; (for drive info and FastOpen) or to get room (for sector cache).
; Because moving-to-head is done at access, and DOSLFN must not be
; reentered, static list pointers are also work area pointers.
;bits for main function control byte <ctrl0>
CTRL_Main =bit 7 ;main switch whether DOSLFN is active or turned off
CTRL_Write =bit 6 ;allow write access (except for DELETE/UNLINK/MOVE)
CTRL_Tilde =bit 5 ;tilde usage (HKLM/.../NameNumericTail)
CTRL_Tunnel =bit 4 ;tunnel effect
CTRL_CDROM =bit 3 ;CDROM support (default is ON if MSCDEX was loaded)
CTRL_InDOS =bit 2 ;InDOS flag usage
CTRL_RoBit =bit 1 ;write-protect attribute for CDROM files (like NORO)
;**********************************
;** static variables in PSP area **
;**********************************
;N: "Program Segment Prefix" area is used to reduce memory consumption
; of DOSLFN. Area before 5Ch is apparently used by some DOS extenders.
; Because DOS is not reentrant, LFNDOS doesn't need to be reentrant,
; therefore, these handy variables and buffers are allowed and usable.
org 5Ch
argv0 dw ? ;points to heap
argv0file dw ? ;points behind last backslash, 13 bytes space
;60h
LocalHeap dw ? ;zeigt auf Anfang des Heaps
TrailMinLen dw ? ;TrailByte: Minimum und Anzahl
DriverChain dd ? ;Zeiger ins DOS auf Treiber-Kette
lead_byte_table dd ? ;Zeiger ins DOS fr Fhrungsbyte-Bereiche
uppercase_table dd ? ;Zeiger ins DOS fr Zeichen >=80h
;Offset ist um 7Eh vermindert fr direktes XLAT
;70h
CurSector dd ? ;current "working" sector
longpos_s dd ? ;internal, set by Locate_DirEnt (FAT)
longpos_a dw ? ; -"-
CurPathComp dw ? ;Momentan "aktive" Pfad-Komponente oder Maske
DPB_Shift db ? ;{Verschiebung fr Sektoren pro Cluster}
DPB_Drive db ? ;{Drive Parameter Block: Laufwerk, 0=A}
DriveType db ? ;{Schalter fr Festplatten-Zugriffsart}
DT_BigDos =bit 0 ;erweiterte INT25/26-Schnittstelle
DT_DrvPar =bit 1 ;Wir haben Laufwerks-Info
DT_FAT32 =bit 2 ;gr”áere Žnderungen (kein INT25/26)
DT_FAT16 =bit 3 ;wegen FAT-Zugriff
DT_CDFS =bit 4 ;genauer: Joliet
DT_SmartOS =bit 5 ;wenn das Betriebssystem den LFN l”scht...
DT_Locked =bit 6 ;wenn geschrieben wurde (MS-DOS7+)
DT_Dirty =bit 7 ;Sektor muss geschrieben werden!
;In Abh„ngigkeit von DriveType arbeitet das Programm genaugenommen
;in 3 Modi (mehr sind nicht allgemein machbar):
;* FAT-Modus fr Disketten und Festplatten
;* Joliet fr Windows9x-typische CDs
;* Rckfallmodus fr alles andere: LFN_FindFirst u.a. wird mittels "normaler"
; Funktionen nachgebildet (wie es sonst jedes Programm zu Fuá tun máte,
; und das ist beim Programmieren nervenaufreibend, verflixte DTAs und
; das erweiterte Globbing)
;Sehr nett w„re ja noch ein "Netzwerk-Modus", bspw. per NFS oder DOS-Samba,
;aber wer liefert mir den Quelltext?
;Weiterhin ein "lfnbk"-Modus, mit Abbildung der langen Dateinamen ber
;eine regul„re Hilfsdatei
LFN_DirEnts db ? ;Anzahl DirEnts beim Schreiben des LFN
;This command-line area must not contain variables that initialize at startup
;80h - following 32 bytes are used (at least) three times!
ErrInfo TErrInfo <> ;overloads following
org 80h
FCB_Name db 11 dup (?) ;used for building unique file name
;Never contains 05h as first byte
ShortName db 13 dup (?) ;filled by (CD_)Locate_DirEnt
;here we have 8 bytes room - temporary needed for reading ISO file names
org 80h
DirEnt_Copy TDirEnt <> ;32 bytes space for moving FAT DirEnt while
;inserting LFN, may have 05h as first byte
;A0h
DPB_FAT1Sec dd ? ;FAT: Startsektor 1. FAT
DPB_DirSec dd ? ;{Sektor Hauptverzeichnis (nur FAT)}
DPB_UsrSec dd ? ;{Sektor des 1. Clusters (mit Nr. 2)}
DPB_LastSec dd ? ;{Letzter Sektor der Partition}
;B0h
shortbuffer db 3+64+13 dup (?) ;Puffer fr kurze 8.3-Dateinamen
;100h - three bytes for JMP are free for use
LastAccessTime dw ?
subst_drive db ? ;Zeichen, geSUBSTetes (virtuelles) Laufwerk
;Program Control Flag Byte Assignment:
PF_Fail_Uni2Oem =bit 0 ;Nicht zu OEM konvertierbarer Unicode-Name
PF_Follow =bit 1 ;Sektor-Verfolgung nach DirScan
PF_LFN_Input =bit 2 ;LongName-API Namensinterpretation
PF_Slash =bit 3 ;Entfernter Slash bei Gen_Alias
PF_Tunnel_Save =bit 4 ;save LFN before calling OldInt21
PF_Tunnel_Restore=bit 5 ;restore LFN after calling OldInt21
;*****************************
;** Stack Frame Assignments **
;*****************************
;N: Due to complex data processing inside DOSLFN, it's not worth
; to keep register data. Registers are pushed onto stack, and with setting
; BP, these registers are easily available via stack frame, ie
; BP and a small offset value, as defined below.
; This technique is known from Windows VxD programming.
;N: Some bit registers are kept onto stack too, their bit-access consumes
; one byte less op-codes than bit-access to a static variable.
File_Flags equ byte bp-6 ;properties of last path component
FuncNum equ byte bp-5 ;{properties of drive used}
Client_E_DX equ word bp-4 ;high part of EDX (unreferenced)
Client_E_AX equ word bp-2 ;high part of EAX (unreferenced)
Client_DI equ word bp ;frame of "pusha" op-code
Client_SI equ word bp+2
Client_BP equ word bp+4 ;(unreferenced)
;Client_SP equ word bp+6 ;free space for us - never popped
PFlags equ byte bp+6 ;input control flags
ctrl equ byte bp+7 ;program control flags
Client_BX equ word bp+8
Client_DX equ word bp+0Ah
Client_CX equ word bp+0Ch
Client_AX equ word bp+0Eh
Client_ES equ word bp+10h
Client_DS equ word bp+12h
Client_FS equ word bp+14h ;(unreferenced)
Client_IP equ word bp+16h ;(unreferenced)
Client_CS equ word bp+18h ;(unreferenced)
Client_Flags equ word bp+1Ah
Client_DXBX equ dword bp+8
Client_CXDX equ dword bp+0Ah ;CX=High, DX=Low, in einem Schlag
Client_AXCX equ dword bp+0Ch
Client_AL equ byte LOW Client_AX
Client_AH equ byte HIGH Client_AX
Client_BL equ byte LOW Client_BX
Client_BH equ byte HIGH Client_BX
Client_CL equ byte LOW Client_CX
Client_CH equ byte HIGH Client_CX
Client_DL equ byte LOW Client_DX
Client_DH equ byte HIGH Client_DX
;*******************************
;** Start of program and ISRs **
;*******************************
;N: Both Interrupt Service Routines (ISRs) are moved to start of .COM
; image to reduce possible offset changes during development.
; Offset changes made resident DOSLFN indeinstallable, and I had to reboot
org 100h
jmp transient
ctrl0 db 11110110b ;8 Ein/Aus-Schalter
;Bit7: global ein/aus
;Bit6: Schreiben e/a
;Bit5: Schlangen e/a
;Bit4: Tunneleffekt e/a
;Bit3: CDROM-Code vorhanden e/a
;Bit2: InDOS-Benutzung
;Bit1: Schreibschutz-Attribut fr CD e/a (NORO.COM Gegenstck)
;Bit0: (ungenutzt)
proc NewInt21 far ;Neue INT21-Routine
;D: Int21 handler, always returns with IRET, chaining to OldInt21
; by jumping rather than calling preserves stack frame for odd-behaved
; other APIs (if any)
; Contains Installation Check of DOSLFN (maybe moved to Int2F)
pushf
cmp ax,REQfunc ;Installationscheck?
jne I21cont
cmp dx,REQcode
jne I21cont
mov ax,ANScode
mov dx,cs
popf
iret
endp
proc NewInt2F far
;D: Because of dummies and for easier usage, DOSLFN (version 0.32j+)
; traps Int2F for following actions:
; * Disables itself when Win9x starts, giving a hint message
; * Loads an API translating VxD "LFNXLAT.386" when Win3x starts
; * giving a warning message pointing to missing API translation
; when Win3x or Win2x start in Standard Mode (=PM286)
; * Loads the appropriate OEM<->Unicode conversion table when
; NLSFUNC changes the code page
; * Future Installation Check of DOSLFN may reside here
pushf
cmp ax,1605h ;Windows Enhanced Mode Init Broadcast
jz @@handle
cmp ax,1606h ;Exit Broadcast
jz @@handle
cmp ax,1401h ;NLSFUNC.COM CallOut BX=Codeseite
jz @@handle
; cmp ax,0AD01h ;DISPLAY.SYS API Aufruf BX=Codeseite
; jz @@handle
@@e: popf
JMPF ;= db 0EAh
OldInt2F dd ?
@@handle:
popf
; push ax ;(Stack-Parameter fr HandleWindowsOrCP)
pushf
call [cs:OldInt2F]
call HandleWindowsOrCP
iret
endp
proc I21cont far
test [cs:ctrl0],CTRL_Main
jz @@isrend ;do nothing if main switch is OFF
xchg ah,al ;AL comparings are shorter
cmp al,71h ;LFN functions?
je @@yes_lfn
cmp al,3Ah ;SFN rmdir?
je @@yes_sfn ;remove LFN entry, prepare tunnel!
cmp al,41h ;SFN unlink?
je @@yes_sfn ;remove LFN entry, prepare tunnel!
cmp al,56h ;SFN move? (dst=ES:DI)
je @@yes_sfn ;remove LFN, prepare&apply tunnel!
cmp al,39h ;SFN mkdir?
je @@yes_sfn ;apply tunnel!
cmp al,3Ch ;SFN creat?
je @@yes_sfn ;apply tunnel IF file doesn't exist
cmp al,5Bh ;SFN create new?
je @@yes_sfn ;apply tunnel!
cmp ax,006Ch ;SFN extended open/create?
je @@yes_sfn ;apply tunnel IF..., take DS:SI!
cmp al,4Eh ;SFN FindFirst?
xchg ah,al
je @@filter0F ;filter out volume labels!
cmp ah,4Fh ;SFN FindNext?
je @@filter0F ;filter out volume labels too!
cmp ah,11h ;FCB FindFirst?
je @@FCB_11 ;filter out volume labels!
cmp ah,12h ;FCB FindNext?
je @@FCB_12 ;filter out volume labels too!
@@isrend: popf
JMPF ;jmp far (db 0EAh)
OldInt21 dd ? ;only this kind of jump makes no trouble
@@filter0F: ;bei FindFirst/FindNext Rckgaben mit Attribut 0Fh auswerfen
popf
sti
call sfn_find ;this routine is fully reentrant
retf 2
@@FCB_11:
popf
call sfn_find_FCB
mov ah,11h ;set back (may be altered to 12h)
iret
@@FCB_12:
popf
call sfn_find_FCB
iret
@@yes_lfn:
INT3
@@yes_sfn:
popf ;save two bytes of stack needed
xchg ah,al
call IncInDosFlag
sti ;reentrancy should be detected by caller
push fs ds es ;bp+14h .. bp+10h
pusha ;ax=bp+0Eh, cx..dx..bx..sp..bp..si..di=BP+0
mov bp,cs
mov ds,bp
mov es,bp
mov bp,sp
push eax ;High-Teile retten fr PKZIP
mov al,[ctrl0]
mov [ctrl],al ;access needs less bytes
pop ax
push edx
cld
mov [throw_sp],sp ;prepare and beautiful error exit, less "jc"
mov [throw_fi],ofs _fcb_retu ;standard finalizer
mov fs,[Client_DS] ;h„ufig ben”tigt
shr [by LOW Client_Flags],1 ;CY ausschieben
cmp ah,71h
je @@yes_long
mov al,PF_Tunnel_Restore
cmp ah,3Ah
je @@rm
cmp ah,41h
je @@rm
cmp ah,56h
jne @@cr
mov al,PF_Tunnel_Save or PF_Tunnel_Restore
jmp @@cr
@@rm: mov al,PF_Tunnel_Save
@@cr: mov [PFlags],al
call sfn_process ;all writing SFN functions
jmp __no_func
@@yes_long:
call CheckLoadCP
mov [PFlags],PF_LFN_Input
mov [FuncNum],al
mov di,ofs verteiler
call case
mov ax,7100h ;fr "nicht untersttzt" (->PFlags!)
jc __no_func
inc [counter_i2171]
call [wo di]
__no_func:
jnc @@no_ax
mov [Client_AX],ax
@@no_ax: rcl [by LOW Client_Flags],1 ;CY einschieben
pop edx
push ax
pop eax
popa
pop es ds fs
call DecInDosFlag
iret
endp
;THROW-Geschichten...
SetErr18:
mov al,18
db 0B9h ;mov cx,nnnn
SetErr5:
mov al,5
db 0B9h ;mov cx,nnnn
SetErr3:
mov al,3
db 0B9h ;mov cx,nnnn
SetErr2:
mov al,2
SetError:
call SetExtError ;"eigene" Fehler setzen
stc
proc Throw
mov sp,8086
throw_sp = wo $-2
call [throw_fi]
jmp __no_func
endp
;***************************
;** Legacy API twiddeling **
;***************************
;N: Except MS-DOS7+, other DOS versions generate some garbage on
; FindFirst/Next: they list out LFNs as volume labels.
; Well-behaved file managers ignore these entries, but some other
; like COMMAND.COM's built-in DIR doesn't.
; Therefore, it's up to DOSLFN to wipe out such returns, proceeding
; with next DirEnt.
; And while we twiddle with DirEnts, this is a good chance to
; remove the ugly ReadOnly bits out of CD DirEnts, but is not yet done.
proc noentry_sfn_find
;D: DirEnts with attribute 0Fh (LFN designator) must be wiped out.
; (MS-DOS 7+ and Windows NT [DOS 5] do this;
; this is necessary for all other DOS versions)
;I: registers unchanged, _without_ BP stack frame!
;F: INT21/4E&4F alter AX even if successful! 09/01, claude.caillet@free.fr
@@rept: popf
mov ah,4Fh
sfn_find:
call CallOld
jc @@e
pushf ;don't change other flags (esp. ZF)
push ax bx es
mov ah,2Fh
call CallOld ;get address of DTA
cmp [(TSearchRec es:bx).attr],0Fh
pop es bx ax
je @@rept ;next iteration makes FindNext
popf
@@e: ret
endp
proc sfn_find_FCB
;FU: FindFirst/FindNext via FCB muss auch gefiltert werden
; (so ein Laster, das von der COMMAND.COM aufgebrdet wird,
; niemand sonst verwendet diese Funktionen heutzutage.)
; (MS-DOS 7 und Windows NT [DOS 5] filtern selbst;
; notwendig ist diese Aktion fr alle anderen DOS-Versionen)
@@rept: call callold
or al,al
jnz @@err
push bx es
mov ah,2Fh
call CallOld ;get address of DTA
cmp [by es:bx],0FFh ;Extended FCB?
jne @@1 ;nein, bx nicht verschieben
add bx,7
@@1: cmp [by es:bx+12],0Fh
pop es bx
mov ah,12h
je @@rept
@@err: ret
endp
proc SFN_AL_CallOld
;FU: Aufruf des vorherigen INT21 mit DX=Zeiger auf ShortBuffer
; Seiteneinstiege ohne Laden von AH und DX
mov ah,[Client_AL]
SFN_CallOld:
mov dx,ofs ShortBuffer
CallOld:
; call DecInDosFlag
pushf
call [cs:OldInt21]
; call IncInDosFlag
_coat: ret
endp
proc CallOldAndThrow
call CallOld
jnc _coat
jmp Throw
endp
proc SetExtError
;DOS-Fehler (fr Int21 AH=59h) setzen (fr momentanes PSP)
;Tats„chlich ben”tigt Win95 COMMAND.COM diese Funktion!
mov ah,0 ;alles "kleine" Fehler
push ax
mov di,ofs ErrInfo
mov dx,di
stosw
mov cx,(SIZE ErrInfo)/2 -2
xor ax,ax
rep stosw ;dazwischen lauter Nullen
mov ah,62h
call CallOld ;PSP ermitteln
xchg bx,ax ;als letztes
stosw
mov ax,5D0Ah
call CallOld ;Fehler setzen
pop ax
ret
endp
;*****************************************
;** Windows and Code Page Notifications **
;*****************************************
proc HandleWindowsOrCP
;D: Instruct Windows 3.x to load a VxD for API translating
;(PE: Auf dem Stack: AX vor dem Aufruf von OldInt2F - nein!)
;PE: DS und ES zeigen (n)irgendwohin!
; Bei Windows (AH=16):
; Bit0(DX)=0: Enhanced Mode
; Bei Windows-Start (AL=5):
; DS:SI=(uninteressant hier)
; ES:BX=LPWinStart
; CX=0: Windows darf starten
; DI=Versionsnummer
; bei Codeseitenwechsel (AH<>16):
; AL=0: OK (von DISPLAY.SYS o.„.)
; BX=Codeseite
;PA: nur bei Windows-Start (AX=1605, DI<0400):
; ES:BX=neue LPWinStart zum Laden von LFNXLAT.386
;VR: keine! Auch keine Segmentregister! Auáer ES:BX im Fall s.o.
; [ErrInfo]
push ds es
pusha
LD es,cs
LD ds,cs
mov bp,sp
cld
cmp ah,16h ;Betrifft Windows?
je @@win
or al,al ;CHCP verlief OK?
jnz @@e
mov [NewCP],bx ;Wegen InDOS muss verz”gert geladen werden
jmp @@e
@@win:
BTST dx,bit 0 ;Enhanced Mode?
jnz @@e
cmp al,05h ;Init Broadcast?
je @@winstart
BSET [ctrl0],CTRL_Main ;dann Exit Broadcast (AL=6)
jmp @@e
@@winstart:
or cx,cx ;Anderes TSR str„ubt sich?
jnz @@e
cmp di,400h ;Windows 95+?
jc @@loadvxd
BRES [ctrl0],CTRL_Main
jmp @@e
@@loadvxd:
lea di,[ErrInfo]
mov [Client_BX],di ;BX modifizieren
mov ax,3 ;Version 3.00
stosw
xchg ax,bx
stosw
mov ax,es
xchg ax,[Client_ES] ;ES modifizieren
stosw
mov ax,[argv0]
stosw
mov ax,ds
stosw
xor ax,ax
mov cl,4 ;CH=0
rep stosw ;2 DW”rter
lea si,[lfnxlatvxd$]
mov di,[argv0file]
call strcpy
@@e: popa
pop es ds
ret
endp
proc MakeTblFileName
;PE: DI=Ziel Dateiname
; BX=Codeseite
;VR: AX,BX,CX,DX,DI
lea si,[TblFileName$]
call strcpy ;DI zeigt hinter die Null
mov ax,10
xchg ax,bx
@@l: xor dx,dx
div bx
add dl,'0'
mov [di-9],dl;"UNI.TBL\0" zurck auf die letzte Ascii-Null
dec di
or ax,ax
jnz @@l ;maximal 5 Runden
ret
endp
proc LoadCP
;D: Loads Code Page Table (CPxxxUNI.TBL) file according to code page in BX
;PE: BX=Codeseite (bei Nummern >=1000 wird "P" oder "CP" berschrieben)
;VR: alle (auáer FS)
mov di,[argv0file]
call MakeTblFileName
mov dx,[argv0]
; jmp LoadUniFile
endp
proc LoadUniFile
;D: Loads Unicode file to, removes old table from heap
;I: DX=filename
;O: CY=1 error, BL=3: cannot open file, BL=4: wrong file format
; CY=0 OK, table loaded
;VR: alle, DS=ES, [ErrInfo], [TrailMinLen], [UniTableLen]
;L„dt beide Arten von Tabellen; die Unterscheidung, ob SBCS oder DBCS
;f„llt Oem2Uni bzw. Uni2Oem anhand IsDbcsLeadByte, dem Tabellen-Wert u.„.
DOS 3D00h ;zum Lesen ”ffnen
mov bl,3
jc @@e ;Datei nicht gefunden o.„.
ReadUniFile: ;Einstieg mit AX=Handle
xchg bx,ax
mov cx,32
lea dx,[ErrInfo]
DOS 3Fh ;32 Bytes lesen, Header darf nicht l„nger sein
cmp ax,cx
jne @@e13 ;Datei ungltig: viel zu kurz
mov si,dx
@@l: lodsb
or al,al ;Kennbyte 00h
jz @@e13 ;von ASCII->ASCII-Tabellen weiá DOSLFN nichts
dec ax ;Kennbyte 01h (in ersten 32 Byte)? (AH=0)
jz @@1 ;"normale" Unicode-Tabelle
dec ax ;Kennbyte 02h (in ersten 30 Byte)? (AH=0)
loopnz @@l
;DBCS
cmp cl,2 ;Keine 2 Bytes da?
jc @@e13 ;dann .TBL ungltig
lodsw ;DBCS-Info
mov [TrailMinLen],ax
@@1: ;SBCS
sub si,dx
xor cx,cx
push si ;Lese-Position
xor dx,dx
DOS 4202h ;Datei-L„nge in DX:AX, DX wird ignoriert
pop dx
sub ax,dx
or ah,ah ;wie "cmp ax,100h"
jz @@e13 ;Datei zu kurz
push ax ;Rest-L„nge in AX
shr ax,1
mov [UniTableLen],ax ;Anzahl Unicodes, bei SBCS = 80h
DOS 4200h ;jetzt zum Daten-Anfang (CX=0)
lea di,[UniXlat]
call FreeDIPtr
pop ax
push ax
call iLocalAlloc
mov [UniXlat],di
pop cx
jc @@e13 ;Zu lang, Heap reicht nicht
mov dx,di
DOS 3Fh
cmp ax,cx
jne @@e13 ;Datei ungltig: zu kurz (kann nicht sein)
DOS 3Eh ;DOS setzt CY
@@e: ret
@@e13: DOS 3Eh
mov bl,4
stc
ret
endp
proc CheckLoadCP
;Prft auf neue Unicode-Tabelle und l„dt diese gegebenenfalls nach
pusha
xor bx,bx
xchg [NewCP],bx
or bx,bx
jz @@e
call LoadCP
jnc @@e
mov [LastError],5
@@e: popa
ret
endp
;****************************************
;** Initialized Constant and Data Area **
;****************************************
language db 'E' ;'D'eutsch,'F'rancais,'N'ihongo,'R'ussky?
UniXlat dw 0 ;0 bedeutet hier: OEM = ISO-Latin-1
NewCP dw 0 ;wird bei Int2F gesetzt
rwrec tRWRec <?,1,ofs Sektor>
lfnxlatvxd$: dz "LFNXLAT.386"
TblFileName$: dz "CP000UNI.TBL"
align 2
;N: The following OEM->Unicode conversion table may be overloaded from file.
; Therefore, all 1-byte-per-character DOS versions can be supported
; with all national characters.
; For locales with DBCS (double-byte character set), like Chinese,
; Japanese, or Hangul (=Korea), such a table is not applicable;
; DOSLFN doesn't work.
;N2: THIS TABLE ISN'T INTEGRATED AND USED ANYMORE (01/03) WITH FULL-DBCS
;label oem_uni_tab word ;hier: Codeseite 437
; dw 00C7h, 00FCh, 00E9h, 00E2h, 00E4h, 00E0h, 00E5h, 00E7h
; dw 00EAh, 00EBh, 00E8h, 00EFh, 00EEh, 00ECh, 00C4h, 00C5h
; dw 00C9h, 00E6h, 00C6h, 00F4h, 00F6h, 00F2h, 00FBh, 00F9h
; dw 00FFh, 00D6h, 00DCh, 00A2h, 00A3h, 00A5h, 20A7h, 0192h
; dw 00E1h, 00EDh, 00F3h, 00FAh, 00F1h, 00D1h, 00AAh, 00BAh
; dw 00BFh, 2310h, 00ACh, 00BDh, 00BCh, 00A1h, 00ABh, 00BBh
; dw 2591h, 2592h, 2593h, 2502h, 2524h, 2561h, 2562h, 2556h
; dw 2555h, 2563h, 2551h, 2557h, 255Dh, 255Ch, 255Bh, 2510h
; dw 2514h, 2534h, 252Ch, 251Ch, 2500h, 253Ch, 255Eh, 255Fh
; dw 255Ah, 2554h, 2569h, 2566h, 2560h, 2550h, 256Ch, 2567h
; dw 2568h, 2564h, 2565h, 2559h, 2558h, 2552h, 2553h, 256Bh
; dw 256Ah, 2518h, 250Ch, 2588h, 2584h, 258Ch, 2590h, 2580h
; dw 03B1h, 00DFh, 0393h, 03C0h, 03A3h, 03C3h, 03BCh, 03C4h
; dw 03A6h, 0398h, 03A9h, 03B4h, 221Eh, 03C6h, 03B5h, 2229h
; dw 2261h, 00B1h, 2265h, 2264h, 2320h, 2321h, 00F7h, 2248h
; dw 00B0h, 2219h, 00B7h, 221Ah, 207Fh, 00B2h, 25A0h, 00A0h
;B: Because a more advanced DOSLFN version should fully support Japanese,
; this table is intended to load dynamically and to move into heap.
;B: For Japanese support, the conversion table to load must contain code
; for: MBCS->Unicode, Unicode->MBCS, and Upcase.
; Difficult for DBCS is the Path Delimiter "\", because it maps to YEN
; symbol, even worse, it is a valid trail byte.
; This is done by Microsoft. Much easier is the use of "/" instead.
;N: Format of such a DBCS<->Unicode table is yet defined: see TBL.TXT
Invalid_Lfn_Chars db '"<|>:\/' ;7 characters
Invalid_Chars db 0,' .+,;=[]' ;the order here is strategic
;B: Both charsets above mean invalid characters for SFN. The dot (.)
; has special meaning in SFN and is handled separately
;B: Normally, the space character 32 (20h) is allowed in SFN,
; but the Win9x LFN API dircards spaces (and dots) when building SFN aliases
; Furthermore, the space is problematic because most command-line
; utilities do not support an escape to interpret a space literally
;B: Dots and spaces are invalid for LFNs at the end! They are stripped
; automatically. Consequently, names containing only dots and/or spaces
; are invalid, with the exception "." and ".." for the special directories.
;B: Although Explorer doesn't allow to create names _beginning_ with a dot
; or space, these are allowed file names. This is an Explorer bug.
;Statistik-Z„hler
counter_read dw 0
counter_write dw 0
counter_i2171 dw 0
LastError db 0
proc Check_CDFS
test [DriveType],DT_CDFS ;bytefressender Befehl
ret
endp
proc Check_CDFS_Throw
call Check_CDFS
jnz SetErr5
ret
endp
;*****************************
;** Basic Sector Read/Write **
;*****************************
ReadNextSec:
inc [CurSector]
proc ReadSec
;{Liest einen Sektor Nummer <CurSector> nach <Sektor>, PA: CY=1:Fehler}
;Liest nur, wenn's ein neuer Sektor ist!
;PE: CurSector=Sektor-Nummer
;PA: [Sektor] gefllt mit Sektor-Daten
; CY=1: Fehler
;VR: alle (bedeutet hier und im folgenden EAX,BX,CX,EDX,SI und DI,
; nicht aber DS,ES,SS,SP und BP, werden dann extra gelistet)
mov eax,[CurSector]
ReadSecEAX:
mov [CurSector],eax
cmp [rwrec.sect],eax
je @@e ;nichts tun!
call FlushDirty
cmp eax,[CD_BackupSektor]
je @@restore_backup
jmp @@make_backup
@@nobackup:
mov [rwrec.sect],eax
inc [counter_read]
mov al,[DriveType]
test al,DT_CDFS
jnz @@cdfs
xor si,si ;lesen FAT32
mov di,ofs int25 ;lesen FAT16
jmp Fat_RW
@@cdfs:
mov eax,[CD_BackupSektor]
cmp eax,[rwrec.sect]
je @@restore_backup
mov bx,ofs CD_Sektor
mov si,[wo HIGH rwrec.sect]
mov di,[wo LOW rwrec.sect]
movzx cx,[DPB_Drive]
mov dx,1 ;nur 1 Sektor!
MUX 1508h ;MSCDEX: Sektor lesen
@@e:
ret
@@restore_backup:
call Check_CDFS
jz @@nobackup
xchg [rwrec.sect],eax
mov [CD_BackupSektor],eax
mov si,ofs CD_Sektor
mov di,ofs CD_Backup
mov cx,1024 ;512 DWords = 2048 Bytes
@@swap:
mov ax,[si]
xchg [di],ax
mov [si],ax
cmpsw ;einfach si+=2 und di+=2
loop @@swap
clc
ret
@@make_backup:
call Check_CDFS
jz @@nobackup
push eax
mov eax,[rwrec.sect]
mov [CD_BackupSektor],eax
mov cx,512
mov si,ofs CD_Sektor
mov di,ofs CD_Backup
rep movsd
pop eax
jmp @@nobackup
endp
;******************************
;** Basic Sector Cache Flush **
;******************************
proc FlushDirty
test [DriveType],DT_Dirty
jz @@e
_WriteNow:
push eax
call WriteSec
pop eax
and [DriveType],not DT_Dirty
@@e: ret
endp
proc WriteNow
call _WriteNow
ResetDrv:
mov ah,0Dh
jmp CallOld
endp
proc WriteSec
;{Schreibt Sektor <Sektor> nach Nummer <RWRec.Sect>, PA: Fehlercode}
;PE: RWRec.sect=Sektor-Nummer
; [Sektor] gefllt mit Sektor-Daten
;PA: CY=1: Fehler
;VR: alle
inc [counter_write]
mov si,4001h ;schreiben: Verzeichnis-Bereich FAT32
mov di,ofs int26 ;schreiben: FAT16
bts [wo DriveType],6 ;DT_Locked
jc Fat_RW ;Laufwerk ist bereits gesperrt
mov bl,[DPB_Drive]
inc bl
mov bh,0 ;LOCK LEVEL
mov cx,084Ah
mov dx,1 ;fr Schreibzugriff
mov ax,440Dh
call CallOld ;DOS7 LOCK
;jmp Fat_RW
endp
proc Fat_RW
;FU: Lesen und Schreiben von/auf FAT16 und FAT32
;PE: DI=Zeiger auf Prozeduren int25 oder int26 (FAT16)
; SI=0 fr Lesen, 4001h fr Schreiben Verzeichnis-Daten (FAT32)
; [DPB_Drive]=Laufwerk (0=A: usw.)
; [DriveType]=Laufwerkstyp, FAT12/16/32,BIGDOS
; [RWRec]=Sektor,Anzahl,Speicheradresse
;VR: alle
mov al,[DriveType]
test al,DT_FAT32
jnz Fat32_RW
test al,DT_BigDos
jnz @@b ;{gleich zu BIGDOS}
mov si,ofs RWRec ;3 Bytes
lodsw ;je 1 Byte
xchg dx,ax ;DX=Sektornummer
lodsw
lodsw
xchg cx,ax ;CX=Anzahl
lodsw
xchg bx,ax ;DS:BX=Sektor-Adresse
push di
call @@pu
pop di
jnc @@e
cmp ax,0207h ;{zu BIGDOS wechseln? lt.RBIL}
stc
jnz @@e ;{nein, sonstiger Fehler}
or [DriveType],DT_BigDos
@@b:
lea bx,[RWRec]
mov cx,0ffffh
@@pu: mov al,[DPB_Drive]
push bp ;zumindest DR-DOS zerst”rt BP
call di
pop bp
@@e: ret
endp
proc Fat32_RW
;FU: Lesen und Schreiben von/auf FAT32
; [DPB_Drive]=Laufwerk
; [RWRec]=Sektor,Anzahl,Speicheradresse
mov dl,[DPB_Drive]
inc dl
mov cx,0FFFFh
lea bx,[RWRec]
mov ax,7305h
jmp CallOld ;10/02: ohne Rekursion
endp
proc int25
int 25h
pop bp ;{Stack korrigieren}
ret
endp
proc int26
int 26h
pop bp ;{Stack korrigieren}
ret
endp
proc GetDrvParams pascal
uses es,si
;{Ermittelt Laufwerksparameter fr <@drive> (1=A: usw.)
; und setzt die Variablen DPB_xxx sowie DriveType, PA: DriveType<>0 wenn OK}
; Von Laufwerken >=C: erfolgt die Bestimmung nur bei neuem Buchstaben,
; bei Disketten- und CD-Laufwerken nur nach Ablauf eines TimeOuts
;PE: AL=Laufwerksnummer (0=current, 1=A:)
sub al,1
jnc @@nodef
mov ah,19h ;Akt. Laufwerk beschaffen
call CallOld
@@nodef:
cmp al,[DPB_Drive] ;gleich?
jne @@readin ;bei Unterschied sofort lesen
cmp al,2
mov cx,FDChangeTime
jc @@chktick ;Laufwerke default:, A: und B:
call Check_CDFS
mov cl,CDChangeTime
jnz @@chktick
@@nc0:
jmp @@no_change ;etwas Jump-over-Jump
@@chktick:
push ax
call GetTick
sub ax,[LastAccessTime]
cmp ax,cx
pop ax
jc @@nc0
@@readin:
push ax
call CD_Done ;Dynamische Datenstrukturen aufgeben
test [DriveType],DT_Locked
jz @@no_lock
mov bl,[DPB_Drive]
inc bl
mov cx,086Ah
mov ax,440Dh ;MS-DOS7 UNLOCK
call CallOld
@@no_lock:
pop ax
mov [DPB_Drive],al
mov [DriveType],0
;{Abfrage fr FAT12/FAT16}
push ds
mov dl,[DPB_Drive]
inc dl
mov ah,32h ;{liefert AL=0:OK, FFh=Fehler}
call CallOld
mov dx,ds
pop ds
or al,al
jnz @@test32
mov es,dx
cmp [(tExDPB es:bx).SecLen],200h ;{Standardm„áige Sektorl„nge?}
jnz @@e
mov al,[(tExDPB es:bx).Drive]
cmp al,[DPB_Drive] ;geSUBSTet?
jne @@e
or [DriveType],DT_DrvPar
movzx eax,[(tExDPB es:bx).UsrSec]
mov [DPB_UsrSec],eax
mov ax,[(tExDPB es:bx).ResSec]
mov [DPB_FAT1Sec],eax
mov ax,[(tExDPB es:bx).SecDir]
mov [DPB_DirSec],eax
mov cl,[(tExDPB es:bx).Shift]
mov ax,[(tExDPB es:bx).HiClus] ;Letzter Cluster
cmp ax,0FF6h
jbe @@ok
or [DriveType],DT_FAT16
@@ok:;Ansprung mit CL=Shift und EAX=LastCluster
mov [DPB_Shift],cl
inc eax
shl eax,cl ;1.nicht-adressierbarer Sektor
dec eax
mov [DPB_LastSec],eax
cmp eax,0FFFFh
jc @@e
or [DriveType],DT_BigDos
jmp @@e
;{Abfrage fr FAT32}
@@test32:
call get_dpb_32 ;now with own stack frame
jnc @@ok
@@test_cd:
test [ctrl],CTRL_CDROM
jz @@nodrv ;Will kein CD-ROM erkennen
mov cl,[DPB_drive]
mov ch,0 ;CX=Laufwerk (hier 0=A:)
call CD_Init
jnc @@e
@@nodrv:
mov [DriveType],0 ;kein untersttzter Laufwerkstyp
jmp @@e
@@e:
call InvalSector
mov [fastopen_buf],0
@@no_change:
call GetTick
mov [LastAccessTime],ax
ret
endp
proc get_dpb_32 pascal
;I: [DPB_Drive]=drive to get info
;O: [DPB_Drive]=physical drive (changed if SUBSTed)
; [DriveType], [DPB_FAT1Sec], [DPB_UsrSec], [DPB_DirSec] filled with values
; EAX=max_cluster
; CL=shift
; CY=1 if error
;N: change 10/01: stack storage for tExDPB, never overwrite sector data
local @@DPB:TExDpb
push 3Dh ;61 bytes space, marker below @@dpb
mov di,sp
push es
LD es,ss
mov cx,3Fh ;{63 Bytes}
mov dl,[DPB_Drive]
inc dl
mov si,0F1A6h
stc
mov ax,7302h ;{get extended DPB}
call CallOld
pop es
jc @@e ;{Fehler: kein FAT32}
cmp [@@DPB.SecLen],200h
stc
jne @@e ;cannot yet accept other sector sizes
mov al,[@@DPB.Drive]
cmp al,[DPB_Drive]
stc
jne @@e ;cannot support SUBSTed drives yet
or [DriveType],(DT_FAT32 or DT_BigDos or DT_DrvPar)
;{FAT32 ist immer BigDos}
movzx eax,[@@DPB.ResSec]
mov [DPB_FAT1Sec],eax
mov eax,[@@DPB.first_sector]
mov [DPB_UsrSec],eax
;here bugfix 10/01: root directory is not always at cluster 2!
mov cl,[@@DPB.Shift]
mov eax,[@@DPB.root_cluster]
sub eax,2
shl eax,cl
add eax,[DPB_UsrSec] ;should CLC
mov [DPB_DirSec],eax
mov eax,[@@DPB.max_cluster]
@@e: ret
endp
proc InvalSector
;FU: Gelesenen Sektor-Inhalt fr ungltig erkl„ren
; (weil Schreibzugriff auf Verzeichnis erfolgte u.„.)
mov [rwrec.sect],-1 ;"falscher Sektor" laden
ret
endp
;Es muss die Zeit beim Zugriff auf wechselbare Medien
;(A:, B: und CD-Laufwerke) erfasst werden...
proc GetTick
push ds
push 40h
pop ds
mov ax,[6Ch] ;55-ms-Timer abfragen (Aufw„rtsz„hler)
pop ds
ret
endp
fstrcpyBS: mov ax,ofs strcpyBS
jmp noentry_fstrcpy
fstrcpy: mov ax,ofs strcpy
proc noentry_fstrcpy pascal
;fast normale strcpy-Funktion, erwartet cld, ver„ndert keine Register
;liefert in AX Anzahl kopierter Zeichen (ohne Null), also strlen
arg @dst:dword,@src:dword
uses ds,es,si,di
lds si,[@src]
les di,[@dst]
call ax
lea ax,[si-1]
sub ax,[wo LOW @src] ;Anzahl Zeichen
ret
endp
proc strcpyBS
@@l: lodsb
cmp al,'/'
jne @@1
mov al,'\'
@@1: stosb
or al,al
jnz @@l
ret
endp
proc strcpy
lodsb
stosb
or al,al
jnz strcpy
_fcb_retu:
ret
endp
File_Flag_Wildcards =01h ;? oder * enthalten
File_Flag_Is_LFN =02h ;s.u.
File_Flag_Has_Star =04h ;* enthalten
File_Flag_Has_Dot =08h ;. (nicht am Anfang) enthalten
; File_Flag_DotAtEnd =10h ;(Abgeschnittener) Punkt am Ende
File_Flag_NDevice =20h ;Regul„rer Dateiname
File_Flag_LowerCase =40h ;Kleinbuchstaben a-z enthalten
File_Flag_Char_High =80h ;codeseitenabh„ngige Zeichen
; File_Flag_DBCS_Char =80h
;Ist File_Flag_Is_LFN gesetzt, kann entweder ein langer Name vorliegen,
;oder der (vielleicht kurze) Name enth„lt die Zeichen ' .+,;=[]'
;Es bedeutet, dass der Name keinesfalls als FCB-Name zu finden ist.
;Beim Erstellen mit Schlangen-Zwang ist Schlange zu setzen.
;In Verbindung mit File_Flag_Has_Star bedeutet es, dass der Win32-
;Namensvergleich stattfinden muss (d.h. im Rckfallmodus muss nach
;der Suche nach *.* noch einmal getestet werden)
;
;Zus„tzlich zu File_Flag_Lowercase ist auch File_Flag_Char_High gesetzt,
;wenn Umlaute (also Zeichen >=80h) enthalten sind.
;Auch bei nur groáen Umlauten
;legt Win9x auch in diesem Fall LFN-Eintr„ge an,
;um Probleme mit Codeseiten zu umgehen
;Suche nach LFN-Dateinamen deshalb bei Is_LFN und/oder Char_High
;
;Ist weder File_Flag_Lowercase noch File_Flag_Is_LFN gesetzt,
;ist bei CREATE/MKDIR/MOVE keinerlei LFN-Eintrag zu erzeugen!
proc _noentry_Copy_FCB_Part
;BE: Kopiert LFN in FCB, FCB muss mit SPACE vorgefllt sein
;PE: SI=LFN-Zeiger
; BX=LFN-Ende (zeigt hinter Punkt), 0 fr Ende durch ASCII-Null
; DI=FCB-Zeiger
; DX=FCB-Ende-Zeiger+1
; AH=Flags (File_Flag_Has_Dot)
; DS,ES=CS
;PA: AH=weitere Flags (File_Flag_Wildcards u.„.) gesetzt
;VR: AX,CX,DX,SI,DI
@@lead: pop dx
dec dx ;potentielles Ende bei 7 oder 2 Bytes
cmp di,dx
je @@a ;kein Platz fr Trail-Byte!
inc dx
stosb
lodsb ;TrailByte
or ah,File_Flag_Char_High or File_Flag_LowerCase
jmp @@b
@@l2: push dx
mov dl,al
call IsDbcsLeadByte
jnc @@lead
call UpCase
or dl,dl ;>=80h
js @@is_lower
cmp al,dl ;ver„ndert?
jz @@was_upper
@@is_lower:
and dl,80h
or ah,dl ;Bit 7 setzen (lassen, sprungfrei)
or ah,File_Flag_LowerCase
@@was_upper:
pop dx
@@b: stosb
Copy_FCB_Part: ;Einsprung fr Erweiterung
@@l3: lodsb
cmp al,'?'
je @@qm
cmp al,'*' ;zu Fragezeichen machen?
je @@star
push di
mov di,ofs Invalid_Chars ;0,' .+,;=[]'
mov cx,9
repne scasb
pop di
jnz @@cp ;erlaubte SFN-Zeichen
or al,al
je _fcb_retu
cmp si,bx ;auf dem (letzten) Punkt?
je _fcb_retu
or ah,File_Flag_Is_LFN
cmp al,' ' ;Leerzeichen ist Durchl„ufer (kein Ersatz)
je @@l3
cmp al,'.' ;Punkt ist Durchl„ufer (kein Ersatz)
je @@l3
mov al,'_' ;'+,;=[]' durch '_' ersetzen
@@cp: cmp di,dx ;haben noch Zeichen und kein Platz?
jne @@l2 ;Noch ist Platz
@@a: or ah,File_Flag_Is_LFN
jmp @@l3 ;weiter nach '*' oder '?' fahnden
@@qm: ;falls Fragezeichen: Bit setzen und weiter
or ah,File_Flag_Wildcards
jmp @@cp
@@star: ;falls Stern: einige Extrawrste
or ah,(File_Flag_Wildcards or File_Flag_Has_Star)
test ah,File_Flag_Has_Dot
jnz @@q0
mov dx,ofs FCB_Name+11 ;alles mit Fragezeichen!
@@q0: mov al,'?'
db 0B1h ;mov cl,nn
@@q1: stosb
cmp di,dx
jne @@q1
jmp @@l3 ;zur Auswertung von File_Flag_Is_LFN
endp
proc Gen_Alias pascal
;Alias-Generierung, "ersetzt" Int21/AX=2900h
;Eine "Erweiterung" ist definiert als der String hinter dem letzten Punkt,
;welcher nicht in einer Kette am Anfang stehender Punkte ist, also
;".ab" oder "..exe" enthalten keine "Erweiterungen"
;
;TRUENAME muss schon dafr sorgen, dass:
;- nachlaufende Leerzeichen und Punkte entfernt sind
;- ein Punkt am Ende nur verbleibt, wenn ein '*' enthalten ist
;- Pfad-Trenner zusammengefasst zu '/' sind (fr DBCS)
;- keine ungltigen LFN-Zeichen enthalten sind
;- Wildcards vor Backslash als Fehler gelten
;
;Hier werden (noch) keine Schlangen zugesetzt, das macht Poke_Number...
;Beachtet erstes Zeichen im FCB (05h fr E5h) nicht!
;PE: SI=Pfad-Komponente
; DS,ES=CS
;PA: FCB gefllt
; Pfad-Komponente ggf. modifiziert, Null-terminiert
; SI=n„chste Pfad-Komponente oder auf ein Null-Byte
; AH=[File_Flags]=File_Flags
; [CurPathComp]=momentane Pfad-Komponente (=SI beim Aufruf)
; [PFlags]:PF_Slash zeigt gel”schten Slash an
;VR: AX,BX,CX,DX,SI
uses di
mov [CurPathComp],si
;FCB l”schen
mov di,ofs FCB_Name
mov cx,6 ;CH bleibt 0
mov ax,' '
rep stosw ;das Byte zuviel macht nichts
;Pfad-Komponente isolieren
BRES [PFlags],PF_Slash
push si
@@l: lodsb
or al,al
je @@e2
cmp al,'/'
jne @@l
BSET [PFlags],PF_Slash ;ein Fall fr File_Flags!
mov [by si-1],0
@@e2: pop si
xor bx,bx
;nicht-erste Punkte bergehen suchen
@@l1: lodsb
cmp al,'.' ;Punkt(e) am Anfang (".login" o.„.)
je @@l1 ;z„hlt nicht als Erweiterung
cmp al,' ' ;auch wenn gemischt mit Leerzeichen
je @@l1 ;(was fr grausige Dateinamen!)
; or al,al
; jz @@ende ;Notbremse, sollte hier nie vorkommen!
;letzten Punkt finden
@@l2: lodsb
or al,al
jz @@ende
cmp al,'.' ;Punkt entdeckt?
jne @@l2 ;Kein anderes Zeichen mit Sonderbehandlung
mov bx,si ;potenzieller Ext-Zeiger (hinter Punkt)
or ah,File_Flag_Has_Dot ;"normaler" Punkt
jmp @@l2
@@ende: dec si ;auf die Null!
;Name in FCB kopieren
push si
mov si,[CurPathComp]
mov di,ofs FCB_Name
mov dx,ofs FCB_Name+8
push dx
call Copy_FCB_Part ;Namensteil (8)
pop dx
test ah,File_Flag_Has_Dot
jz @@keine_ext
mov si,bx
mov di,dx
add dx,3
call Copy_FCB_Part ;Erweiterung (3)
@@keine_ext:
pop si
mov [File_Flags],ah
ret
endp
proc Poke_Number_Over_FCB pascal
;BE: in [FCB_Name] wird die Zahl SI "eingepflanzt"
; Es erfolgt kein Test auf SI=0
;PE: [FCB_Name]-Namensteil gefllt, ab erstem Leerzeichen oder derart,
; dass die Zahl rechtsbndig steht. (Bei DBCS ist bisweilen 1 Leerzeichen
; dahinter, also nur 7 Bytes insgesamt, erforderlich!)
; Erstes Byte muss hier noch E5h sein, nicht 05h!
; [FCB_Name] darf keine regul„ren Zwischen-Leerzeichen enthalten!
; DS,ES=CS
;PA: [FCB_Name]-Namensteil modifiziert unter DBCS-Beachtung
; BX=Zeiger auf Tilde (zum Wegpoken fr den n„chsten Versuch)
;VR: AX (AH=0),BX,CX=0,DX
uses DI
mov bx,10 ;Zahlenbasis
mov ax,si ;Zahl
mov cx,1 ;Ziffernz„hler, 1 fr '~'
@@l: xor dx,dx
inc cx ;Eine Ziffer
div bx
or ax,ax ;Null?
push dx ;Divisionsrest (0..9) in LIFO
jnz @@l ;n„chste Ziffer
mov al,9
sub ax,cx ;Verbleibende Bytes +1
mov di,ofs FCB_Name-2
@@n2: inc di
@@n1: inc di
mov dl,[di]
cmp dl,' ' ;In generierten SFN gibt es keine Leerzeichen
je @@ok
dec ax
jz @@ok
call IsDbcsLeadByte
jc @@n1
dec ax ;2 Bytes
jnz @@n2
@@ok: mov bx,di ;Rckpatch-Zeiger
push '~'-'0' ;...die geliebte Schlange voran...
@@more: pop ax ;LIFO -> Reste entstanden von hinten
add al,'0' ;mit der h”chstwertigen Ziffer anfangen
stosb
loop @@more
cmp di,ofs FCB_Name+7 ;ein Trail-Byte zu t”ten?
jne @@e
mov al,' '
stosb
@@e: ret
endp
proc Copy_Term_Spaces
;Hilfsroutine fr Copy_FCB_8P3
@@l: lodsb
Copy_Term_Spaces_1: ;Einsprung fr modifiziertes AL
stosb
cmp al,' '
je @@f
mov bx,di ;M”glicher Ende-Zeiger (vorrcken)
@@f: loop @@l
mov di,bx ;bei Trailing Spaces zurckstellen
ret
endp
proc Change_First_FCB_Byte
;FU: Hilfsprogramm fr Copy_FCB_8P3 und Is_FCB_Equal
;PE: AL=1. FCB-Byte
; CL=Ersatz fr E5 (L”sch-Kennung)
;PA: AL=Ge„ndertes Byte: E5->CL, 05->E5, sonst unver„ndert
;VR: AL,CL
cmp al,0E5h ;Gel”schter Eintrag?
je @@1 ;auf CL setzen (Vorgabe)
cmp al,05h ;Ersatzbyte fr E5?
mov cl,0E5h ;das ist das Byte (nicht Zeichen - DBCS!) E5
jne @@e
@@1: mov al,cl
@@e: ret
endp
proc Copy_FCB_8P3
;Kopiert FCB-Dateiname in 8.3-Form nach DI, auch fr FCB mit Leerzeichen!
;PE: BX=Zeiger auf Directory-Eintrag
; ES:DI=Ziel (bei BX<>FCB_Name E5h am Anfang in '?', 05h in E5h wandelnd)
; DS=CS (ben”tigt KEIN ES=DS wegen/fr ax=71A8h)
;PA: DI vorgerckt (auf die Null), String nullterminiert und ohne Backslash
;VR: AL,CX=0,SI,DI
mov si,bx
Copy_FCB_8P3_from_SI:
push bx
mov cx,'?'
cmp si,ofs FCB_Name
lodsb
je @@1 ;aus lokalem FCB-Puffer NICHT wandeln!
call Change_First_FCB_Byte
@@1: mov bx,di ;Ein Leerzeichen vor dem Punkt zulassend...
mov cl,8
call Copy_Term_Spaces_1
mov al,'.'
stosb ;Der Punkt l”scht sich wieder, wenn keine Ext
mov cl,3
call Copy_Term_Spaces
pop bx
@@e: mov [by es:di],0
ret
endp
proc Pick_Sector_From_DirEnt
;PE: BX=DirEnt-Zeiger (nur FAT!)
;PA: EAX=[CurSector]=[SuchSektor]=Sektor-Nummer
; CY=1 wenn ungltige Cluster-Nummer
;VR: EAX,CL
xor ax,ax
test [DriveType],DT_FAT32
jz @@1
mov ax,[(TDirEnt bx).ClusH]
and ah,0Fh ;Obere 4 Bits undefiniert = FAT28!
@@1: shl eax,16
mov ax,[(TDirEnt bx).ClusL]
;jmp Cluster2Sector
endp
proc Cluster2Sector
;PE: EAX=Cluster-Nummer
;PA: EAX=[CurSector]=[SuchSektor]=Sektor-Nummer
; CY=1 wenn ungltige Cluster-Nummer
;VR: EAX,CL
or eax,eax
jz _set_root_sector
mov cl,[DPB_Shift]
sub eax,2
shl eax,cl ;Cluster->Sektor
add eax,[DPB_UsrSec]
cmp [DPB_LastSec],eax ;šberlaufprfung!
jmp _set_cur_and_such
_set_root_sector:
mov eax,[DPB_DirSec]
_set_cur_and_such:
mov [SuchSektor],eax
mov [CurSector],eax
ret
endp
proc Cluster2FAT
;FU: L„dt zum Cluster EAX die FAT in den Puffer und stellt einen
; Zeiger zur Verfgung (bei FAT12 muss ggf. ein weiterer Sektor
; nachgelesen werden!)
;PE: EAX=Cluster-Nummer (2=erster Cluster)
;PA: EAX=Sektor-Nummer in 1. FAT
; BX=Adresse FAT-Eintrag
; CH Bit 0 = High-Nibble-Bit fr FAT12
;VR: EAX,BX,EDX
xchg edx,eax
mov ah,3 ;Nibbles pro FAT-Eintrag
mov al,[DriveType]
test al,DT_FAT16
jz @@1
mov ah,4
@@1: test al,DT_FAT32
jz @@2
mov ah,8
@@2: movzx eax,ah ;4 Bytes?
;nun in EAX Nibbles pro Cluster-Eintrag
mul edx ;EDX:EAX=Nibble-Nummer
mov bx,ax
and bx,03FFh ;%1024=Nibble-im-Sektor
shrd eax,edx,10 ;/1024=Sektor-Nummer
add eax,[DPB_FAT1Sec]
push eax bx cx
call ReadSecEAX
pop cx bx eax
jc @@e
mov ch,bl ;letztes Bit retten
shr bx,1 ;Nibble->Byte
add bx,ofs Sektor
@@e: ret
endp
proc Alloc_Cluster ;NOT TESTED - scheint aber zu funktionieren
;FU: Clusterkette verl„ngern, neues Cluster l”schen (mit Nullen fllen)
;PE: [SuchSektor]=1. Sektor des zu verl„ngernden Verzeichnisses
; [num_cluster]=Anzahl Cluster des zu verl„ngernden Verzeichnisses
;PA: [sektor] geladen mit erstem Sektor des neuen Clusters
; BX=Sektor-Zeiger
; CY=1 bei Fehler
; (Festplatte voll, volles Hauptverzeichnis [FAT16], DOS will nicht o.„.)
;VR: [Alloc_Cluster_SFN],[Alloc_Cluster_FCB],[sektor] zerst”rt
mov eax,[SuchSektor]
sub eax,[DPB_UsrSec]
jc @@e0 ;geht nicht im Hauptverzeichnis! (auáer FAT32)
;Cluster-Kette des momentanen Vrz. kreuzverketten und verl„ngern!
;Datei erzeugen und schlieáen
lea si,[ShortBuffer]
lea di,[Alloc_Cluster_SFN]
mov dx,di
mov cx,3 ;3 Bytes
rep movsb ;Laufwerksbuchstabe:\
mov si,di ;SI fr Datei->FCB
mov ax,5A00h
stosb ;nullterminieren
mov cl,6 ;system, hidden
call CallOld ;Tempor„re Datei erzeugen
jc @@e0 ;ging voll daneben!
xchg bx,ax ;Handle->BX
mov ah,3Eh
call CallOld ;Datei schlieáen
jc @@e0 ;hm!
call ResetDrv
;Datei aufsuchen
lea di,[Alloc_Cluster_FCB]
mov ax,2900h
call CallOld ;Dateiname formatieren ->ES:DI
mov eax,[DPB_DirSec]
call ReadSecEAX
mov bx,ofs Sektor
@@find_loop:
lea di,[Alloc_Cluster_FCB+1]
call Is_FCB_Equal_DI
jz @@found
call Next_DirEnt
jnc @@find_loop
@@e0: jmp @@e
@@found:
;BX=DirEnt, modifizieren
movzx eax,[num_cluster]
mov cl,[DPB_Shift]
shl eax,cl ;EAX=Sektoren Verzeichnis
shl eax,9 ;EAX=Bytes Verzeichnis
mov [(TDirEnt bx).fsize],eax
mov eax,[SuchSektor]
sub eax,[DPB_UsrSec]
shr eax,cl ;Cluster draus
add eax,2
mov [(TDirEnt bx).ClusL],ax
ror eax,16
mov [(TDirEnt bx).ClusH],ax ;Kreuzverbundene Cluster erzeugen
push bx
call WriteNow
mov si,0
jc @@unhook
;Datei ”ffnen, verl„ngern und schlieáen
mov ax,3D02h ;zum Schreiben ”ffnen
lea dx,[Alloc_Cluster_SFN]
call CallOld
jc @@unhook
xchg bx,ax ;Handle
xor cx,cx
xor dx,dx
mov ax,4202h ;ans Ende seeken
call CallOld
xor ax,ax
lea di,[Sektor]
mov dx,di
mov cx,100h
rep stosw ;Sektor l”schen
call InvalSector
mov di,1
mov cl,[DPB_Shift]
shl di,cl
mov cx,200h ;sektorweise
@@wr_loop:
mov ah,40h ;schreiben
call CallOld
jc @@do_close
cmp ax,cx
jc @@do_close
dec di
jnz @@wr_loop ;wenn CY=0 und Z=0 springen
@@do_close:
adc si,si ;CY retten
mov ah,3Eh
call CallOld
@@unhook:
adc si,si ;CY einschieben
pop bx
jnz @@err
push bx
;Datei hart l”schen (Cluster-Kette nicht freigeben)
call ReadSec
pop bx
mov [(TDirEnt bx).FName],0E5h ;einfach l”schen
call WriteNow
@@e: jnc @@exi
@@err: stc
mov [LastError],2 ;"couldn't expand directory"
@@exi: ret
endp
proc Calc_Next_Cluster pascal
;Berechnung fr Next_Sektor, liest die FAT ein
;PE: EAX=(vorhergehender) Sektor (gerechnet ab UsrSec)
; CL=Shift
;PA: EAX=n„chster Sektor (erster Sektor des n„chsten Clusters, ab UsrSec)
; CY=1: Ende der Cluster-Kette, EAX=Cluster-Nr.
;VR: alle, [Sektor]-Inhalt zerst”rt
shr eax,cl
add eax,2 ;EAX ist nun CLUSTER
call Cluster2FAT
jc @@e
mov eax,[bx]
mov dl,[DriveType]
test dl,DT_FAT32
jnz @@3
movzx eax,ax
test dl,DT_FAT16
jnz @@3a
;dicke Extrawurst fr FAT12: Nachlese 2.Sektor, falls bx am Ende
cmp bx,ofs SektorEnde-1
jnz @@4
pusha
call ReadNextSec
popa
jc @@e
mov ah,[Sektor] ;2. Byte vom Anfang nachlesen
@@4: test ch,1 ;Nibble-Bit gesetzt?
jz @@5
shr ax,4
@@5: and ax,0FFFh
cmp ax,0FF7h
jmp @@3b
@@3a:
cmp ax,0FFF7h
jmp @@3b
@@3: ;nun wieder Cluster in Sektor umrechnen
and eax,0FFFFFFFh ;die obersten 4 Bit sind reserviert!
cmp eax,0FFFFFF7h
;Also bietet FAT32 max. 256 Mega-Cluster, bei heute blichen LBA-Laufwerken
;mit 28-bit-Sektoradresse (also max. 128 GB) reicht das fr 512-Byte-Cluster
@@3b: cmc
jc @@e ;Ende der Clusterkette
cmp eax,2
jc @@e ;momentaner Cluster ist frei (falsch!)
sub eax,2
shl eax,cl
@@e: ret
endp
proc Next_Sektor pascal ;nur FAT
;liefert n„chsten Sektor der Clusterkette bzw. des Hauptverzeichnisses
;PE: [CurSector]=momentaner Sektor
;PA: [CurSector]=n„chster Sektor, bereits gelesen
; BX=Zeiger auf Sektor-Anfang
; [num_cluster] inkrementiert bei Cluster-Wechsel
;VR: alle
mov eax,[CurSector]
inc eax
cmp [DPB_LastSec],eax
jc @@e ;war User-Bereich: Ende!
sub eax,[DPB_UsrSec];Hauptverzeichnis-Ende?
cmc
jz @@e ;war Hauptverzeichnis: Ende! (mit CY=1)
jnc @@er ;war Hauptverzeichnis: es gibt weitere
mov cl,[DPB_Shift]
mov bx,1 ;Maske bauen (low-16bit reicht)
shl bx,cl
dec bx ;0->0, 1->1, 2->3, 4->7 usw.
test ax,bx
jnz @@er ;noch im gleichen Cluster: weiter!
dec eax
call Calc_Next_Cluster
jc @@e ;kein n„chstes Cluster: Ende!
inc [num_cluster]
@@er: add eax,[DPB_UsrSec]
call ReadSecEAX ;Sektor lesen
lea bx,[Sektor] ;Zeiger an Anfang stellen
@@e: ret
endp
proc Next_DirEnt
;PE: BX=DirEnt-Zeiger
;PA: BX=vorgerckter DirEnt-Zeiger, ggf. mit neu gelesenem Sektor
; CY=1: kein weiterer Sektor in Clusterkette
;VR: alle
call Check_CDFS
jnz CD_Next_DirEnt
add bx,32 ;GrӇe von DirEnt
cmp bx,ofs SektorEnde
cmc
jc Next_Sektor ;CY durchreichen
@@e: ret ;noch im gleichen Sektor: OK
endp
proc IsDbcsLeadByte
;Testet DL auf Fhrungsbyte von Zwei-Byte-Zeichens„tzen
;PE: DL=Zeichen oder Fhrungsbyte
;PA: CY=1: kein Fhrungsbyte
;VR: -
push ds si ax
lds si,[lead_byte_table]
@@l: lodsw
cmp ax,1
jc @@e
cmp dl,al
jc @@e ;hoffentlich aufsteigend sortiert!
cmp ah,dl
jc @@l
@@e: pop ax si ds
ret
endp
proc Upcase
;konvertiert AL in Groábuchstaben, auch fr >=80h
;fr Dateinamensvergleich bei LFN
;Darf nicht fr TrailBytes aufgerufen werden!
;Dass es mit LeadBytes geht, dafr sorgt DOS mit einer 1:1-Tabelle;
;DOSLFN vertraut dieser (komischen) Sache nicht, umgeht Upcase auch dann.
;PE: AL=Zeichen
;PA: AL=Zeichen oder Groábuchstabe
;VR: AL
cmp al,80h
jnc @@a80
cmp al,'a'
jb @@1
cmp al,'z'
ja @@1
bres al,bit 5
@@1: ret
@@a80: push ds bx
lds bx,[uppercase_table]
xlat
pop bx ds
ret
endp
proc Globbing
;FU: Dateinamen-Vergleich mit DOS-typischer Suchmaske
;PE: SI=MASKE (kann unter DOS auch Name sein)
; DI=NAME (beide Strings seien korrekte DBCS-Strings)
; DS,ES=CS
;PA: CY=0 bei Treffer
;VR: AX,DX (DL geht bei HandleDBCS drauf, DH ist "Punkte-Z„hler")
mov dh,0
@@r: push si di
@@l: lodsb ;MASKE
mov ah,[di] ;NAME
cmp ah,'.'
jne @@1a
inc dh ;NAME enth„lt Punkt
@@1a: cmp al,'.' ;MASKE-Punkt (mit Sonderbedeutung)?
jne @@nodot
cmp [by si],0 ;folgt Stringende?
je @@dotatend ;Bedeutung: NAME darf keinen Punkt haben
cmp [wo si],'*' ;folgt Stern und Stringende?
je @@dotstar ;Bedeutung: NAME ohne Punkt darf zu Ende sein
@@nodot:
or al,al
jz @@end
cmp al,'*'
jz @@star
@@2: inc di ;erst jetzt NAME-Zeiger vorrcken!
or ah,ah
jz @@f
cmp al,'?'
jz @@qm
mov dl,al
call IsDbcsLeadByte
jnc @@leadbyte ;gibt's nicht mit Upcase!
call UpCase
xchg ah,al
call UpCase
@@trail: cmp al,ah
jz @@l
@@f: stc
@@e: pop di si
ret
@@end: cmp al,ah ;Auch Null? CY=1 wenn ah<>0! (Stringenden
; fallen nicht zusammen!)
jmp @@e ;okay oder auch nicht!
@@dotatend:
or dh,dh
jnz @@f ;Fehler wenn Punkt enthalten!
jmp @@e0
@@dotstar:
or dh,dh
jnz @@2 ;weiter so, wenn Punkt enthalten
@@e0: cmp dh,ah ;NAME muss zu Ende sein fr CY=0
jmp @@e
@@qm: ;bei Fragezeichen: ganzes Zeichen(!) bergehen
mov dl,ah
call IsDbcsLeadByte
jc @@l
inc di ;Trailbyte ungesehen bergehen
jmp @@l
@@star: ;bei Stern
call @@r ;Rekursion!
jnc @@e ;wenn der Rest passt, dann ist's OK
mov dl,[di]
or dl,dl
jz @@f ;Wenn NAME zu Ende, dann Fehler
inc di
call IsDbcsLeadByte
jc @@star
inc di
jmp @@star ;mit n„chstem Zeichen(!) weitermachen
@@leadbyte:
cmp al,ah
jnz @@f
lodsb ;MASKE Trail, darf nichts ungltiges sein!
mov ah,[di] ;NAME Trail
inc di
jmp @@trail ;zum Vergleich der Bytes
endp
proc GlobbingEx
;FU: wie Globbing, testet jedoch auch noch bei Treffer, ob bei
; File_Flag_DotAtEnd der Name keine Erweiterung hat
; (Der Trick, im FCB das erste Zeichen der Erweiterung zu testen,
; klappt bei CDs nicht, oder man msste da erst nach FCB konvertieren)
;PE: SI=Name (umgekehrt als bei Globbing!!)
; [CurPathComp]=Maske (immer ohne '.' am Ende)
; [File_Flags]=Punkt-Merker "File_Flag_DotAtEnd"
; DS,ES=CS
;PA: Z=1 bei Treffer
; CY=0 (immer)
;VR: AX,DI(=Maske)
mov di,[CurPathComp]
xchg si,di
push dx
call Globbing
pop dx
xchg si,di
db 0D6h ;setalc
or al,al ;Umwandlung NC->Z
ret
endp
proc BE_Uni2Oem ;Big Endian Version
xchg ah,al
endp
proc Uni2Oem
;Konvertiert Unicode-Zeichen zu OEM-Zeichen anhand [UniXlat]
;PE: AX=Unicode-Zeichen
; DI=Speicherziel
;PA: AL=Oem-Zeichen oder zweites Byte bei DBCS (nur wenn IsDbcsLeadByte)
; (Da TrailByte>=40h interessiert es nicht bei der Sonderzeichenbeh.)
; AL='_' bei nicht konvertierbarem Zeichen sowie PF_Fail_Uni2Oem gesetzt
; DI=vorgercktes Speicherziel
; Z=1 wenn AL=0
;VR: AX,DI
cmp ax,80h
jc @@e
push cx di
mov di,[UniXlat]
or di,di
jz @@nc ;ohne Tabelle keine šbersetzung
mov cx,80h ;WIRD HIER GEPATCHT!
UniTableLen = wo $-2
push cx
repne scasw ;wenn gefunden bei Index=0, dann CX=7Fh
pop ax
jne @@NoConv
sub ax,cx ;aus Index 0 wird AX=1
add ax,7Fh ;nun Index 0 ist AX=80h
or ah,ah ;>=100h?
jz @@e1 ;1-Byte-Zeichen
dec ah ;-100h
div [by HIGH TrailMinLen] ;AH=TrailIndex, AL=LeadIndex
push dx
xor dx,dx
xchg dh,ah ;TrailIndex retten, AH nullsetzen
inc ax ;1-basiert
mov di,[UniXlat]
mov cx,80h ;wird NICHT gepatcht!
repne scasw ;MUSS gefunden werden! Sonst Fehler in .TBL
mov dl,0FFh ;AH ist 0
sub dl,cl ;Index 0 -> Leadbyte 80h
; call IsDbcsLeadByte ;Das sollte es sein!
xchg dx,ax ;AL=LeadByte, AH=TrailIndex
pop dx
; jc @@NoConv ;So geht es nicht!
pop di
stosb ;Lead-Byte schreiben
xchg ah,al
add al,[by LOW TrailMinLen]
jmp @@e2
@@nc:
or ah,ah ;>=100h?
jz @@e1 ;geht OK, ISO-Latin-1 annehmen
@@NoConv:
INT3 ;sollte sehr selten vorkommen!
mov al,'_' ;nicht konvertierbares Zeichen
BSET [PFlags],PF_Fail_Uni2Oem
@@e1: pop di
@@e2: pop cx
@@e: stosb
or al,al
ret
endp
proc Oem2Uni
;FU: konvertiert jede Art von OEM-Zeichen in Unicode anhand [UniXlat]
;PE: SI=Quellstring
;PA: AX=Unicode-Zeichen
; SI=vorgerckter Quellstring
;VR: EAX,SI
;BUG: Bei DBCS-Codeseite, aber OHNE LeadByteTable (die Situation beim Start
; einer chinesischen Win9x/Me-Bootdiskette ohne Aufruf von PDOS95.BAT)
; ist das Ergebnis von Oem2Uni dasselbe
xor eax,eax
lodsb
cmp al,80h
jc @@e
push ecx dx
movzx ecx,[UniXlat]
jcxz @@e1 ;ohne Tabelle keine šbersetzung: ISO-Latin-1
mov dx,ax ;Kopie zum Test, DH=0
mov ax,[ecx+2*eax-100h]
cmp ax,80h ;ein LeadByte-Index? (!Forderung fr SBCS!)
jnc @@e1 ;nein, OK
; call IsDbcsLeadByte ;DL extra prfen
xchg ax,dx ;LeadIndex nach DX, AH=0 {LeadByte nach AL}
; jc @@e1 ;nein, Chinesisch ist noch nicht aktiv!
lodsb ;Trail-Byte "ziehen", AH=0
sub al,[by LOW TrailMinLen]
;jc @@e1 ;fhrt zu falschem Chinesisch (GB vs. GBK)
xchg dx,ax ;LeadIndex nach AX, TrailByte nach DX
dec ax ;Index 0 (ungenutzt)?
js @@e1 ;Wird Unicode FFFF draus!
mul [by HIGH TrailMinLen] ;Index->Adresse des TrailByteVektors
add ax,dx ;TrailIndex dazu
mov ax,[ecx+2*eax+100h]
@@e1: pop dx ecx
@@e: ret
endp
;proc noentry_Copy_Uni_Oem
;FU: Hilfsprogramm, um aus LFN_DirEnt die zerstckelten Unicodes zu holen
;PE: SI=Unicode-Zeichenkette
; DI=Oem-Zeichenpuffer
; CX=Anzahl Zeichen +1
; DS,ES=CS
; AL<>0 fr "Arbeit", AL=0 fr "Kurzschluss"
;PA: SI,DI vorgerckt
; AL=0 wenn Ende erreicht
; PF_Fail_Uni2Oem gesetzt bei "falschen" Zeichen
;VR; AX,CL
;@@l: lodsw
; call Uni2Oem
;Copy_Uni_Oem:
; or al,al
; loopnz @@l
; ret
;endp
;proc Copy_Oem_Uni
;Kopiert CX OEM-Zeichen in Unicode-Puffer
;Zumindest WindowsNT erfordert FFFF-Eintr„ge nach einer terminierenden
;0000, deshalb arbeitet CH als Ende-Merker zum n„chsten Aufruf
;PE: SI=Oem-Zeichenkette
; DI=Unicode-Zeichenpuffer
; CX=Anzahl Zeichen (CH=FFh: CL=Anzahl FFFF-Zeichen)
; DS,ES=CS
;PA: SI,DI vorgerckt (SI bis max. hinter die Null)
;VR: AX,CX=0 (normal) oder CX=FFFF (Ende erreicht)
; xor ax,ax ;auch als Vorbereitung fr FFFF
; inc ch
; jz @@f ;war FF
; dec ch
;@@l: call Oem2Uni
; stosw
; or ax,ax
; loopnz @@l
; jne @@e
;@@f: dec ax ;=FFFF
; rep stosw
; dec cx ;Kennung fr weitere
;@@e: ret
;endp
proc calc_check
;FU: FCB-Prfsumme berechnen
;PE: SI=FCB-Zeiger
;PA: AH=Prfsumme
;VR: AX,CX=0
mov cx,11
mov ah,ch ;mit 0 vorbesetzen
@@l2: ror ah,1
lodsb
add ah,al
loop @@l2
ret
endp
proc Locate_DirEnt
;FU: von BX aus gltigen Nicht-LFN-DirEnt aufsuchen, dabei longname auffllen
; Gel”schte DirEnts werden einfach bergangen (hier noch kein Unerase)
;PE: BX=Zeiger in Sektorpuffer auf ein DirEnt oder LfnDirEnt
; DS,ES=CS
;PA: BX=Zeiger auf DirEnt,
; CY=1 wenn Ende
; DL=1: LFN gltig,
; DL=FF: LFN nur wegen Checksumme falsch (aber trotzdem ungltig!)
; [longname] gefllt mit langem Dateinamen, Leerstring wenn DL<>1
; [shortname] gefllt mit 8.3-Namen
; [longpos_s] Position Startsektor LFN
; [longpos_a] Zeiger BX in Sektor-Puffer
; [PFlags]&PF_Fail_Uni2Oem gel”scht oder gesetzt
;VR: alle
;in der Schleife: DL=Sequenz-Nummer, DH=Prfsumme
mov dl,0
@@l: mov al,[(TLfnDirEnt bx).count]
cmp al,1
jc @@e ;Ende!
cmp al,0E5h
je @@3a ;n„chste Runde, LFN-in-Aufbau l”schen
cmp [(TLfnDirEnt bx).attr],0Fh ;LFN-Kennung?
jne @@exk ;BX ist OK, zeigt auf normalen DirEnt
test al,40h ;"Letztes" Stckel LFN?
jz @@2
mov dl,al
and dl,3Fh ;Sequenz-Nummer
jz @@3 ;ungltig, 0
cmp dl,20
ja @@3 ;ungltig, >20
mov eax,[CurSector]
mov [longpos_s],eax ;(m”gliche) Adresse sichern fr's L”schen
mov [longpos_a],bx
mov dh,[(TLfnDirEnt bx).check] ;Prfsumme
@@2a:
mov al,13*2
mul dl ;Adresse ermitteln
lea di,[longname-13*2]
add di,ax ;AL<>0 fr Copy_Uni_Oem!
lea si,[(TLfnDirEnt bx).name1]
push di
mov cx,5
rep movsw
add si,3
mov cl,6
rep movsw
lodsw ;add si,2
movsw
movsw
pop di
xor ax,ax
mov cl,13
repne scasw ;Unicode-Null suchen
jz @@t ;wenn Namensteil <13 Zeichen
test [(TLfnDirEnt bx).count],40h ;"Letztes" Stck?
jz @@3 ;nein
xor ax,ax
stosw ;terminieren!
jmp @@3
@@t:
test [(TLfnDirEnt bx).count],40h ;Muss auch "letztes" Stck sein!
jz @@3a ;Ungltig, DirEnt verwerfen
jmp @@3 ;Terminierung nicht (mehr) erforderlich
@@2:
cmp dl,2 ;Sequenz noch Null oder bereits 1?
jc @@3a ;ungltiger LFN
dec dl
and al,3Fh
cmp dl,al
jne @@3a ;Reihenfolge falsch
cmp dh,[(TLfnDirEnt bx).check] ;Prfsumme gleich?
je @@2a ;Prfsumme gleich
@@3a:
mov dl,0
@@3:
push dx
call Next_DirEnt
pop dx
jnc @@l
@@e: ret
@@exk: ;BX zeigt auf kurzen Dateinamen, šberprfung von Checksum
mov di,ofs longname
cmp dl,1
jnz @@nolong
; test [ctrl],CTRL_ChkLnk
; jz @@e2 ;Verbindung NICHT prfen
mov si,bx
call calc_check ;SI->AL
cmp ah,dh
jz @@e2
mov dl,0FFh
@@nolong:
mov [wo di],0 ;auch: Eintrag l”schen
@@e2: BRES [PFlags],PF_Fail_Uni2Oem ;Fr den Fall: kein LFN
mov si,di
@@l2: lodsw
call Uni2Oem ;Es wird bestenfalls krzer!
jnz @@l2
mov di,ofs shortname
call Copy_FCB_8P3
clc
ret
endp
proc noentry_StrIComp ;StringCompare mit UpCase
;PE: SI=Maske
; DI=Name
; CLD
;PA: CY=1: String DI grӇer als String SI
; Z=0: Strings ungleich
; Z=1: Strings gleich, AX=0
; SI und DI zeigen hinter das erste ungleiche Zeichen
; oder hinter die Null(en)
;VR: SI,DI,AX,Flags
@@2:
or ax,ax
jz @@e ;Beide Strings zu Ende
StrIComp:
lodsb
call UpCase
xchg ah,al
mov al,[di]
inc di
call UpCase
cmp ah,al
jz @@2
@@e:
ret
endp
proc Match_Attr
;Prft ob Attribut mit [SearchAttr] passt
;PE: AL=Attribut
;PA: Z=1: passt
; CY=0 (immer)
;VR: AL
test al,[by LOW SearchAttr]
jnz @@e ;paát leider nicht
Match_MM_Attr: ;Einstieg: Nur Must-Match-Attribut testen
not al
test al,[by HIGH SearchAttr]
@@e: ret
endp
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;++ Neue, "objektorientierte" FindFirst/FindNext-Routine ++
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;Match&Stop-Routinen mit folgenden Parametern:
;PE: BX=DirEnt-Zeiger fr aktuelles DirEnt
; [CurSector]=Aktuelle Sektornummer
; DX=User-Daten (frei verwendbar)
;PA: CY=1: Such-Ende einleiten (AX=Fehlercode 9912h)
; Z=1: Treffer
; DX=User-Daten (beim n„chsten Aufruf wieder aktuell)
;VR: AX,CX,DX,SI,DI (BX darf auáer bei CY=1 NICHT ver„ndert werden!)
proc Match_CD_LFN_Proc
mov ax,ofs CD_LongName
jmp Match_CD_AX_Proc
endp
proc Match_CD_SFN_Proc
mov ax,ofs CD_Shortname
Match_CD_AX_Proc:
cmp [(TCD_DirEnt bx).r],SIZE TCD_DirEnt
jc @@e
call CD_CheckRootDot
jnc @@e ;mit Z=0
call ax
Match_Current:
mov di,[CurPathComp]
call StrIComp
clc ;nie Fehler:-)
@@e: ret
endp
proc Check_Virtual_Remove
;PE: [CurSector]:BX=Verzeichniseintrag
;PA: Z=1 wenn Eintrag virtuell gel”scht
;VR: AX,SI,DI
cmp [FuncNum],56h
jne @@e
mov di,[SearchAttr]
cmp di,1
jc @@e ;mit NZ
add di,6
mov si,ofs CurSector
cmpsd
jne @@e
mov ax,bx
scasw
@@e: ret
endp
proc Match_LFN_Proc
;FU: Sucht fr FAT lange UND kurze Namen
;PE: BX=Anfang irgend eines Verzeichniseintrags (LFN, SFN, gel”scht)
; [CurPathComp]=Zu vergleichende Pfad-Komponente
; [xxx]=(bei MOVE) zu ignorierender Verzeichnis-Eintrag
;PA: CY=1: Fehler: BX ist kein Verzeichniseintrag
; BX=Anfang eines SFN-Verzeichniseintrags
; weitere Ergebnisparameter wie bei Locate_DirEnt
; Z=1: Name passt
; Z=0: Verzeichniseintrag ist Label oder passt nicht
call Locate_DirEnt
jc @@e ;raus bei Fehler
;Bugfix 11/02: Volume Labels nicht verfolgen!
test [(TDirEnt bx).attr],8
jnz @@e ;raus bei Label
;Fix 12/02: Zu l”schender Eintrag bei lfn_move bergehen
call Check_Virtual_Remove
jnz @@1
or ax,ax ;nie Null, daher Z=0
@@e: ret
@@1:
; cmp dl,1 ;LFN vorgefunden?
; jne @@cmpshort ;unn”tig weil longname[0]=0 ohne LFN
mov si,ofs Longname
call Match_Current
jz @@e ;Treffer!
@@cmpshort:
mov si,ofs ShortName
jmp Match_Current
endp
proc Glob_LFN_Proc
;Globbing fr FAT lange UND kurze Namen (hier gleich Win95-Verhalten)
call Locate_DirEnt
jc @@e ;raus bei Fehler
mov al,[(TDirEnt bx).attr]
call Match_Attr
jnz @@e ;raus, kein Treffer! (CY=0)
cmp dl,1
jne @@cmpshort
mov si,ofs LongName
call GlobbingEx ;LFN-Suche
jz @@e ;Treffer, raus!
@@cmpshort:
mov si,ofs ShortName
call GlobbingEx ;SFN-Suche mit LFN-Syntax
@@e: ret
endp
proc DirScan pascal
;Allgemeine Routine zum "Scannen" eines Verzeichnisses
;dank Pointer zur Match&Stop-Routine
;PE: [CurSector]=Startsektor des Verzeichnisses
; BX=MatchProc-Zeiger (bei NextDirScan muss dieser in [MatchPtr] stehen!)
;PA: CY=1: Nicht gefunden
;VR: AX,BX,CX,DX,SI,DI
mov [MatchPtr],bx
call ReadSec
jc @@e
mov bx,ofs Sektor ;der DirEnt-Zeiger
@@l: call [MatchPtr]
jbe @@e ;bei CY=1 (Fehler) oder Z=1 (gefunden)
NextDirScan:
call Next_DirEnt
jnc @@l
@@e: ret
endp
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
proc Is_FCB_Equal
;FU: Testet momentanen DirEnt mit Gleichheit zu FCB_Name
;PE: BX=DirEnt-Zeiger (mit 1. Byte =05 fr E5)
; [FCB_Name] mit Vergleichsstring gefllt
;PA: Z=1 wenn gleich
;VR: AL,DI,CX (CH=0)
lea di,[FCB_Name]
Is_FCB_Equal_DI:
mov si,bx
xor cx,cx
lodsb ;aus Festplatten-Sektor entnehmen
call Change_First_FCB_Byte
scasb
jne @@e
mov cl,5 ;CH ist schon null
repe cmpsw ;Die restlichen 10 Bytes brauchen kein Extra
@@e: ret
endp
;**** Hilfsprogramme fr TRUENAME ****
proc IsEnd ;Testet AL auf Ende von Pfad-Komponente
or al,al
jz @@e
IsBS: cmp al,'\'
jz @@e
cmp al,'/'
@@e: ret
endp
proc IsInvalidLfnChar
push di cx
mov di,ofs Invalid_Lfn_Chars
mov cx,8
repne scasb
pop cx di
ret
endp
proc HandleDBCS
;PE: AL=Zeichen, AH Bit 7 = Trailbyte-Flag
;PA: CY=1 wenn Trailbyte
; NO RETURN mit AX=2 wenn falsches Trailbyte <40h (Notbremse)
;VR: DL(=AL), AH Bit 7
shl ah,1
mov dl,al
jc @@1
call IsDbcsLeadByte ;NC wenn's so ist!
cmc
rcr ah,1 ;Hinein das Bit! CY=0
ret ;NC wenn kein Trail-Byte
@@1: cmp al,40h
jc SetErr2 ;Ungltiges Trail-Byte (Parsen nicht m”glich)!
;Ist 3, wenn \/ folgt? (hmpf)
shr ah,1 ;0 einschieben
stc
ret
endp
proc noentry_SwapSlashes
;FU: String parsen und DBCS-sicher \ zu / machen, 05h zurck zu E5h machen
;PE: DS:SI=Zeiger auf String
; DH=0: bei Leerstring Ergebnis-SI auf letztes Zeichen, sonst auf '\0'
; DH=1: Ergebnis-SI stets auf '\0'
;PA: SI vorgerckt entsprechend DH
; Zeichen im Puffer entsprechend ge„ndert
; NO RETURN bei falschem Trail-Byte
;VR: SI,DX,AX (AH Bit 7 =0, andere Bits unver„ndert)
@@pal: call HandleDBCS
jc @@paf ;bei Trailbyte nicht auf \ testen!
inc dh ;1 Zeichen mitz„hlen
cmp al,'\'
jne @@paf
mov [by si-1],'/' ;auf Unix drehen, damit es kein Trail-Byte ist
SwapSlashes:
cmp [by si],05h
jne @@paf
mov [by si],0E5h ;Unsinn von DOS' TRUENAME rckg„ngig machen
@@paf: lodsb
or al,al
jnz @@pal
sub dh,1 ;CY setzen lassen, wenn Wurzelverzeichnis
sbb si,1 ;auf die Null oder auf letzten /
ret
endp
proc GetSubstRoot
;Ermittelt Startverzeichnis fr geSUBSTetes Laufwerk oder schlicht X:\
;PE: FS:SI=Dateiname
; DS=ES:DI=Puffer
;PA: Puffer gefllt
; [subst_drive]=DL=virtuelles Laufwerk, DH=0
; BX=DI=Zeiger auf letzten '\' oder #0 im Puffer
; SI um 2 vorgerckt, wenn Laufwerk angegeben
; AX=Pfadquelle, Puffer+3 (normalerweise), grӇer bei UNC-Pfad
; NO RETURN bei Fehler
; [PFlags]???
;VR: EAX,BX,CX,DX,SI,DI
;N: DOS' TRUENAME liefert bei IFS-Laufwerken (CDROM, Netzwerk) einen
; Netzwerkpfad. Da IFS-Laufwerke nicht SUBST-bar sind, wird in diesem Fall
; einfach 'Laufwerksbuchstabe:\' zurckgegeben
; Der Pfad C:\DEV\NUL wird zu C:/NUL (mit Forward-Slash!) aufgel”st.
push di
mov ax,[fs:si]
or al,al
jz SetErr3 ;G„nzlich leer ist ein FEHLER!
cmp ah,':' ;Laufwerk gegeben?
je @@take_drive
mov ah,19h ;aktuelles Laufwerk beschaffen
call CallOld
add al,'A'
jmp @@2
@@take_drive:
segfs movsw ;Laufwerk bertragen, SI+=2, DI+=2
call upcase
@@2: movzx dx,al ;DH=0
mov ax,[fs:si]
call IsBS
jnz @@normal
mov al,ah
call IsBS
jnz @@normal
mov dl,0 ;Kennung UNC-Laufwerk!
pop di
stc
jmp @@e
@@normal:
mov ax,'\' ;TRUENAME kein Backslash anh„ngen lassen
stosw
pop di
push si
mov si,di ;Darf lt. RBIL auch bereinander liegen
mov ah,60h
call CallOldAndThrow ;So funktioniert's auch geSUBSTet
mov ax,'\\' ;Netzwerkpfad? (Kann auch MSCDEX sein!)
scasw
jne @@3
mov eax,'\:?' ;'?' wird ersetzt
mov al,dl
mov [si],eax
call strlenp1 ;Ende von "\\S.\A." suchen
dec di
@@3: inc di
push di dx
mov dh,-3 ;Kode in SwapSlashes arbeiten lassen!
call SwapSlashes ;Terminierende Null oder Backslash suchen
pop dx ax
mov di,si
pop si
@@e: mov bx,di
mov [subst_drive],dl
ret
endp
proc Truename
;DE: Kopiert DOS-Dateinamen in <longbuffer> und macht dabei ein TRUENAME:
; * Prft auf ungltige LFN-Zeichen ab
; * holt KEINE Laufwerksdaten
; * ermittelt ggf. das aktuelle Verzeichnis
; * l”st ..-Referenzen auf
; * schneidet nachlaufende Leerzeichen von Komponenten ab
; * schneidet nachlaufende Punkte ab, auáer bei "*" in Komponente
; * * und ? sind ungltige Zeichen vor \
; * " \" wirkt wie "."
; * wandelt alle '\' in '/' (wegen DBCS)
; * fasst mehrere '\' '/' zusammen zu einem
; * wandelt E5h NICHT zu 05h, wie das DOS' TRUENAME (AH=60h) tut! (brrr)
;BUG: interpretiert Netzwerkpfad "\\maschine\freigabe\pfadname" nicht
; Der Pfad C:\DEV\NUL wird ohne PF_Lfn_Input zu C:/NUL aufgel”st (OK),
; nicht aber bei gesetztem PF_Lfn_Input.
;
;PE: FS:SI=Dateiname, CLD
; [PFlags]:PF_LFN_Input=Schalter, ob Dateiname "lang" oder "kurz"
;PA: <longbuffer> gefllt mit TRUENAME entspr. Int21/7160/CX=0
; NO RETURN bei Fehler
; [subst_root]=Anzahl zu bergehender Zeichen fr SUBST
; [subst_drive]=virtuelles Laufwerk, =LongBuffer[0] wenn kein SUBST
;VR: EAX,BX,CX,DX,SI,DI (=alle)
mov di,ofs longbuffer
BTST [PFlags],PF_LFN_Input
jnz @@lfn_truename
push si di
call GetSubstRoot
pop di si
@@unc: push ax ds
LD ds,fs
mov ah,60h
call CallOld ;DOS noch einmal werkeln lassen (kein THROW)
pop ds si
jc Throw
cmp [by di],'\' ;Netzwerkpfad oder CDROM? (Kein Laufwerk?)
jne @@sfn1
mov al,dl ;nicht SUBSTbar, Laufwerk bernehmen
or al,al
jz @@sfn1 ;Netzwerkpfad, nicht behandeln!
push di
mov al,dl
stosb
mov ax,'\:'
stosw
call strcpy ;UNC-Netzwerkpfad killen - Rest vorkopieren
pop di
@@sfn1: mov si,di
call SwapSlashes
jmp @@ee
@@lfn_truename:
call GetSubstRoot ;liefert DH=0
jc @@unc
@@l0: inc dh
segfs lodsb ;DBCS-sicher: Fhrungs-Backslashes weg!
call IsBS
jz @@l0 ;kein aktuelles Verzeichnis holen!
dec si ;also auf ersten Nicht-Backslash
dec dh
jnz @@0
mov al,'/'
stosb
xchg si,di
sub dl,'@' ;fr GetCurDir: 'A:'=1 usw.
mov ah,47h
call CallOldAndThrow ;Aktuelles Vrz. nach <longbuffer>
call SwapSlashes ;SI ans Ende rcken, dabei \ zu / machen
xchg di,si
@@0: movzx ax,[by fs:si]
;AH Bit 0 = ?*-Speicher (File_Flag_Wildcards) - um falschen Pfad auszuwerfen
; Bit 2 = *-Speicher (File_Flag_Has_Star) - um Punkt rechts stehen zu lassen
; Bit 3 = .-Speicher (File_Flag_Has_Dot) - um Leer-Pfade ("/ /") zu killen
; Bit 7 = LeadByte-Speicher - um 5Ch ('\') als TrailByte durchzulassen
@@new0: or al,al ;Folgen Zeichen? (Mit Sicherheit kein \/)
jnz @@new_name ;nein, so stehen lassen
cmp di,ofs longbuffer+2 ;Root-Backslash?
jne @@e
inc di ;stehen lassen!
@@e: stosb
;und als letztes alles vor dem letzten Backslash upcasen (eigentlich)
@@ee: xchg ax,bx
sub ax,ofs longbuffer+2
mov [subst_root],ax
ret
@@scandot:
;Name, der mit '.' anf„ngt, k”nnte nur aus Punkten bestehen, und ist
;dann aktuelles, bergeordnetes usw. Verzeichnis!
mov cx,0 ;Punkte-Z„hler
push si ;Startzeiger retten
@@scn: inc cx
segfs lodsb
cmp al,'.'
je @@scn
call IsEnd
jz @@rmb
mov al,'.'
pop si
jmp @@setd ;ist ein "normaler" Name, von vorn
;Ende einer Punktkette erreicht, in CX=Anzahl Punkte
@@rmb: pop dx ;Zeiger verwerfen
@@rl: dec di ;CX Ebenen aufsteigen, AL enth„lt '\' oder 0
cmp [by di],'/' ;DBCS-sicher
jne @@rl
cmp di,bx ;Der SUBST-Pfadanteil ist "heilig"!
loopnz @@rl
jcxz @@new0 ;wenn CX<>0 dann ging es nicht "hoch genug"
jmp SetErr3
@@new_name:
BTST ah,File_Flag_Wildcards
jnz @@err2 ;Vor / sind keine ?* erlaubt!
mov al,'/' ;ja, jetzt Pfad-Trenner setzen
stosb ;šberlauf-šberwachung unn”tig, Reserve am Puffer-Ende
@@l1: segfs lodsb
call IsBS
jz @@l1 ;mehrfache Slash/Backslash zusammenfassen
and ax,0FFh ;AH: wenigstens das Has_Dot l”schen
jz @@e
cmp al,'.'
jz @@scandot
jmp @@be
;Klappt nicht mit Unterprogramm wegen neuer Globbing-Routine
@@l3a: cmp al,'?' ;Prfbits in AH setzen
jne @@3b
BSET ah,File_Flag_Wildcards
@@3b: cmp al,'.'
jne @@3a
@@setd: BSET ah,File_Flag_Has_Dot
@@3a: cmp al,'*'
jne @@l3
dec si
@@3al: inc si
cmp [fs:si],al ;Mehrere Sterne zusammenfassen
je @@3al
BSET ah,File_Flag_Has_Star or File_Flag_Wildcards
@@l3: ;normaler Name
cmp di,ofs longbuffer_end-1
@@err2: jnc SetErr2
stosb
segfs lodsb
@@be: call HandleDBCS
jc @@l3 ;bei Trail-Byte unver„ndert speichern
call IsInvalidLfnChar
jnz @@l3a ;erlaubt, kopieren
call IsEnd
clc
jnz @@err2 ;unerlaubtes Zeichen = "Datei nicht gefunden"
mov dh,al ;Pfad-Trenner oder Ende nach DH retten
@@l2: ;Ende erreicht, rckw„rts Punkte und Leerzeichen l”schen
dec di
mov al,[di]
cmp al,' '
je @@l2 ;Leerzeichen sofort weg!
cmp al,'/'
je @@sla ;nur Leerzeichen: noch kein Fehler!
cmp al,'.'
jne @@t2e ;Nicht l”schen, wenn * enthalten, zusammenfas.
BTST ah,File_Flag_Has_Star ;Stern enthalten?
jz @@l2 ;nein, der Punkt muss weg
cmp [di-1],al ;Punkt davor?
je @@l2 ;dann muss der Punkt doch noch weg
@@t2e: inc di
@@t2f: mov al,dh
jmp @@new0
@@sla: BTST ah,File_Flag_Has_Dot ;Irgendwo ein Punkt gewesen?
jz @@t2f ;der Slash bleibt! (Nicht auf @@t2e gehen.)
jmp SetErr5 ;Das ist ein ganz besonderer Fall!
;An dieser Stelle hat Win95a noch richtige Bugs!
;Die zu emulieren habe ich keine Lust.
endp
proc start_stuff
;das langweilige TRUENAME und Laufwerksparameter beschaffen...
;PE: FS:SI=Dateiname
; [PFlags]:PF_LFN_Input=Schalter, ob Dateiname "lang" oder "kurz"
;PA: NO RETURN bei Fehler
; CY=0 && Z=1: OK, Wurzelverzeichnis
; CY=0 && Z=0: OK, Unterverzeichnis, TRUENAME steht in longbuffer
; SI=longbuffer+3
; DI=shortbuffer+3 (Laufwerk:\ schon hineinkopiert)
; [CurSector] gefllt mit Startsektor des Hauptverzeichnisses
call Truename ;THROWt bei Fehler
mov al,[longbuffer]
sub al,40h
call GetDrvParams ;egal was dabei rauskommt!
mov si,ofs longbuffer
mov di,ofs shortbuffer
movsd ;Laufwerk:\NULL
dec si ;bleiben im Ziel stehen
dec di
Set_Root:
;"Current"-Sektor(en) auf "Hauptverzeichnis" setzen, fr MakeLongName
;call reset_cache_ptr
mov [fastopen_ptr],ofs fastopen_buf
BSET [PFlags],PF_Follow ;immer mit Verfolgung ansetzen
call _set_root_sector
call Check_CDFS
jz @@nocd
push si di
lea si,[Medium.jol.joltree.rootdir]
lea di,[Search.jol.j.sect]
movsd ;Startsektor
movsw ;L„nge
lea si,[Medium.jol.isotree.rootdir]
lea di,[Search.jol.i.sect]
movsd ;Startsektor
movsw ;L„nge
pop di si
@@nocd: cmp [by si],0 ;CY immer 0, Z setzen
@@e: ret
endp
proc same_stuff
;fr file_locate und path_locate
;Funktioniert auch im Rckfallmodus; da wird einfach der Dateiname in FCB_Name
;nach ShortBuffer (DI) kopiert, d.h. da wird ein echter 8.3-Name draus
;PE: PF_Follow=0: Cache umgehen und Sektor nicht "verfolgen"
; (fhrt zum Setzen von [Longpos_s]:[Longpos_a])
;PA: CY=1 wenn nicht gefunden, AL=2 oder 3 je nach Funktionsklasse
; DI=Short-Buffer-Zeiger vorgerckt (nur wenn nicht NIL gewesen)
push si di
cmp [DriveType],1
jc @@fallback
test [PFlags],PF_Follow
jz @@nocache ;ohne Follow nie in Cache gehen!
call find_in_cache
jz @@shortcut
@@nocache:
test [File_Flags],File_Flag_NDevice
jz @@fallback ;dirty hack 11/01
call Check_CDFS
jnz @@cdfs
mov bx,ofs Match_LFN_Proc
call DirScan
jc @@e
test [PFlags],PF_Follow
jz @@shortcut
call Pick_Sector_From_DirEnt
jmp @@catshort
@@e: pop di si
mov al,[FuncNum]
cmp al,3Ch ;LFN-Funktion mit Verzeichnissen?
mov al,3
jc @@e1
mov al,2 ;"file not found"
BT [wo PFlags],1 ;PF_Follow
adc al,0 ;modify to "path not found"
stc
@@e1: ret
@@fallback:
mov si,ofs FCB_Name
mov di,ofs ShortName
call Copy_FCB_8P3_from_SI
mov [LongName],0 ;nie langen Namen liefern
jmp @@shortcut
@@cdfs:
test [File_Flags],(File_Flag_Is_LFN or File_Flag_Char_High)
jz @@test_short
mov bx,ofs Match_CD_LFN_Proc
call CD_Ping_DirScan
jnc @@catshort ;gefunden!
@@test_short:
mov bx,ofs Match_CD_SFN_Proc
call CD_Pong_DirScan
jc @@e ;Konsistenzfehler
@@catshort:
call put_to_cache
@@shortcut:
pop di
or di,di
jz @@skip_copy ;bei Ziel=NIL nicht kopieren!
mov si,ofs ShortName
call strcpy ;gewonnenen Namen nach DI (ShortBuffer)
dec di
@@skip_copy:
pop si
ret
endp
proc file_locate
;verfolgt angegebenen Pfad bis zum Schluss
;Wird ziemlich selten gebraucht, weil diese Funktion nicht zur Manipulation
;des DirEnts zu gebrauchen ist! (lfn_chdir, lfn_attr, lfn_shortname)
;PE: FS:SI=Dateiname
; [PFlags]:PF_LFN_Input=Schalter, ob Dateiname "lang" oder "kurz"
;PA: NO RETURN bei Fehler (THROW zu "Pfad nicht gefunden")
; [ShortBuffer] gefllt mit 8.3-Pfad
;A: [Longpos_s]:[Longpos_a] sind nicht immer gesetzt!
call start_stuff
jz @@e ;ist root (und OK)
@@l: call Gen_Alias
call same_stuff
jc SetError
call MakeBSlash
jnz @@l
or al,al ;Z=0
@@e: ret
endp
proc path_locate
;verfolgt angegebenen Pfad, aber nicht den Dateinamen
;PE: FS:SI=Dateiname
; [PFlags]:PF_LFN_Input=Schalter, ob Dateiname "lang" oder "kurz"
;PA: NO RETURN bei Fehler (z.B. Pfad nicht gefunden)
; [ShortBuffer] gefllt mit 8.3-Pfad und abschlieáendem Backslash
; [CurPathComp]=Zeiger auf Dateiname
;BUG: Check_Device ist Sache von TRUENAME!
call start_stuff
jz @@root ;nur root ist hier auch Fehler!
@@l: call Gen_Alias
BTST [PFlags],PF_Slash
jz @@ckdev ;fertig gefunden, in [CurPathComp]...
call same_stuff
jc SetError
call MakeBSlash
jmp @@l
@@ckdev:
call Check_Device
@@e: ret
@@root: cmp [FuncNum],4Eh
;"Keine weiteren Dateien" meldet DOS bei FindFirst auf "c:\"
mov al,05h ;ansonsten "Zugriff verweigert"
jne @@ex
mov al,12h
@@ex: jmp SetError
endp
proc MakeBSlash
;FU: Backslash und \0 an ES:DI anh„ngen, wenn [PFlags]:PF_Slash
; gesetzt ist
;PE: DI=Zielpuffer
; [PFlags]:PF_Slash
; SI=Quellpuffer (um auf 0 zu testen)
;PA: SI und DI inkrementiert falls Flag gesetzt
; AX=005Ch
;VR: AX, DI
mov ax,'\' ;Backslash und Null
BTST [PFlags],PF_Slash
jz @@1
stosw
dec di
inc si
@@1: cmp [si],ah ;Null? (CY=0)
ret
endp
proc dirent_locate
;ermittelt DirEnt-Zeiger bx fr Datei
;PA: NO RETURN bei Fehler mit "path_locate"
; CY=1 wenn Datei nicht gefunden (AL=2) oder AL=3 bei Verzeichnis-Fkt.
; [ShortBuffer] gefllt mit 8.3-Pfad und abschlieáendem Backslash (?)
; BX=DirEnt-Zeiger
; [longpos_s]+[longpos_a]=LFN-DirEnt-Zeiger (auch bei CY=1 ver„ndert!)
;N: Ein nachlaufender Backslash wird hier nicht angesetzt!
call path_locate
File_DirEnt_Locate:
BTST [File_Flags],File_Flag_Wildcards
jnz SetErr3 ;an dieser Stelle nicht erlaubt
BRES [PFlags],PF_Follow
push di
call same_stuff ;jetzt ohne Cache!
jc @@e
call MakeBSlash
cmp [DriveType],0 ;FallBack-Modus?
jne @@e
BTST [File_Flags],File_Flag_Is_LFN
jnz SetErr5 ;im Fallback-Modus unzul„ssig!
BRES [File_Flags],File_Flag_LowerCase ;kein LFN erzeugen!
mov ax,4300h
call SFN_CallOld ;Existenz-Test
jnc @@e
pop di ;Zeiger stehen lassen!
ret
@@e: pop cx
ret
endp
proc MakeLongName
;Erzeugt "langen" Dateinamen, nur fr lfn_pwd und lfn_longname
;PE: SI=Zeiger auf kurzen Dateinamen (LW-Parameter schon geladen)
; FS:DI=Ziel (langer Dateiname im Anwender-Adressraum)
; [subst_root]=Zeichenzahl fr SUBST
;PA: CY=1: da ging was schief!
;VR: alle, [subst_root]
cmp [by si],0 ;Sonderfall fr lfn_pwd und lfn_longname
jz @@ez ;nichts zu tun im Wurzelverzeichnis!
add [subst_root],si
call Set_Root
@@l: call Gen_Alias
push di
xor di,di ;hier: keinen "kurzen Pfad" bauen
call same_stuff
jc SetError
pop di
cmp si,[subst_root] ;noch vor den auszugebenden Komponenten?
jbe @@1
push fs di
push ds
mov bx,ofs LongName
cmp [by bx],1
jnc @@havelong
mov bx,ofs ShortName ;Zeiger auf kurzen Namen
@@havelong:
push bx
call fstrcpy ;Name kopieren
add di,ax
BTST [PFlags],PF_Slash
jz @@1
mov [by fs:di],'\'
inc di
@@1: BTST [PFlags],PF_Slash
jz @@2
inc si
@@2: cmp [by si],0
jnz @@l
@@ez: mov [by fs:di],0
@@e: ret
endp
verteiler: DVT 39h,lfn_mkdir ;w DS:DX
DVT 3Ah,lfn_rmdir ;w DS:DX
DVT 3Bh,lfn_chdir ;r DS:DX
DVT 41h,lfn_unlink ;w DS:DX CX SI
DVT 43h,lfn_attr ;? DS:DX BL CX SI DI
DVT 47h,lfn_pwd ;r DS:SI DL
DVT 4Eh,lfn_ffirst ;r DS:DX ES:DI CX SI
DVT 4Fh,lfn_fnext ;r BX ES:DI SI
DVT 56h,lfn_move ;w DS:DX ES:DI
DVT 60h,lfn_name ;r DS:SI ES:DI CX
DVT 6Ch,lfn_creat ;? DS:SI BX CX DX DI
DVT 0A0h,lfn_volinfo ;- DS:DX ES:DI BX CX DX
DVT 0A1h,lfn_fclose ;r BX
DVT 0A7h,lfn_timeconv;- DS:SI BX CX DX
DVT 0A8h,lfn_genshort;- DS:SI ES:DI DX
DVT 0AAh,lfn_subst ;- DS:DX BH(=0,1,2) BL(=LW)
db 0
_CASE
;Programm-Verteiler-Tabelle fr <lfn_attr>
pvt_attr dw ofs attr_getattr ;via DOS
dw ofs attr_setattr ;via DOS
dw ofs attr_getphyssize
dw ofs attr_settimem
dw ofs attr_gettimem
dw ofs attr_settimea
dw ofs attr_gettimea
dw ofs attr_settimec
dw ofs attr_gettimec
;Programm-Verteiler-Tabelle fr <lfn_attr bei CDFS, nur Lesezugriffe>
cd_pvt_attr dw ofs cd_attr_getattr ;via DOS
dw ofs cd_attr_getphyssize
dw ofs cd_attr_gettimem
dw ofs cd_attr_gettimea ;liefert 0
dw ofs cd_attr_gettimec ;liefert 0-0-0
;Alle Verteiler-Funktionen werden mit Stapelrahmen sowie ver„nderten
;Registern AX=7100h, DS=ES=CS, BP=Rahmenzeiger und DI=?? aufgerufen.
;Bei Aufruf ist das Richtungsflag gel”scht (aufsteigend)
;Sie mssen in AX den Rckgabewert liefern und ansonsten auf den Stapel
;zugeifen.
proc lfn_mkdir
;1. Finden des LFN-Eintrags
mov si,dx
call path_locate
call Check_CDFS_Throw ;auf CD schlecht m”glich:-)
call File_DirEnt_Locate
jnc SetErr5 ;Existiert bereits: Fehler!
;2. geeigneten, nicht bereits vorhandenen FCB-Namen ermitteln
call build_unique_fcb_name_start_1
call SFN_AL_CallOld
jc SetError
call InvalSector
;sollte an Cache angehangen werden! (hier noch nicht)
call ResetDrv
;4. LFN dazubasteln
call install_long_filename
jc @@del
ret
@@del: and [DriveType],not DT_Dirty ;Sektor doch nicht schreiben
mov ah,3Ah
call SFN_CallOld ;Verzeichnis l”schen
jmp SetErr5
endp
proc lfn_chdir
mov si,dx ;noch unzerst”rt...
call file_locate
jz @@1 ;Root
BTST [PFlags],PF_Slash ;12/02
jz @@1 ;kein Backslash am Ende
mov [by di-1],ah ;Backslash am Ende entfernen (so tut es 9x)
@@1: mov di,ofs ShortBuffer
call ModifyBuffer ;Nie auf dem Hostlaufwerk!
mov dx,di
mov ah,3Bh
jmp CallOld
endp
proc lfn_rmdir
call Find_Longname_For_Deletion
call SFN_AL_CallOld
jc Throw
jmp loesch_longpos
endp
proc lfn_pwd
;etwas brutal den User-Puffer missbrauchen, dann TRUENAME werkeln lassen
mov al,dl
push si
or al,al
jz @@1
add al,'@'
mov ah,':'
mov [fs:si],ax
add si,2
@@1: mov [wo fs:si],'.' ;das beschafft das aktuelle Verzeichnis!
pop si
call start_stuff ;macht den Rest und kmmert sich ums SUBST
mov si,ofs LongBuffer+3
mov di,[Client_SI] ;FS steht noch
jmp MakeLongName
endp
;+++++++++++ 3 Unterprogramme fr LFN_Create ++++++++++++++++
proc Copy_FCB_8P3_from_FCB_to_DI
push si di
mov si,ofs FCB_Name
call Copy_FCB_8P3_from_SI
pop di si
ret
endp
proc build_unique_fcb_name_start_1
mov si,1
build_unique_fcb_name:
;FU: Erstellt eindeutigen, neuen FCB-Namen
;PE: [FCB_Name]=bereits vom LFN abgeleiteter kurzer Name ohne Schlange
; [File_Flags]=Schalter fr Schlangen-Erzeugung (mit [ctrl])
; SI=Hint fr Schlange
; [ShortBuffer] gefllt mit Pfad
; DI=Zeiger ans ShortBuffer-Ende (hinter Slash, dort soll der Name hin)
;PA: [FCB_Name] geeignet modifiziert (garniert mit "~1" o.„.)
; [ShortBuffer] voll gefllt
; NO RETURN bei Alias-šberlauf, AL=5, oder unzul„ssiges Wildcard, AL=3
;VR: AX,BX,CX,DX,DI
;BUG: Sollte bei RENAME den zu entfernenden Dateinamen beachten (strcmp)
call Copy_FCB_8P3_from_FCB_to_DI
mov al,[File_Flags]
test al,(File_Flag_Is_LFN or File_Flag_Lowercase) ;wieso LC???
jz @@e ;gar nicht "typisch lang": fertig!
test al,File_Flag_Wildcards
jnz SetErr3
mov bx,ofs FCB_Name+31 ;Scratch-Byte fr's erste Mal
test al,File_Flag_Is_LFN
jz @@no_tilde ;nur wegen Kleinbuchstaben noch keine Tilde!
BTST [ctrl],CTRL_Tilde
jz @@no_tilde ;nicht mit Tilde starten
@@put_tilde:
mov [by bx],' ' ;Vorherige Erg„nzung im FCB_Name l”schen
call Poke_Number_Over_FCB
call Copy_FCB_8P3_from_FCB_to_DI
@@no_tilde:
mov ax,4300h ;Dateiattribute holen (als Existenz-Test)
call SFN_CallOld
cmc
jnc @@e ;nicht existent: fertig!
inc si
jnz @@put_tilde ;n„chster Versuch, sonst Umrundungs-Fehler
jmp SetErr5
@@e: call strlenp1 ;ans Ende rcken
dec di
jmp MakeBSlash ;falls da, sollte es sp„ter sch”n krachen
endp
proc strlenp1
;FU liefert String-L„nge+1 (also Alloc-L„nge), max. 200h
;PE: ES:DI=Stringzeiger
;PA: AX=String-L„nge+1
; DI=Zeiger hinter die terminierende Null
;VR: AX,CX,DI
mov ax,200h
mov cx,ax
repne scasb
sub ax,cx ;String-L„nge +1
ret
endp
proc make_free_dirent_space
;FU: Freien Speicher im Verzeichnis finden bzw. bereitstellen
;PE: [CurPathComp]=ASCIIZ langer Dateiname
; [SuchSektor]=Startsektor aktuelles Verzeichnis
; [FCB_Name]=zu suchender kurzer Dateiname
;PA: CY=1 wenn kein freier Platz vorhanden
; (DOS-Fehler oder Hauptverzeichnis voll oder Festplatte voll)
; [longname]=Unicode-Dateiname
; [longpos_s]:[longpos_a]=LFN-Sektoradresse
; [DirEnt_Copy]=Kopie des (gel”schten) "kurzen" Verzeichnis-Eintrags
; Verzeichnis-Eintrag gel”scht (markiert oder schon geschrieben)
; [LFN_DirEnts]=Anzahl n”tiger LFN-Verzeichniseintr„ge (etwa: L„nge/13)
;VR: alle, [num_cluster],[sektor]
mov si,[CurPathComp]
mov di,ofs LongName ;Kann zu kurz sein!!!
mov cx,-2
@@le: inc cx
call Oem2Uni
stosw
or ax,ax
jnz @@le
push cx ;= String-L„nge -1
dec ax
mov cl,12 ;CH=0 wenn mindestens 1 Zeichen(!)
rep stosw ;12x FFFF, wie es Win9x tut, hintenan
pop ax
mov cl,13 ;Unicode-Zeichen pro Eintrag
div cl ;Anzahl Eintr„ge in AL
inc al ;1..13->1, 14..26->2 usw.
mov [LFN_DirEnts],al
;4.2: Freiraum suchen, dabei "eigenen" DirEnt herausrechnen
;DH=Scan-Flags Bit0 "eigenen" DirEnt gefunden (zur Kontrolle)
; Bit1 gengend zusammenh„ngenden Freiraum gefunden
; Bit2 Ende (00) gefunden, nur noch Freiraum suchen
; Bit3 Clusterketten-Ende wurde erreicht
;DL=Z„hler freie DirEnts
mov eax,[SuchSektor]
mov [num_cluster],1
call ReadSecEAX
jc @@e0 ;wenn's schief geht
lea bx,[Sektor] ;der DirEnt-Zeiger
xor dx,dx
@@l1:
BTST dh,bit 2
jnz @@f_eol ;end-of-loop?
mov al,[bx]
or al,al ;Ketten-Ende
jz @@f_end
cmp al,0E5h
jz @@f_era
BTST [(TDirEnt bx).attr],bit 3 ;Volume Label (oder LFN-Eintrag)?
jnz @@f_vol ;FCB-Vergleich zwecklos oder sogar falsch
call Is_FCB_Equal
jz @@f_fcb
@@f_vol:mov dl,0 ;Schluss mit Leerraum
jmp @@to_next
@@f_fcb:
bts dx,0+8 ;setzen, schon gesetzt?
@@e0: jc @@e ;Fehler, wenn 2x gefunden (sollte nie sein)
mov si,bx
mov di,ofs DirEnt_Copy
mov cx,10h
rep movsw ;als Kopie sicherstellen
mov [by bx],0E5h ;und l”schen
or [DriveType],DT_Dirty
@@f_era:
BTST dh,bit 1 ;Schon gengend Freiraum gefunden?
jnz @@to_next
@@f_era1:
or dl,dl
jz @@f_newspace
dec dl
jnz @@to_next
BSET dh,bit 1 ;OK, gefunden
jmp @@to_next
@@f_newspace:
mov dl,[LFN_DirEnts] ;Z„hler laden
mov eax,[CurSector]
mov [longpos_s],eax ;(potentiellen) Anfang merken
mov [longpos_a],bx
@@to_next:
mov al,dh
not al
test al,3 ;Freiraum UND DirEnt gefunden?
jz @@e ;ja, fertig
push dx
call Next_Dirent
pop dx
jnc @@l1 ;n„chste Runde
BSET dh,bit 3
@@f_end:
BSET dh,bit 2
@@f_eol:
BTST dh,bit 0
stc
jz @@e ;Fehler: FCB nicht gefunden!
BTST dh,bit 1
jnz @@e ;Freiraum wurde schon gefunden!
BTST dh,bit 3 ;schon kein DirEnt mehr Platz im Cluster?
jz @@f_era1 ;doch!
push dx
call FlushDirty
call Alloc_Cluster ;mit Nullen gefllt und bereitgestellt
pop dx
jc @@e ;z.B. wenn Festplatte rappelvoll
BRES dh,bit 3 ;weiter mit normalem Next_DirEnt
jmp @@l1
@@e: ret
endp
proc CTRL_write_test
BTST [ctrl],CTRL_Write
jnz @@e
mov [LastError],1 ;Verbotener Schreibzugriff
ilfn_retu:
@@e: ret
endp
proc install_long_filename
;FU: Baut langen Dateinamen in Verzeichniseintrag ein,
; wenn es die Art des "langen" Dateinamens erforderlich macht
;PE: [CurPathComp]=ASCIIZ langer Dateiname
; [SuchSektor]=Startsektor aktuelles Verzeichnis
; [FCB_Name]=zu suchender kurzer Dateiname
;PA: [longpos_s]:[longpos_a]=LFN-Sektoradresse
; Sektorinhalt wird sofort ausgeschrieben
;VR: ?,[longname],[num_cluster],[sektor]
test [File_Flags],(File_Flag_Is_LFN or File_Flag_Lowercase)
jz ilfn_retu ;nicht basteln!
install_long_filename_noflagtest:
call CTRL_Write_test
jz ilfn_retu ;Bastelverbot
;1: Anzahl der notwendigen LFN-Verzeichniseintr„ge berechnen
call make_free_dirent_space
jc ilfn_retu ;Fehler!
;2: alles OK fr LFN-Eintragung
mov eax,[longpos_s]
call ReadSecEAX
jc ilfn_retu ;Fehler!
mov bx,[longpos_a]
;3: Langen Dateinamen einsetzen
mov si,ofs FCB_Name
call calc_check
xchg dh,ah
mov dl,[LFN_DirEnts]
;Schleife mit DL=Eintrags-Nummer, DH=Checksumme
mov cx,40h ;fr den Anfang
@@l2: mov al,13*2
dec dl
mul dl
inc dl
mov si,ofs LongName
add si,ax ;1->+0, 2->+13 usw.
mov di,bx
mov al,dl
or al,cl ;am Anfang 40h, sp„ter 0
stosb
mov cl,5 ;CH ist bereits 0
rep movsw
mov ax,0Fh
stosw ;Attribut
mov al,dh
stosb ;Prfsumme
mov cl,6
rep movsw
xor ax,ax
stosw ;Startcluster 0
movsw
movsw
or [DriveType],DT_Dirty
push dx
call Next_DirEnt
pop dx
jc @@e
xor cx,cx
dec dl
jnz @@l2
;4: Kurzen Dateinamen (mit Creation_Time) eintragen
cmp [DirEnt_Copy.timec],0
jnz @@k2
mov eax,[DirEnt_Copy.timem]
mov [DirEnt_Copy.timec],eax
@@k2: mov si,ofs DirEnt_Copy
mov di,bx
mov cx,10h
rep movsw
call WriteNow
lfn_creat_retu:
@@e: ret
endp
proc lfn_creat
;1. Finden des LFN-Eintrags
call path_locate
;Vermeidung von zuviel "locate_dirent", wenn der VC einfach seine
;drei DIRINFO-Dateien sucht...
mov ah,[Client_DL]
mov al,[File_Flags]
shr ah,4
push ax
test al,(File_Flag_Is_LFN or File_Flag_Char_High)
jnz @@locate_dirent ;Suche muss sein
dec ah ;Create als Option?
jnz @@pop_open_only ;nein, bloá Name kopieren reicht
test al,File_Flag_LowerCase ;Nur Groábuchstaben?
jz @@pop_open_only ;dann nicht erst suchen, sofort erzeugen
@@locate_dirent:
INT3
call File_DirEnt_Locate ;ver„ndert [CurSector] auf momentanen
pop ax
jnc @@open ;Nur ”ffnen: ganz einfach!
dec ah
jnz SetErr2 ;oberes Nibble muss 1 sein (sonst Code 2)!
call Check_CDFS_Throw ;auf CD ist CREAT schlecht m”glich:-)
call CTRL_Write_test
jz @@open_only ;8.3-Name erzeugen lassen (ohne Schlange?!)
;2. geeigneten, nicht bereits vorhandenen FCB-Namen ermitteln
mov si,1
test [Client_BH],4 ;Wirklich DI als Hint benutzen?
jz @@no_DI_hint
mov si,[Client_DI]
@@no_DI_hint:
call build_unique_fcb_name
jmp @@creat
@@pop_open_only:
pop ax
@@open_only:
mov si,ofs FCB_Name
call Copy_FCB_8P3_from_SI
@@open: ;3. Aufruf des OldInt21
mov [File_Flags],File_Flag_NDevice
;"nicht basteln"-Code vermerken
@@creat:
mov ax,[Client_CX] ;create-Attribut
test [File_Flags],(File_Flag_Is_LFN or File_Flag_Lowercase)
jz @@nopatch ;nicht R/O entfernen
mov [SearchAttr],ax
BRES al,bit 0 ;zun„chst ohne Schreibschutz erzeugen
@@nopatch:
mov dx,[Client_DX] ;Aktion (unver„ndert)
call SFN_6C_CallOld ;die Universalfunktion rufen
xchg bx,ax
mov [Client_CX],cx ;gemachte Aktion
call InvalSector
dec cx
dec cx
jnz retu1 ;Nur wenn "created" weitermachen
;kann an Cache angehangen werden! (hier noch nicht)
test [File_Flags],(File_Flag_Is_LFN or File_Flag_Lowercase)
jz retu1 ;nicht basteln!
mov ax,4400h ;Ist es gar ein Zeichentreiber?
call CallOldAndThrow ;m”glicherweise unn”tig mit dem CX-Test oben
BTST dx,bit 7 ;Datei oder Zeichentreiber-Bit
jnz retu1 ;nicht basteln!
;4. LFN dazubasteln, aber nicht an ge”ffneter Datei!!
mov ah,3Eh ;also Datei schlieáen
call CallOld
jc @@del ;Irrl„ufer! (L”schversuch eigentlich zwecklos)
call ResetDrv
call install_long_filename
jnc @@open_again
@@del: and [DriveType],not DT_Dirty ;Sektor doch nicht schreiben
mov ah,41h
call SFN_CallOld ;Datei l”schen (egal ob's funktioniert)
jmp SetErr5
;Noch mal ”ffnen
@@open_again:
mov ax,[SearchAttr] ;(Neues) Attribut
mov dx,2 ;Aktion = "truncate" - das Attribut wirkt!
;jmp SFN_6C_CallOld
endp
proc SFN_6C_CallOld
;FU: OldInt21/AX=6C00 (Extended Open/Create) aufrufen, fr lfn_creat
;PE: AX=Attribute, DX=CreateFlags
xchg cx,ax
lea si,[ShortBuffer]
mov bx,[Client_BX] ;Access/Share-Flags
mov ax,6C00h
call CallOldAndThrow
mov [Client_AX],ax ;Datei-Handle
retu1: ret
endp
proc lfn_move
;Vorgehensweise:
;Bildung des SFN fr beide Dateinamen (also zwei ShortBuffer
; erforderlich, dafr muss der Heap herhalten,
;Vormerken: L”schposition (wie bei SFN_unlink), FCB-Name und LFN
; fr neuen Namen
;Aufruf der DOS-Funktion RENAME
;alten DirEnt l”schen; SFN-LFN-Verknpfung NICHT in Tunnel schieben!
;neuen DirEnt setzen
;Sonderfall:
;Bilden beide (unterschiedlichen) LFN den gleichen SFN,
;wird _nicht_ die DOS-Funktion gerufen, sondern alles von Hand gemacht!
;(Zurzeit wird aber schlichtweg zu einem anderen Schlangen-Z„hler umbenannt)
;1. Quelldatei in SFN umwandlen
mov [SearchAttr],0
call Find_Longname_For_Deletion
;2. Quelldatei-SFN wegkopieren
mov di,ofs ShortBuffer
call strlenp1 ;AX=Alloc-L„nge
add ax,12 ;Platz fr Quell-LFN-L”sch-Info
call iLocalAlloc
jc retu1 ;kein Platz!
mov [SearchAttr],di ;ZWECKENTFREMDUNG
mov [throw_fi],ofs EMessage ;bei Fehler Speicher freigeben
mov si,ofs longpos_s
mov cx,3
rep movsw
mov si,ofs CurSector
movsd
xchg bx,ax
stosw
mov si,ofs ShortBuffer
call strcpy ;hinein in den Speicher!
;3. Zieldatei in SFN umwandeln
mov fs,[Client_ES]
mov si,[Client_DI]
call path_locate
call Check_CDFS_Throw ;auf CD schlecht m”glich:-)
call File_DirEnt_Locate
jnc SetErr5 ;Existiert bereits: Fehler!
;4. geeigneten, nicht bereits vorhandenen FCB-Namen ermitteln
call build_unique_fcb_name_start_1
;5. SFN-Funktion aufrufen
mov si,[SearchAttr]
lea dx,[si+12]
mov di,ofs ShortBuffer
mov ah,56h
call CallOldAndThrow
call ResetDrv
;6. Quell-LFN entfernen, SI steht noch
mov di,ofs longpos_s
mov cx,3
rep movsw
call Loesch_longpos ;evtl. vorhandenen Dateinamen killen!
;7. Ziel-LFN dazubasteln
call install_long_filename
;Und was tun, wenn's schiefging?
FreeSA:
mov ax,[SearchAttr]
jmp LocalFreeAX ;l”scht CY, wenn Zeiger OK
endp
proc EMessage
;FU: Fehler-Ausstieg nur fr lfn_move
push ax
call FreeSA
pop ax
stc
ret
endp
proc lfn_unlink
cmp [Client_SI],1
je @@wild
jc lfn_rmdir
@@err2: jmp SetErr2
@@wild:
call Start_FindFirst
mov al,[DriveType]
cmp al,1
jc @@err2 ;im Rckfallmodus (noch) kein Delete mit *
test [File_Flags],File_Flag_NDevice
jz @@err2
test al,DT_CDFS
jnz @@err2
; INT3
push di
mov bx,ofs Glob_LFN_Proc
call DirScan ;auf FAT ganz einfach!
pop di
jc @@err2
@@l: lea si,[ShortName]
push di
call strcpy
call SFN_AL_CallOld ;Auch bei Fehler weitermachen
cmp [LongName],0
jz @@sk ;nichts zu l”schen
test [DriveType],DT_SmartOS
jnz @@sk ;Turbo: Sektor nicht invalidieren
call Loesch_longpos ;SOO einfach darf's wohl nicht sein!
@@sk: call NextDirScan
pop di
jnc @@l
clc
jmp InvalSector
endp
proc Find_Longname_For_Deletion
;FU: Kopf-Funktion fr SFN/LFN-unlink/rmdir/move
;PE: FS:DX=zu l”schender Dateiname
; [PFlags]:PF_LFN_Input=Schalter, ob Dateiname "lang" oder "kurz"
;PA: [longpos_s]:[longpos_a]=Sektoradresse LFN-Eintrag
; [ShortBuffer]=kurzer Datei-Pfad (durchaus mit Kleinbuchstaben)
; [ShortName]=kurzer Dateiname (so wie vorgefunden, also Groábuchstaben)
; [LongName]=langer Dateiname (so wie vorgefunden)
; [CurSector]:BX=Sektoradresse SFN-Eintrag
; NO RETURN wenn zu l”schender Name nicht gefunden wurde
mov si,dx
call dirent_locate
jc SetError
cmp [longname],0 ;wirklich mit langem Namen?
jz @@w ;nein
test [DriveType],DT_SmartOS ;hat das OS bereits einmal gel”scht?
jz @@e ;nein, mssen's vielleicht selber tun
@@w: mov [longpos_a],0 ;nichts anschlieáend zu l”schen
@@e: ret
endp
proc Tunnel_Save2
;Einfach ShortBuffer und LongName retten, die von Find_Longname_For_Deletion
;brig geblieben sind
xor ax,ax
mov si,ofs Tunnel2
mov [si],ax
mov di,ofs LongName
cmp [di],al ;Ist da berhaupt einer?
jz @@e
call strlenp1
add ax,11+5
call iLocalAlloc
jc @@e ;kein Speicher? Nicht so schlimm...
mov [si],di
mov si,ofs FCB_Name
mov cx,11
rep movsb
mov si,ofs DPB_drive
movsb
mov si,ofs SuchSektor
movsd
mov si,ofs LongName
jmp strcpy
Tunnel_Save:
xor cx,cx
xchg [tunnel2],cx
jcxz @@e
xchg ax,cx
@@tunnel_free:
lea di,[tunnel]
jmp XchgDIPtr ;kmmert sich um Null-Zeiger
@@e: ret ;Ansprung-Return in der Mitte
Tunnel_Restore:
;Getunnelten langen Dateinamen bei Passung zum kurzen dazusetzen
;VR: alle
mov cx,[tunnel]
jcxz @@e ;Nichts zu wollen!
mov si,[Client_DX]
cmp [FuncNum],56h ;sfn_move?
jne @@ok
mov fs,[Client_ES]
mov si,[Client_DI]
Tunnel_Restore_1:
@@ok: call InvalSector ;k”nnte noch falsches DirEnt enthalten
call DirEnt_Locate ;muss existieren! Ansonsten: Alternativ-THROW
jc @@e ;DirEnt nicht gefunden
cmp [longname],0
jnz @@e ;Hat schon langen Dateinamen (open_existing)
mov di,[tunnel]
mov si,ofs FCB_Name ;W„re sch”ner alles hinteinander
mov cx,11
repe cmpsb
jne @@e
mov si,ofs DPB_Drive
cmpsb
jne @@e
mov si,ofs SuchSektor
cmpsd
jne @@e
mov [CurPathComp],di
call install_long_filename_noflagtest
xor ax,ax
jmp @@tunnel_free ;Tunnel "verbrauchen"
endp
proc sfn_create ;AH=3Ch
mov si,12h
jmp @@1
sfn_createnew: ;AH=5Bh
mov si,10h
@@1: xchg si,dx
mov bx,2 ;read/write access, compatibility mode
sfn_createex: ;AH=6Ch
mov [SearchAttr],cx
call @@try ;Stattdessen stets DOS4+ Extended Open rufen!
cmp [FuncNum],6Ch
jne @@2
mov [Client_CX],cx ;bedingt CX setzen
@@2: dec cx
dec cx ;"created"? (war =2?)
clc
jnz @@e ;nein, kein LFN ansetzen (CY=0)
mov cx,[tunnel]
jcxz @@e ;Nichts zu wollen!
push bx si ;Dateiname und OpenMode retten
xchg bx,ax
mov ah,3Eh
call CallOldAndThrow ;Schlieáen!
call Tunnel_Restore_1
pop si bx
mov cx,[SearchAttr]
btc cx,0 ;Schreibgeschtzt?
jnc @@3 ;nein, SetFAttr berspringen
mov ax,4301h ;Attribut muss entfernt werden!
mov dx,si
call PushedCallOld
BSET cx,bit 0
@@3: mov dx,0002h ;TRUNCATE, CX wird eingesetzt (wurde erprobt)
@@try: mov ax,6C00h ;Nochmals ”ffnen, diesmal CX _nicht_ setzen!
PushedCallOld:
push ds
mov ds,[Client_DS]
call CallOld
mov [Client_AX],ax ;Handle oder Fehlerkode
pop ds
jc Throw ;bei Fehler muss alles so bleiben
@@e: ret
endp
proc sfn_process
;Unabh„ngig von der Stellung des Schalters "Schreiben" muss beim
;L”schen von Dateien und Verzeichnissen _immer_ der LFN-Eintrag
;mit gel”scht werden!
;Ansonsten blieben im Verzeichnis LFN-Eintr„ge zurck, die das L”schen
;des Verzeichnisses verhindern, und das w„re weitaus schlimmer.
;Glcklicherweise wird Int21 immer sequentiell (im G„nsemarsch)
;gerufen, dadurch sollten Reentranzprobleme unter Windows vom Tisch sein.
;Beim L”schen in der NT-DOS-Box kommt das NT zuvor (dieses l”scht
; selbst„ndig den LFN-Teil, genauso auch das (nackte) MS-DOS7)
;BUG: Da fehlen noch die FCB-Funktionen fcb_unlink (AH=13h),
; fcb_creat (AH=16h), fcb_move (AH=17h)
xchg al,ah
mov [FuncNum],al ;fr Tunnel_Restore und sfn_createXX
;0. Extrawrste fr handle-liefernde Funktionen
cmp al,3Ch
je sfn_create
cmp al,5Bh
je sfn_createnew
cmp al,6Ch
je sfn_createex
;1. Finden des LFN-Eintrags
test ah,PF_Tunnel_Save ;AH=[PFlags]
jz @@1
call Find_Longname_For_Deletion
@@1: ;2. Aufruf des OldInt21
mov ax,[Client_AX] ;rmdir oder unlink oder rename
mov dx,[Client_DX] ;Dateiname
push es
mov es,[Client_ES] ;nur fr move/rename
mov di,[Client_DI] ;nur fr move/rename
call PushedCallOld ;Throw geht nicht, falsches DS
pop es
test [PFlags],PF_Tunnel_Save
jz @@e1
test [ctrl],CTRL_Tunnel
jz Loesch_longpos ;Wenn's nicht erst in den Tunnel kommt...
call Tunnel_Save2 ;Ergebnis in <tunnel2> "parken"
Loesch_longpos:
call terminate_cache ;evtl. vorhandenen Dateinamen killen!
;Dieser muss genaugenommen in den "Tunnel" geschoben werden!
;3. L”schen des LFN-Eintrags
call InvalSector ;ist nun auf jeden Fall ungltig!
mov bx,[longpos_a]
or bx,bx
jz @@e1 ;nichts zu tun!
mov eax,[longpos_s]
push bx
call ReadSecEAX
pop bx
mov al,[(TLfnDirEnt bx).count]
cmp al,0E5h ;Schlaues Betriebssystem am Werk?
jne @@nosmart
or [DriveType],DT_SmartOS ;nie mehr nachfummeln mssen!
@@nosmart:
test al,80h
jnz @@e1 ;hat das OS (z.B. WinNT) schon gel”scht o.„.!
test al,40h ;Letztes Stckel?
jz @@e1 ;irgendwas ist faul
and al,3Fh ;Nummer
@@loesch:
cmp [(TLfnDirEnt bx).attr],0Fh
jne @@ep ;wieder ist was faul (aber doch schreiben)
mov [(TLfnDirEnt bx).count],0E5h
or [DriveType],DT_Dirty ;schreiben lassen
dec al
jz @@ep ;Ende erreicht
push ax
call Next_DirEnt
pop ax
jc @@ep ;sollte eigentlich nie passieren
cmp al,[(TLfnDirEnt bx).count] ;Folge-Glied?
je @@loesch ;alles noch in Ordnung!
@@ep: call FlushDirty ;sicherheitshalber sofort schreiben (Diskette!)
@@e1:
test [PFlags],PF_Tunnel_Restore
jz @@2
call Tunnel_Restore
@@2: test [PFlags],PF_Tunnel_Save
jz @@e
call Tunnel_Save ;Endgltig in <tunnel> retten
clc
@@e: ret
endp
proc Check_NoRO
;FU: Testet aktuelles Laufwerk auf NoRO-Kandidat und, wenn ja, l”scht
; Schreibschutzattribut
;PE: CX oder CL = Attribut
;PA: CX oder CL = modifiziertes Attribut
;VR: CL,AL
test [ctrl],CTRL_RoBit
jnz @@e ;alles belassen
mov al,[DriveType]
cmp al,1 ;unbekannt: NORO
jc @@1
test al,DT_CDFS ;auf CDs sowieso NoRO
jz @@e
@@1: BRES cx,1 ;Schreibschutz-Attribut weg!
@@e: ret
endp
;<lfn_attr>-Unterprogramme
;PE: BX=DirEnt-Zeiger
; CY=0
;N: DOS6.2: although SFN GetAttr of "X:\" fails on a CD drive,
; LFN GetAttr never fails (was bug until 0.22d)
proc lfn_attr_subroutines
cd_attr_getattr:
attr_getattr: ;via DOS ohne spezielle (CD-)Verrenkungen
mov cx,10h
cmp [by ShortBuffer+3],0 ;nur "X:\" ?
jz @@wrcx ;Extrawurst!
mov ax,4300h
call SFN_CallOld ;also GetAttr
jc @@e
call Check_NoRO
@@wrcx: mov [Client_CX],cx
@@e: ret
attr_setattr:
mov cx,[Client_CX]
mov ax,4301h
jmp SFN_CallOld
cd_attr_getphyssize:
mov eax,[(TCD_DirEnt bx).fsize]
mov cl,11 ;2^11=2048
jmp @@getphyssize
attr_getphyssize:
mov eax,[(TDirEnt bx).fsize] ;mit Clusterverschwendung...
mov cl,[DPB_Shift] ;fr max. 64K-Cluster
add cl,9 ;2^9=512 Bytes pro Sektor
@@getphyssize:
mov bx,1
shl bx,cl
dec bx
test ax,bx
jz @@FullCluster
or ax,bx
inc eax ;aufrunden
@@FullCluster:
mov [Client_AX],ax
ror eax,16
mov [Client_DX],ax
@@retu: clc
ret
attr_settimem:
;Fehlt noch: Anpassung der Verzeichniseintr„ge "." und ".."
;im untergeordneten Verzeichnis (falls Verzeichnis), oder was macht Win9x?
mov ax,[Client_DI]
rol eax,16
mov ax,[Client_CX]
cmp [(TDirEnt bx).timem],eax
je @@retu
mov [(TDirEnt bx).timem],eax
@@Dirty_Sec:
or [DriveType],DT_Dirty
ret
cd_attr_gettimem:
call CD_Get_Time
jmp @@attr_gettimem
attr_gettimem:
mov eax,[(TDirEnt bx).timem]
@@attr_gettimem:
push eax
pop [Client_CX] ;LOW
pop [Client_DI] ;HIGH
ret
attr_settimea:
mov ax,[Client_DI]
cmp [(TDirEnt bx).timea],ax
je @@retu
mov [(TDirEnt bx).timea],ax
jmp @@Dirty_Sec
attr_gettimea:
mov ax,[(TDirEnt bx).timea]
cd_attr_gettimea:
mov [Client_DI],ax
ret
attr_settimec:
mov ax,[Client_DI]
rol eax,16
mov ax,[Client_CX]
mov [(TDirEnt bx).timec],eax
mov ax,[Client_SI]
mov [(TDirEnt bx).timec10ms],al
jmp @@Dirty_Sec
cd_attr_gettimec:
call CD_Get_Time
jmp @@attr_gettimec
attr_gettimec:
mov dl,[(TDirEnt bx).timec10ms]
mov eax,[(TDirEnt bx).timec] ;DWORD
@@attr_gettimec:
mov [Client_CX],ax ;LOW
shr eax,16
mov [Client_DI],ax ;HIGH
mov dh,0
mov [Client_SI],dx
ret
endp lfn_attr_subroutines
proc lfn_attr
mov si,dx
mov al,bl
cmp al,9
jnc @@e5 ;Fehler: falsche Subfunktion
mov dx,ofs file_locate
cmp al,2
jc @@1 ;immer erlaubt, weil Schreiben via DOS
mov dx,ofs dirent_locate
call CTRL_Write_test
jnz @@1 ;Schreiben erlaubt
test al,1
jnz @@e5 ;verbotener Schreibzugriff!
@@1: call dx ;also je nach [Client_BL]
jc @@e
mov ax,ofs cd_pvt_attr
mov si,[Client_BX]
and si,0FFh
call Check_CDFS
jnz @@iscd
mov ax,ofs pvt_attr
add si,si
@@iscd: test si,1 ;ungerade Nummer?
jnz @@e5
add si,ax
xor ax,ax
jmp [wo si]
@@e5: mov al,5
@@e: jmp SetError
endp
proc InitFill
;FU: Win32_Find_Data-Record-Zeiger laden und EAX l”schen; CH laden;
; Client_CX l”schen (return OEM oder?)
mov es,[Client_ES]
mov di,[Client_DI]
mov ch,[by LOW Client_SI]
xor eax,eax
mov [(TW32FindData es:di).sname],al
mov [Client_CX],ax
ret
endp
proc FillFD
;Routine fr FindFirst/FindNext: W32FindData-Record fllen
;PE: [Client_ES]:[Client_DI]=FindData-Zeiger
; BX=DirEnt-Zeiger
; [Client_SI]=DateTime_Format (Bit 0)
;PA: FindData gefllt; Zeitformat=DOS
; [Client_CX]=0 oder 1 (Unicode_Conversion_Flags)
;VR: ES,DI,SI,EAX,EDX,CH
call InitFill
call copy_attr_and_time
xor eax,eax
stosd ;SizeH
xchg edx,eax
stosd ;SizeL
call stosq0 ;res
mov si,ofs LongName
cmp [by si],al
jz @@short_only
push di
call strcpy ;"Langer" Dateiname
pop di
mov al,[PFlags] ;evtl. Konvertierungsfehler?
and al,PF_Fail_Uni2Oem ;muss Bit 0 sein!
mov [Client_CL],al ;Konvertierungsfehler mitteilen
add di,260 ;auf "kurzen" Namen
@@short_only:
mov si,ofs ShortName
jmp strcpy
endp
proc PutValues
;Routine fr FindFirst/FindNext: Handle-Puffer fllen
;PE: DI=Handle-Puffer
; [SearchAttr]=Such-Attribut
; BX=DirEnt-Zeiger
; [CurSector]=Sektornummer
;PA: Handle-Puffer gefllt
;VR: EAX,DX,SI,DI,CX
mov al,MAGIC_hFind ;Magic fr "gltiges Handle"
stosb
mov al,[DPB_Drive]
stosb
mov ax,[SearchAttr]
stosw
call Check_CDFS
jnz @@cd
mov ax,bx
stosw
lea si,[CurSector]
movsd
jmp @@w
@@cd: lea si,[Search.jol]
mov cx,11
rep movsw
@@w: ;mov al,[File_Flags]
;stosb
mov si,[CurPathComp]
call strcpy ;den String hinterher!
ret
endp
proc Check_Valid_BX
;Testet ob BX=FindFirst/FindNext-Handle gltig ist
;PA: NO RETURN wenn ungltig (AL=6)
; SI=BX+1
; Z=0 fr Fallback-Modus
or bx,bx ;Nullhandle extra (wegen VC-Fehler)
jz @@f_vc ;AX (=7100h) belassen!
mov si,bx
lodsb
cmp al,MAGIC_hFind
jz @@ok
cmp al,MAGIC_FB_hFind
jz @@ok_Z0
@@f_vc: mov al,6 ;invalid handle (s.a. Int21/AH=59)
jmp SetError
@@ok_Z0:or al,al
@@ok: ret
endp
proc Alloc_Find_Handle
;FU: Speicherreservierung fr FindFirst
;PE: [CurPathComp]=Suchausdruck (wegen Speicherplatzbedarf sp„ter!)
;PA: DI=[Client_AX]=Zeiger auf entsprechend Platz
; NO RETURN AL=4=handle table full
mov di,[CurPathComp]
call strlenp1
add ax,SIZE TFindInfo ;zz. unabh„nging FAT/Joliet
call Check_CDFS
jz _Alloc_Find_Handle
add ax,2+2+22-(SIZE TFindInfo)
_Alloc_Find_Handle: ;Einstieg fr Rckfall...
call iLocalAlloc
mov al,4 ;handle table full
jc SetError
mov [Client_AX],di ;return Handle
ret
endp
proc FB_Alloc_Find_Handle
;FU: Speicherreservierung fr FindFirst im Rckfallmodus
;PE: [CurPathComp]=Suchausdruck (wegen Speicherplatzbedarf sp„ter!)
;PA: DI=[Client_AX]=Zeiger auf entsprechend Platz
; CY=1: AX=9904=handle table full
xor ax,ax
test [File_Flags],File_Flag_Is_LFN
jz @@1 ;keinen Dateinamen einbeziehen!
mov di,[CurPathComp]
call strlenp1
@@1: add ax,SIZE TFB_FindInfo
jmp _Alloc_Find_Handle
endp
proc FB_FillFD
call InitFill ;liefert CH(!)
mov cl,[DTA.attr]
call Check_NoRO
xchg cl,al
stosd
call stosq0
call stosq0
mov eax,[DTA.time]
call evtl_time_dos_win_dl0 ;verwendet CH
xor eax,eax
stosd ;SizeHigh
mov eax,[DTA.fsize]
stosd
call stosq0 ;2 langweilige reservierte Felder
lea si,[DTA.fname]
jmp strcpy
endp
proc noentry_FB_Check_Found
;FU: Testet Dateinamen und Attribut im DTA gegen zu suchenden
; "langen" Suchausdruck (der z.B. die Suche nach "*1" untersttzt)
; sowie gegen das noch ausstehende Must-Match-Attribut.
; Bei Fehltreffer Ausl”sung von FindNext bis zum Treffer oder CY=1
; Das Attribut 0Fh wird hier extra herausgeworfen...(???)
;PE: DOS DTA auf [DTA] gesetzt und gefllt
@@l: mov al,[DTA.attr]
cmp al,0Fh ;ein LFN (auf FAT)?
je @@retry
call Match_MM_Attr
jnz @@retry
test [File_Flags],File_Flag_Is_LFN
jz @@e ;kein Dateiname zu vergleichen
lea si,[DTA.fname]
call GlobbingEx
jz @@e ;OK, Name geht durch
FB_Find_Next: ;Einstieg fr FB_fnext
@@retry:mov ah,4Fh ;FindNext
FB_Find_First: ;Einstieg mit AH=4Eh
call CallOld
jnc @@l
@@e: ret
endp
proc FB_ffirst
;FU: FindFirst im Rckfallmodus
call same_stuff ;hier: Suchmaske (meist ????????.???)
call DTA_Init
mov cx,[SearchAttr]
not cl
mov dx,ofs ShortBuffer
mov ah,4Eh
call FB_Find_First
jc DTA_Done ;wenn's nichts zu finden gab
call FB_Alloc_Find_Handle
jc DTA_Done ;kein Platz im Heap (pardon!)
mov al,MAGIC_FB_hFind
stosb
call Store_DTA
mov al,[by HIGH SearchAttr]
stosb
mov al,[File_Flags]
stosb
test al,File_Flag_Is_LFN
jz @@no_name
mov si,[CurPathComp]
call strcpy ;liefert CY=0
@@no_name:
jmp FD_Fill
endp
proc FB_fnext
;FU: FindNext im Rckfallmodus
;PE: BX=(SI-1)=Heap-Zeiger (Such-Handle)
call DTA_Init
mov di,ofs DTA
mov cx,21 ;eigentlich k”nnte die DTA auch ganz gut
rep movsb ;im Heap residieren, aber ich bin ja geizig..
lodsb
mov [by HIGH SearchAttr],al
lodsb
mov [File_Flags],al
mov [CurPathComp],si ;hier: egal ob Name gespeichert ist!
call FB_Find_Next
jc DTA_Done
mov di,bx ;BX (=Handle) bis dahin nicht ge„ndert(?)
inc di
call Store_DTA ;die 21 Bytes als Aufh„nger zum Weitersuchen
FD_Fill:
call FB_FillFD
;jmp DTA_Done
endp
proc DTA_Done
;VR: DX; Flags (speziell CY) werden gerettet!
pushf
push ds ax
lds dx,[old_dta]
mov ah,1Ah
call CallOld
pop ax ds
popf
ret
endp
proc DTA_Init
;VR: AX,DX(=ofs dta)
call InvalSector
push es bx
mov ah,2Fh
call CallOld
SES [old_dta],bx
pop bx es
mov dx,ofs dta
mov ah,1Ah
jmp CallOld
endp
proc Store_DTA
;FU: 21 Bytes des DTA nach ES:DI kopieren
;PA: DI entsprechend erh”ht
;VR: CX,SI,DI
lea si,[DTA]
mov cx,21
rep movsb ;die 21 "undokumentierten" Bytes der DTA
ret
endp
proc Check_Device
;D: If file name is a DOS device, DOSLFN should work in FallBack mode
; and let DOS handle these special files
;I: [FCB_Name]=file name to check
; [File_Flags]=plausibility bits before comparing
; [DriverChain]=const FAR pointer to DOS device driver chain
;O: [File_Flags].NDevice=0 if device, unchanged if not
; CY always clear
;M: CX
test [File_Flags],(File_Flag_Is_LFN or File_Flag_Wildcards)
jnz @@e ;cannot be a DOS device
push es bx si di
mov bx,ofs DriverChain
@@l: les bx,[es:bx]
inc bx ;was xxxx:FFFF
jz @@ex ;documented end of chain
dec bx
BTST [wo es:bx+4],8000h ;character device?
jz @@l ;no, continue with next driver
lea di,[bx+10]
lea si,[FCB_Name]
mov cx,4
repe cmpsw
jne @@l ;no match, continue with next driver
BRES [File_Flags],File_Flag_NDevice
@@ex: pop di si bx es
@@e: clc
ret
endp
proc Start_FindFirst
;FU: Gemeinsame Routine fr lfn_ffirst und lfn_unlink mit Platzhalterzeichen
;PE: FS:DX=Suchmaske
; [Client_CX]=Such-Attribute
; [PFlags]:PF_LFN_Input=1
;PA: [File_Flags]=Eigenschaften der letzten Komponente
; [DriveType]=Laufwerkstyp
; CX=[SearchAttr]=bearbeitete Such-Attribute
; CY=Pfad nicht gefunden
mov si,dx
call path_locate
BRES [PFlags],PF_Follow
mov ax,[Client_CX] ;Attribute
cmp al,8 ;Nur Volume Label?
jne @@1
mov ah,al ;dann gilt hier eine Must-Match-Ausnahme!
@@1: or al,21h ;ARCHIVE und READONLY immer "durchlassen"
not al ;als "Auswerf-Maske" umdrehen
mov [SearchAttr],ax
xchg cx,ax ;fr's (lange) Label der CD
@@e: ret
endp
proc lfn_ffirst
INT3
call Start_FindFirst
jc @@e
mov al,[DriveType]
cmp al,1
jc FB_ffirst ;das ganze im Rckfallmodus
test [File_Flags],File_Flag_NDevice
jz FB_ffirst
test al,DT_CDFS
jnz @@oncd
mov bx,ofs Glob_LFN_Proc
call DirScan ;auf FAT ganz einfach!
jmp @@k
@@oncd:
push di
lea si,[Search.jol.i.sect]
lea di,[Search.jol.restart]
movsd
movsw
pop di
test cl,8 ;Volume Label requested?
jnz @@2
cmp di,ofs ShortBuffer+3 ;root dir?
jnz @@2 ;volume label only on root!
call CD_Make_Volume_Label
jnc @@e
@@2:
mov bx,ofs Glob_CD_LFN_Proc
call CD_Ping_DirScan ;auf CDFS ungleich komplizierter!
;mov bx,ofs CD_Sektor ;zurckstellen!?
@@k: jc SetErr2 ;file not found
@@f: ;Eintrag gefunden, mit bx=DirEnt-Zeiger
call Alloc_Find_Handle
call PutValues
call FillFD
@@e: ret
endp
proc lfn_fnext
call Check_Valid_BX
jnz FB_fnext
lodsb
inc al
call GetDrvParams ;tut meist nichts, wenn AL gleich geblieben
lodsw
mov [SearchAttr],ax ;Attribute
call Check_CDFS
jnz @@cd
;weiter mit FAT
mov [MatchPtr],ofs Glob_LFN_Proc
lodsw
xchg bx,ax ;Sektorzeiger
lea di,[CurSector]
movsd ;Sektor-Nummer
jmp @@gem
@@cd: ;weiter mit CDFS (Joliet)
mov [MatchPtr],ofs Glob_CD_LFN_Proc
lea di,[Search.jol]
mov cx,11
rep movsw
call CD_LFN_Load
@@gem:
;lodsb
;mov [File_Flags],al
mov [CurPathComp],si ;Maske folgt (Zeiger in Heap)
push bx
call ReadSec
pop bx
jc @@alldrives
call NextDirScan ;Bei CDROM liegt der Hase im Pfeffer...
jc @@alldrives
call Check_CDFS
jz @@alldrives ;Was fr eine Glle hier!
call SetSuchSektor_SFN
push di
lea di,[Search.jol.j]
call CD_SaveDirInfoFull ;neuer Zeiger fr PutValues
pop di
call CD_SFN_Load
mov [MatchPtr],ofs Match_CD_Sectorpointer_Proc
call CD_NextDirScan_Circular
jc @@e ;Konsistenzfehler!
call CD_Shortname
lea di,[Search.jol.i]
call CD_SaveDirInfoFull
clc
@@alldrives:
jc SetErr18 ;no more files
mov di,[Client_BX] ;find handle
call PutValues
call FillFD
mov ah,4Fh ;"undokumentierter" Returnwert
mov [Client_AX],ax
@@e: ret
endp
proc lfn_fclose
call Check_Valid_BX
xchg ax,bx
jmp LocalFreeAX ;Handle-Tabellen-Eintrag freigeben
endp
proc CheckModifyBuffer
;PE: DI=Pufferadresse
;PA: Puffer und Pufferadresse zu virtuellem Laufwerk modifiziert,
; wenn Bit 7 von Client_CH gesetzt ist
;VR: AX,DI
BTST [Client_CH],bit 7
jz @@e ;Nicht modifizieren
ModifyBuffer:
mov al,[subst_drive]
or al,al ;Netzlaufwerk?
jz @@e ;Nicht patchen!!
add di,[subst_root]
push di
mov ah,':'
stosw
cmp [by di],0 ;Backslash k”nnte entfernt sein
jnz @@1
mov ax,'\'
stosw ;terminiert nachsetzen
@@1: pop di
@@e: ret
endp
proc lfn_name
public lfn_name
cmp cl,3 ;nur 0..2
jnc erre
cmp cl,1
jc lfn_truename
jz lfn_shortname
jmp lfn_longname
erre: stc
ret
endp
proc lfn_truename
call Truename
mov di,ofs longbuffer
jmp _copy_to_client
endp
proc lfn_shortname
call file_locate
mov di,ofs shortbuffer
_copy_to_client:
call CheckModifyBuffer
push [Client_ES] [Client_DI]
push ds di
call fstrcpyBS
ret
endp
proc lfn_longname
call start_stuff
mov si,ofs longbuffer
cmp [by si],'/' ;UNC?
mov ax,'\\'
je @@2
lodsw
BTST [Client_CH],bit 7
jnz @@1
mov [subst_root],0 ;Hostpfad liefern
jmp @@2
@@1: mov al,[subst_drive];virtuelles Laufwerk liefern
@@2: mov fs,[Client_ES]
mov di,[Client_DI]
mov [fs:di],ax ;Laufwerk:
inc si ;hinter den Root-Backslash
scasw ;=add di,2
mov [by fs:di],'\'
inc di
jmp MakeLongName
endp
proc lfn_genshort
;Aus Dateiname (ohne Pfad) kurzen Dateinamen (Alias) generieren
;Seiteneffekt: arbeitet bis zum Backslash (Pfad-Komponente)
cmp [Client_DL],11h ;nur OEM->OEM wird untersttzt!
jne erre
cmp [Client_DH],2 ;nur 0 (FCB) oder 1 (8.3)
jnc erre
mov si,ofs longbuffer
push ds si
push [Client_DS] [Client_SI]
call fstrcpy ;lokal kopieren
call Gen_Alias ;nach FCB_Name
mov es,[Client_ES]
mov di,[Client_DI]
cmp [Client_DH],0
mov bx,ofs FCB_Name
je @@want_fcb
call Copy_FCB_8P3 ;hier mit ES<>DS!
ret
@@want_fcb:
mov si,bx
mov cx,11
rep movsb
ret
endp
proc lfn_timeconv
public lfn_timeconv
cmp [Client_BL],1
jc @@todos
jz @@towin
stc
ret
@@todos:
segfs lodsd
xchg edx,eax
segfs lodsd
xchg edx,eax
call time_win_dos
jc @@e ;kann versagen...
ror eax,16 ;Hi<->Lo
mov [Client_CXDX],eax
mov [Client_BH],dl
clc
@@e: ret
@@towin:
mov eax,[Client_CXDX]
rol eax,16 ;Hi<->Lo
mov dl,[Client_BH]
mov es,[Client_ES]
mov di,[Client_DI]
;jmp time_dos_win ;versagt nie
endp
proc time_dos_win ;TODO
;FU: Zeit-Umwandlung DOS->WIN
; Die Implementierung w„re geradezu Luxus; deshalb einfach eine
; "Abbildung", die zumindest eine korrekte Sortierung erm”glicht,
; und eine Rckkonvertierung zum vorhergehenden FAT-Format erm”glicht
;PE: EAX=DOS-Dateizeit
; DL=DOS-10-ms-Schritte
; [TimeOffset]=Zeitzonen-Umrechnungszahl
; ES:DI=Speicher zum Schreiben der Zeit (stosq)
;PA: EAX:EDX=Win-Dateizeit (100-ns-Schritte seit 1.1.1601)
; CY=1: fehlerhafte Angaben (z.B. 13. Monat o.„.)
;VR: EAX,EDX
xchg edx,eax
shl eax,24 ;stimmt ungef„hr (Faktor 500)
stosq:
stosd
xchg edx,eax
stosd
ret
endp
proc stosq0
xor eax,eax
stosd
stosd
ret
endp
proc evtl_time_dos_win_dl0
;FU: Wandelt je nach CH die Dateizeit ins Win-Format
; oder macht nichts auáer EDX zu l”schen; fr FindFirst/FindNext
;PE: EAX=DOS-Dateizeit
; DL=DOS-10-ms-Schritte (nur bei Einsprung evtl_time_dos_win)
; CH=Schalter DOS (<>0) oder Win (=0)
; ES:DI=Speicherort fr Win32-Zeit
;PA: EDX:EAX=DOS- oder Win-Dateizeit
;VR: EAX,EDX,DI
mov dl,0
evtl_time_dos_win:
or ch,ch
jz time_dos_win
xor edx,edx
jmp stosq
endp
proc time_win_dos ;TODO
;FU: Zeit-Umwandlung WIN->DOS
;PE: EDX:EAX=Win-Dateizeit (100-ns-Schritte seit 1.1.1601)
; [TimeOffset]=Zeitzonen-Umrechnungszahl
;PA: EAX=DOS-Dateizeit
; DL=DOS-10-ms-Schritte
; CY=1: auáerhalb des Bereiches 1980..2107
;VR: EAX,EDX
;Zur Zeit einfach als "Komplement„rfunktion" implementiert
shr eax,24
xchg edx,eax
ret
endp
proc lfn_volinfo
public lfn_volinfo
;Laufwerks-Informationen beschaffen
mov si,dx
call start_stuff
xor eax,eax
mov [Client_DXBX],260*65536+4006h
;L„nge Pfad (DX), BX=4007h w„re mit case-sensitiver Suche
dec al ;255
xchg [Client_AXCX],eax ;L„nge Dateiname<->L„nge VolType
cmp ax,4 ;zu kleiner Puffer?
jc @@novolinf ;Nicht einschreiben!
mov es,[Client_ES]
mov di,[Client_DI]
call Check_CDFS
jnz @@cd
mov eax,'TAF' ;lies: "FAT",0
stosd
@@novolinf:
clc
@@e: ret
@@cd: mov eax,'SFDC' ;lies: "CDFS"
stosd
mov al,0
stosb
ret
endp
proc copy_attr_and_time
;BE: Gemeinsame Routine fr FillFD (FindFirst/FindNext)
; und GetFileInfoByHandle (wie auch immer der Dateiname zu ergattern ist)
; Dummerweise geht nicht mehr, da "Datentr„gernummer" dazwischen kommt
; Fr FAT und CDFS (per Fallunterscheidung)
;PE: BX=DirEnt-Zeiger
; ES:DI=Puffer fr attr,timec,timea,timem
; CH=Schalter fr Zeit-Konvertierung, =0 fr Win-Dateizeit
;PA: DI vorgerckt
; EDX=Datei-GrӇe
;VR: EAX,EDX,DI
xor eax,eax
call Check_CDFS
jnz @@cd
mov al,[(TDirEnt bx).attr] ;gefundenes Attribut
stosd
mov eax,[(TDirEnt bx).timec];creation time
mov dl,[(TDirEnt bx).timec10ms]
call evtl_time_dos_win
mov ax,[(TDirEnt bx).timea] ;access time (nur Datum)
shl eax,16
call evtl_time_dos_win_dl0
mov eax,[(TDirEnt bx).timem];modification time
call evtl_time_dos_win_dl0
mov edx,[(TDirEnt bx).fsize];DateigrӇe (max. 2GB)
ret
@@cd:
call CD_Get_Attr
stosd
call CD_Get_Time ;auf 1 Sekunde genau
call evtl_time_dos_win ;creation time
xchg edx,eax
push eax
call stosq0 ;access time unbekannt
pop eax
call stosq ;modification time
mov edx,[(TCD_DirEnt bx).fsize];DateigrӇe (max. 2GB)
ret
endp
proc lfn_subst ;nur "Query Subst"
;Die anderen Funktionen, "Create Subst" (BH=0, DS:DX=Zu verbindender Pfad)
;und "Terminate Subst" (BH=1) erfordern das Patchen in DOS-Strukturen
cmp bh,2
stc
mov ax,7100h
jnz @@e ;Durchl„ufer: "Nicht untersttzte Funktion"
;etwas brutal den User-Puffer missbrauchen
mov si,dx
mov eax,'\:?' ;das beschafft das SUBST-Verzeichnis!
mov al,bl
add al,'@'
mov [fs:si],eax
call Truename ;spuckt bei falschem Laufwern
push fs [Client_DX]
push ds ofs longbuffer
call fstrcpyBS
@@e: ret
endp
;******************************************************************
;** FastOpen-Cache
;** h„lt die Zuordnung "kurzer Name", "langer Name" und "Startsektor"
;** zur Vermeidung exzessiver Festplattenzugriffe
;** reset_cache_ptr vor Dateinamen-Suche aufrufen
;** fr jede Pfadkomponente find_in_cache aufrufen,
;** bei jedem Versager und Auffindung put_to_cache aufrufen!
;******************************************************************
;Cache-Aufbau: ab Wurzel:
;<tiefe> mal
; ASCIIZ kurzer Dateiname (alias)
; ASCIIZ langer Dateiname (longname)
; DWORD Startsektor
;BYTE 0 Ende der Kette
;[fastopen_ptr] zeigt auf aktuellen Eintrag
;proc reset_cache_ptr
; mov [fastopen_ptr],ofs fastopen_buf
; ret
;endp
proc find_in_cache
;Vergleicht [CurPathComp] mit [fastopen_ptr]
;Wenn das klappt, kopiert langen Dateinamen nach [longname] ???
; und CurPathComp nach shortbuffer (Anh„ngen an DI)
;Wenn nicht, vergleicht [CurPathComp] mit vorgercktem [fastopen_ptr]
;Wenn das klappt, kopiert Alias nach [shortbuffer] (Anh„ngen an DI)
;Wenn nicht, dann raus mit Z=0
;Startsektor nach [CurSector] schreiben
;PA: Z=1: gefunden
; [CurSector]=Startsektor (FAT), [CD_?FN_Cur]=Startsektoren (Joliet)
; [ShortName]=kurzer Dateiname
; [LongName] =langer Dateiname
; [fastopen_ptr] vorgerckt
; Z=0: nicht gefunden
; [fastopen_ptr]^=0 Endemarkierung gesetzt
;VR: EAX, SI, DI (nur bei Z=1)
mov di,[fastopen_ptr]
cmp [by di],1 ;Null als Kennung fr "kein Cache-Eintrag"
jc @@e
mov si,[CurPathComp]
call StrIComp
jz @@f
;nicht "kurz" gefunden: "lang" suchen!
dec di ;zumindest AUF die Null zurck!
mov al,0
push cx
mov cx,-1
repne scasb ;DI hinter die Null von ShortName
pop cx
mov si,[CurPathComp]
call StrIComp
jnz terminate_cache
@@f:
mov si,[fastopen_ptr]
mov di,ofs ShortName
call strcpy ;kurz nach "ShortName" (dann nach "shortbuffer")
mov di,ofs LongName
call strcpy ;lang nach "LongName" (ggf. leere Zeichenk.)
lodsd
call _set_cur_and_such ;belanglos bei CDFS
call Check_CDFS
jz @@nocd
lea di,[Search.jol.i.sect]
stosd ;Start und L„nge bertragen
movsw
lea di,[Search.jol.j.sect]
movsd ;2x
movsw
cmp al,al ;Z setzen
@@nocd: mov [fastopen_ptr],si
@@e: ret
endp
proc terminate_cache
;FU: FastOpen-Kette terminieren
mov di,[fastopen_ptr]
mov al,0
stosb ;Ende-Kennung hier eintragen
ret
endp
proc put_to_cache
;Tut beide Dateinamen in Puffer mit Startsektor, Abschluss mit Doppelnull
;PE: [CurSector]=Startsektor (bei CDFS: [CD_Search.i.sect] und [CD_Search.j.sect])
; šber die Link-Tabelle ist eigentlich nur das Speichern EINES Sektors
; bei CD erforderlich!
; [LongName] =langer Dateiname (ggf. leer)
; [ShortName]=kurzer Dateiname (Zeiger)
;PA: [fastopen_ptr] vorgerckt
; [fastopen_ptr]^=0 Endemarkierung gesetzt
;VR: SI,DI,EAX
mov di,[fastopen_ptr]
mov si,ofs ShortName
call strcpy ;liefert AL=0
mov si,ofs LongName
call strcpy ;ggf. nur die Null speichern, wenn kein LFN
lea si,[CurSector]
call Check_CDFS
jz @@nocd
lea si,[Search.jol.i.sect]
movsd ;Startsektor
movsw ;L„nge in Sektoren
lea si,[Search.jol.j.sect]
movsw ;naja, auch 6 Bytes
@@nocd:
movsd
mov [fastopen_ptr],di
mov al,0
stosb ;Endekennung
ret
endp
;******************************************************************
;** LocalAlloc-Speicher (Heapverwaltung)
;** fr die kleineren Allozierungen bei FindFirst/FindNext usw.
;** Speichervergabe erfolgt in 4-Byte-Stckelung.
;** Der Freispeicher ist in einer verketteten Liste:
;** 1 WORD Next-Pointer
;** 1 WORD GrӇe dieses Freispeicher-Blocks (inkl. der beiden WORDs)
;** Belegter Speicher hat am Anfang:
;** 1 WORD GrӇe dieses belegten Blocks (inkl. dieses WORDs)
;** und zurckgegeben wird ein Zeiger DAHINTER
;******************************************************************
;Konstanten fr Allokations-Strategie:
LMEM_FIRST = 0 ;etwa wie LMEM_Fixed
LMEM_LAST = 1 ;etwa wie LMEM_MoveAble
iLocalAlloc:
;PE: wie LocalAlloc mit fester Allokations-Strategie
mov dh,LMEM_FIRST
proc LocalAlloc pascal
;PE: AX=geforderte Speichermenge in Bytes
; DH=Allokations-Strategie
;PA: CY=1: kein Speicher mehr frei!
; CY=0 und DI=Zeiger auf Speicherblock (fertig fr STOSx)
;VR: CX,DI,DH,AX(=tats„chliche Alloc-Gr”áe inkl. Gr”áen-WORD)
uses bx,si
;## auf 4-Byte-Stckelung aufrunden, dazu 2 Bytes fr GrӇen-Merker
add ax,5
and al,not 3
mov si,[LocalHeap]
xor di,di
@@l2: mov cx,si
mov si,[si] ;di=erster (oder weiterer) Freispeicher
or si,si ;Ende erreicht?
jz @@r
cmp [si+2],ax ;Block hat genug Platz?
jc @@l2 ;nein, n„chsten Freispeicher suchen
mov bx,cx ;Kandidat gefunden: BX=Vorheriger Freispeicher
mov di,si ;Kandidat gefunden: DI=Jetziger Freispeicher
test dh,1
jnz @@l2
@@r:
cmp di,1
jc @@nomem
mov cx,[di+2]
sub cx,ax
jz @@ganz ;Block ganz aufbrauchen (aush„ngen)
;## Zeigerkette bearbeiten
test dh,1
jnz @@hinten
mov si,di
add di,ax ;auf neue Position
mov [bx],di
movsw ;Next-Pointer
mov [di],cx ;neue (kleinere) GrӇe
lea di,[si-2]
jmp @@1
@@hinten:
mov [di+2],cx ;neue (kleinere) GrӇe eintragen
add di,cx ;Hier ist unser Speicher
jmp @@1
@@ganz:
mov si,[di] ;Next-Pointer holen
mov [bx],si ;am vorhergehenden Knoten einsetzen
@@1: stosw ;GrӇe allozierter Block eintragen
ret
@@nomem:mov [LastError],4 ;"not enough memory"
ret
endp
proc JoinMem
;FU: Zwei Freispeicher zusammenziehen, wenn m”glich
;PE: DI=Zeiger auf ersten Freispeicher
;VR: AX,SI,DI
mov si,[di]
mov ax,[di+2]
add ax,di
cmp si,ax ;k”nnen zusammengezogen werden?
jne @@e ;nein (CY=1: fataler Fehler!)
movsw ;Next-Pointer vorziehen
lodsw
add [di],ax ;GrӇen addieren
@@e: ret
endp
proc FreeDIPtr
;PE: DI=Zeiger auf WORD mit dem Heap-Zeiger
;PA: PWORD nullgesetzt, CY=1: ungltiger oder Null-Zeiger
;VR: AX,CX,DI
xor ax,ax
XchgDIPtr:
xchg [di],ax
LocalFreeAX:
xchg di,ax
;jmp LocalFree
endp
proc LocalFree pascal
;PE: DI=Speicherblock-Zeiger
;## "Freispeicher-Umgebung" auf m”gliche "Blasenbildung" abtesten,
;## dabei ggf. nach vorn UND nach hinten verbinden!
;PA: CY=1: Versuch, freien Speicher freizugeben (m.a.W.: ungltiger Zeiger)
;VR: AX,CX
uses bx,si
sub di,2 ;auf das GrӇen-WORD
jc @@e ;war wohl NIL-Zeiger
mov cx,[LocalHeap]
@@l: mov bx,cx
mov cx,[bx]
jcxz @@nomem ;wird einziger oder letzter Freispeicher!
cmp cx,di
jc @@l ;wenn hier Gleichheit rauskommt, w„r's Fehler!
stc
jz @@e
@@nomem:
mov ax,[bx+2] ;GrӇe des Vorblocks
add ax,bx
cmp di,ax ;DI muss nun grӇer/gleich AX sein
jc @@e ;sonst: Versuch der Freigabe von freiem Speicher
mov [bx],di
xchg [di],cx
mov [di+2],cx ;nun CX=GrӇe Speicherblock
call JoinMem ;rechts
mov di,bx
call JoinMem ;links
@@e: ret
endp
;LocalInit -> see transient code area!
proc IncInDosFlag
push ax
mov al,1 ;modified by "i" switch
InDosFlagInc = by $-1
jmp @@1
DecInDosFlag:
push ax
mov al,-1 ;modified by "i" switch
InDosFlagDec = by $-1
@@1: push ds
push 8086 ;modified by installation
InDosFlagSeg = wo $-2
pop ds
lahf
add [8086],al ;modified by installation
InDosFlagOfs = wo $-2
sahf
pop ds
pop ax
ret
endp
;============ cutting line, CDROM only code follow this line ================
;content of link table:
;1.WORD=Anzahl Verzeichnisse (n)
;2..n+1.DWORD: ISO-Sektornummern
;n+2..2n+1.DWORD: Joliet-Sektornummern
;**************************
;** CDROM initialization **
;**************************
CD_VD_ID db 'CD001',1 ;Erkennung fr ISO-Volume
JLT$: dz '.JLT' ;Erweiterung fr Link-Tabelle
proc IoctlRead
;FU: Fhrt einen "IOCTL READ" auf das CD-Laufwerk aus
;PE: BX=Pufferzeiger (28+7 Bytes)
; CX=Laufwerk (0=A:)
; DX=1. und 2. Byte des Datenpuffers
;PA: DI=BX+30 (hinter dem 2. Byte des Puffers)
; CY=1 bei Fehler
;VR: AX,DX,DI
push cx
mov di,bx
mov ax,28
stosw ;len,sub
mov al,3
stosw ;cmd,LOBYTE(status)
mov al,0
mov cl,5
rep stosw ;HIBYTE(status)..mediadescriptor
lea ax,[bx+28]
stosw ;LOWORD(bufferptr)
mov ax,es
stosw ;HIWORD(bufferptr)
mov ax,7
stosw ;buffersize
mov al,0
mov cl,4
rep stosw ;startsector, volumeptr
xchg ax,dx
stosw
pop cx
MUX 1510h
mov al,[bx+4]
add al,al ;shift out ERROR bit (status bit 15)
ret
endp
proc DetermineVolStart
;FU: Wo ist der Anfang der letzten Session?
; (MSCDEX liefert diese Info leider NICHT bei Int2F/1505!)
;PE: CX=Laufwerk (0=A:)
;PA: CY=1 Fehler
; CY=0: EAX=Volume-Start
;VR:
mov bx,ofs Sektor
mov dl,10 ;GetAudioDiskInfo
call IoctlRead
jc @@e
mov dx,[bx+28+1] ;dl=first, dh=last
@@l: push dx
mov dl,11 ;GetAudioTrackInfo
call IoctlRead
pop dx
jc @@e
test [by bx+28+6],40h ;Data track?
jnz @@ok
dec dh ;from back to front
cmp dh,dl ;(at least MSCDEX hides all non-last sessions
jnc @@l ; and returns first==last)
@@e: ret
@@ok:
mov al,60
imul [by bx+28+4] ;min
xchg dx,ax
mov al,[bx+28+3] ;sec
sub al,2
cbw
add ax,dx
cwde
imul eax,75
movsx edx,[by bx+28+2] ;frame
add eax,edx
cd_init_retu:
ret
endp
proc CD_Init ;HIER GIBTS ARBEIT
;weitere Informationen per Sektorzugriff beschaffen!
;Solange Volume-Deskriptoren einlesen, bis Schluss-Deskriptor...
;FU: CD (als solche) und Joliet-CD erkennen
;PE: CX=Laufwerk (0=A:)
;PA: CY=1: Fehler, kein MSCDEX, kein CD-Laufwerk oder eben kein Joliet
call DetermineVolStart
jc cd_init_retu ;Sprungdistanz klein halten
add eax,15
mov [CurSector],eax ;beginnend mit erstem Volume-Deskriptor
or [DriveType],DT_CDFS
@@next_vtoc:
call ReadNextSec ;n„chstes VTOC
jc @@e ;nichts zu lesen!
mov si,ofs CD_Sektor
lodsb
mov di,ofs CD_VD_ID
push cx
mov cl,3 ;CH (Laufwerk) sowieso 0
rep cmpsw ;gleiche ID enthalten?
pop cx
jne @@err ;falscher Aufbau der VTOC
dec al
jz @@p
dec al
jz @@s
sub al,0FDh ;war FFh?
jnz @@next_vtoc ;alle anderen Deskriptoren ignorieren
jmp @@last ;FF = Abschluss
@@p: ;PVD gefunden!
add si,40-7 ;Datentr„gerbezeichnung
mov di,[argv0file]
mov dx,821h
@@next: dec dl
jz @@ends
lodsb
cmp al,'0'
jb @@next
cmp al,'9'
jbe @@take
cmp al,'A'
jb @@next
cmp al,'Z'
ja @@next
@@take: stosb
dec dh
jnz @@next
@@ends: mov si,ofs JLT$
call strcpy
lea di,[Medium.jol.isotree]
mov al,0
jmp @@gem ;zur gemeinsamen "Datenrettung"
@@s: ;SVD gefunden!
add si,88-7
lodsw
cmp ax,'/%' ;Joliet-SVD?
jne @@next_vtoc ;nein, diesen ignorieren
lodsb
cmp al,'@'
je @@jo
cmp al,'C'
je @@jo
cmp al,'E'
jne @@next_vtoc
@@jo: lea di,[Medium.jol.joltree]
mov al,DT_DrvPar
@@gem:
or [DriveType],al
mov eax,[CurSector]
stosd
lea bx,[(CD_Sektor+156)] ;Hauptverzeichnis Little Endian
call CD_RetrieveDirInfo ;Rootsektor und L„nge bertragen
jmp @@next_vtoc
@@last:
cmp [DriveType],(DT_CDFS or DT_DrvPar) ;Beide Deskriptoren OK?
je @@read_jlt
@@err: stc
@@e: ret
@@read_jlt:
mov dx,[argv0]
DOS 3D00h ;open .JLT file (can recurse!)
jc @@nojlt
xchg bx,ax
mov dx,ofs CD_Sektor
mov cx,8
DOS 3Fh ;_lread
cmp [dword CD_Sektor],4
jne @@cl
mov ax,[wo CD_Sektor+4]
push ax
shl ax,3
push ax
add ax,2
call iLocalAlloc
pop cx
pop ax
jc @@cl
mov [Medium.jol.linktbl],di
stosw
mov dx,di
DOS 3Fh ;_lread
@@cl:
pushf
DOS 3Eh ;_lclose
popf
ret
@@nojlt:
cmp [CurSector],32 ;Erste Session?
jnc @@will_nicht ;Link-Tabelle ist (sicherlich) falsch!
call ReadNextSec ;Nachfolgenden Sektor lesen (ist Link-Tabelle!?)
mov si,ofs CD_Sektor
lodsw
cmp ax,'eC' ;start of "CeQuadrat"
jne @@will_nicht
add si,2Ch-2
lodsd ;Anzahl Verzeichnisse
mov bx,ax
shl bx,2 ;DWORD-Offset
push ax
mov ax,bx ;8 Bytes pro Verzeichnis
inc ax ;und 2 Bytes fr die Anzahl
add ax,ax
call iLocalAlloc
pop ax
jc @@ex ;Speichermangel!!
mov [Medium.jol.linktbl],di
stosw
mov cx,ax
jcxz @@ex ;Tempor„re Notbremse
@@l:
lodsd ;Joliet
mov [di+bx],eax ;hinten
movsd ;ISO vorn
loop @@l ;Link-Tabelle OK
@@ex: ret
@@will_nicht:
mov [LastError],3 ;"can't find link table"
stc
ret
endp
proc CD_Done
call Check_CDFS
jz @@e
lea di,[Medium.jol.linktbl]
call FreeDIPtr
@@e: ret
endp
;******************
;** CDROM access **
;******************
proc CD_CheckRootDot
;06/02: filter out "." and ".." entries from root directory
;PE: BX=CD_DirEnt-Zeiger
; [CurSector]=momentaner CD-Sektor
;PA: CY=0: Ist "." oder ".." im Hauptverzeichnis, dazu Z=0 (no match)
; CY=1: Ist nicht der Fall
;VR: -
push eax
mov eax,[CurSector]
cmp eax,[Medium.jol.isotree.rootdir]
je @@1
cmp eax,[Medium.jol.joltree.rootdir]
@@1: pop eax
stc
jne @@e
cmp [(TCD_DirEnt bx).fnamelen],1
stc
jnz @@e
cmp [(TCD_DirEnt bx).fname],2
cmc
@@e: ret
endp
proc CD_check_updir
;FU: L„dt SI auf Name-Zeiger
; Testet auf '.' und '..' (L„nge 1 und Name=(bin„r)0 bzw. (bin„r)1)
;PE: BX=CD_DirEnt-Zeiger
; DI=wo der Name hin soll
;PA: CY=0: normales DirEnt,
; AL=L„nge Name (in Bytes)
; SI=Zeiger Name in CD_DirEnt
; VR: SI,AL
; CY=1: DirEnt='.' oder '..'
; [DI] gefllt mit "." oder ".." (noch nicht nullterminiert!)
; VR: SI,DI,AL=0
lea si,[(TCD_DirEnt bx).fnamelen]
lodsb
cmp al,2 ;L„nge 1?
jnc @@e
cmp [by si],2 ;Null oder Eins?
jnc @@e
lodsb
or al,al ;Null?
mov al,'.'
stosb
jz @@1
stosb ;Zwei Punkte wenn's 1 war
@@1: add al,-'.' ;AL=0 und CY setzen
;stosb
@@e: ret
endp
;proc CD_Prepare_CX
;FU: Hilfsroutine
;PE: AL=Zeichenzahl (ASCIIs oder UNICODEs)
; BX=PCD_DirEnt
;PA: CX=Zeichenzahl (bei Dateinamen gekrzt um 2 fr ";1"-Anh„ngsel)
; mov ah,0 ;gegenber CBW: Katastrophenschutz!
; xchg cx,ax ;Zeichen-Z„hler in CX
; test [(TCD_DirEnt bx).flags],2 ;Verzeichnis?
; jnz @@e ;ja, nicht krzen!
; sub cx,2
;@@e: ret
;endp
proc CD_Longname
;Kopiert Joliet-Namen des Directory-Eintrags BX in [Longname]
;Vereinfachende Annahme: Verzeichnisse haben kein Anh„ngsel,
;Dateien haben immer das Anh„ngsel ";1" (Versionsnummer)
;PE: BX=CD_DirEnt-Zeiger
;PA: SI=ofs Longname (also fertig fr Vergleich)
;VR: AX,CX,SI,DI
mov di,ofs Longname
push di
call CD_check_updir
jc _termAL
shr al,1 ;bei CY=1 offensichtlich Fehler, ignorieren
movzx cx,al
@@l: lodsw
call BE_Uni2Oem ;hier: Motorola-Interpretation
; call IsInvalidLfnChar
; jz @@1
; stosb
@@1: loopnz @@l
jmp _terminate
endp
proc CD_Shortname
;Kopiert ISO-Namen des Directory-Eintrags BX in [ShortName]
;Da Zeichen >80h ohnehin nicht ISO-konform sind, werden sie vereinfachend
;als OEM angenommen
;Vereinfachende Annahme: Verzeichnisse haben kein Anh„ngsel,
;Dateien haben immer das Anh„ngsel ";1" (Versionsnummer), also 2 Zeichen
;PE: BX=CD_DirEnt-Zeiger
;PA: SI=ofs ShortName (also fertig fr Vergleich)
;VR: AX,CX,SI,DI
mov di,ofs ShortName
push di
call CD_check_updir
jc _termAL
MIN al,20 ;Notbremse!! Nicht perfekt!!
;Besser: Krzung (TRUENAME) zu 8.3
movzx cx,al
rep movsb ;String einfach schaufeln
_terminate:
BTST [(TCD_DirEnt bx).flags],2 ;Verzeichnis?
jnz @@1 ;Nicht auf "Version" prfen
mov al,[di-1]
sub al,'1'
cmp al,9
jnc @@1 ;keine Ziffer 1..9
cmp [by di-2],';' ;KANN schiefgehen, wenn nur 1 Ziffer!
jne @@1
dec di
dec di
@@1: xchg cx,ax ;effektiv AX=0
_termAL:
stosb ;Null-Terminierung
pop si
ret
endp
proc CD_Get_Attr
;FU: Liefert DOS-Attribut fr CD-Verzeichniseintrag
; Liefert nur die Bits DIRECTORY (10h), HIDDEN (02h) aus DirEnt
; und READONLY (01h) aus ctrl-Bit
;PE: BX=CD_DirEnt-Zeiger
;PA: AL=AX=Attribut
;VR: AX (AH=0)
mov al,[(TCD_DirEnt bx).flags]
mov ah,0
shl al,6
add ax,ax ;DIR-Bit einschieben
shl ah,2 ;dazwischen 2 Bit Luft
add ax,ax ;HIDDEN-Bit einschieben, jetzt AL=0
test ah,8 ;Directory?
jnz @@1 ;niemals schreibgeschtzt wie MSCDEX
bt [wo ctrl],1 ;CTRL_RoBit-->CY
@@1: xchg ah,al
adc al,al ;RO-Bit einschieben (je nach Vorgabe)
ret
endp
proc shld_proc
shl edx,cl
or dl,al
lodsb ;gleich n„chstes Element holen
ret
endp
proc CD_Get_Time
;FU: Liefert DOS-Zeit von CD (das ist i.d.R. die Zeit der letzten Žnderung)
;PE: BX=CD_DirEnt-Zeiger
;PA: EAX,DL=Zeit im DOS-Format (DH=Zeitzone)
;VR: EAX,EDX
push si bx cx
lea si,[(TCD_DirEnt bx).year]
mov bx,ofs shld_proc
lodsb ;Jahr (seit 1900)
sub al,80 ;1980-1900
mov cl,7
call bx ;7 Bits fr's Jahr
mov cl,4 ;Monat 4 Bits
call bx
inc cl ;Tag 5 Bits
call bx
call bx ;Stunde auch 5 Bits
inc cl ;Minute 6 bits
call bx
shr al,1 ;Sekunde in 2-s-Schritten
sbb ah,ah ;CY in AH 8x retten
dec cl ;Sekunde 5 bits
call bx
xchg ah,al
and al,100 ;entweder 0 oder 100 (dezimal!)
xchg edx,eax
pop cx bx si
ret
endp
proc SetSuchSektor_LFN
;PE: BX=DirEnt-Zeiger ISO
;PA: [SuchSektor]=EAX=zu suchender Joliet-Sektor
;VR: EAX,CX
db 0B9h ;mov cx,nnnn
SetSuchSektor_SFN:
;PE: BX=DirEnt-Zeiger Joliet
;PA: [SuchSektor]=EAX=zu suchender ISO-Sektor
;VR: EAX,CX
xor cx,cx ;2 bytes
mov eax,[(TCD_DirEnt bx).sect]
BTST [(TCD_DirEnt bx).flags],bit 1
jz @@e ;don't search for files!
push di bx
mov di,[Medium.jol.linktbl]
mov bx,[di]
shl bx,2 ;DWORDs (changes flags) = offset between
or cx,cx
mov cx,[di]
jnz @@1
add di,bx
neg bx
@@1: inc di
inc di
repne scasd ;fast scan for sector
jne @@2 ;if not found (error!)
mov eax,[di+bx-4] ;get the companion
@@2: pop bx di
@@e: mov [SuchSektor],eax
ret
endp
proc CD_Make_Volume_Label
;Jede CD habe ein Volume Label... oder?
mov eax,[Medium.jol.joltree.voldesc]
call ReadSecEAX
call InitFill
mov al,8 ;Attribut "Volume Label"
stosd
mov al,ah
mov cx,20
rep stosw ;10 DWords nur Nullen
mov si,ofs CD_Sektor+28h
@@l: lodsw
call BE_uni2oem ;"langes" Label (ist nullterminiert)
jnz @@l
LD es,ds
call Alloc_Find_Handle
mov [Search.jol.j.entry],ofs CD_Sektor ;zurckstellen!
call PutValues
clc
ret
endp
proc CD_RetrieveDirInfo
;PE: BX=CD-Verzeichniseintrag
; DI=Struktur aus Sektor (DWORD) und Anzahl (WORD)
;VR: EAX,DI (um 6 nach hinten)
mov eax,[(TCD_DirEnt bx).sect]
stosd
mov eax,[(TCD_DirEnt bx).fsize]
shr eax,11 ;genauer: durch Sektorl„nge (krumm!) teilen
stosw
ret
endp
proc CD_LFN_Follow
test [PFlags],PF_Follow
jz @@1
push di
lea di,[Search.jol.j.sect]
call CD_RetrieveDirInfo
pop di
@@1: mov [Search.jol.j.entry],bx
ret
endp
proc CD_SFN_Follow
test [PFlags],PF_Follow
jz @@1
push di
lea di,[Search.jol.i.sect]
call CD_RetrieveDirInfo
pop di
@@1: mov [Search.jol.i.entry],bx
ret
endp
proc CD_LoadDirInfoFull
;PE: SI=Struktur aus Sektor (DWORD) und Anzahl (WORD)
;PA: BX, [CurSector] und [CD_Residual] gefllt
lodsw ;Sektorzeiger
xchg bx,ax
lodsd
mov [CurSector],eax
lodsw
mov [CD_Residual],ax
ret
endp
proc CD_SaveDirInfoFull
;PE: DI=Struktur aus Sektor (DWORD) und Anzahl (WORD)
mov ax,bx
stosw
CD_SaveDirInfo:
mov eax,[CurSector]
stosd
mov ax,[CD_Residual]
stosw
ret
endp
proc CD_LFN_Load
;PA: BX, [CurSector] und [CD_Residual] mit Joliet-Suchdaten gefllt
push si
lea si,[Search.jol.j]
call CD_LoadDirInfoFull
pop si
ret
endp
proc CD_SFN_Load
;PA: BX, [CurSector] und [CD_Residual] mit ISO-Suchdaten gefllt
push si
lea si,[Search.jol.i]
call CD_LoadDirInfoFull
pop si
ret
endp
proc CD_Ping_DirScan
;FU: Bei CDFS muá zweimal gesucht werden! Entweder von lang nach kurz
; (Regel) oder von kurz nach lang (Sonderfall)
;PE: BX=Vergleichsmethode fr DirScan [GLOBBING reicht eigentlich!]
;PA: CY=1 fataler Fehler
; CY=0 und Z=0: Nicht gefunden
; CY=0 und Z=1: gefunden
push bx
call CD_LFN_Load ;setze Suchdaten auf Joliet (warum BX verwerfen?)
pop bx
call DirScan
jc @@e
call CD_LFN_Follow ;Falls n„chstes Verzeichnis...
call SetSuchSektor_SFN
call CD_SFN_Load
mov bx,ofs Match_CD_Sectorpointer_Proc
call DirScan ;mit DX=Nummer
jc @@e ;Fehler! (Konsistenzfehler)
call CD_SFN_Follow
call CD_Shortname
clc
@@e: ret
endp
proc CD_Pong_DirScan
;PA: CY=1 fataler Fehler oder nicht gefunden
; CY=0 gefunden
push bx
call CD_SFN_Load
pop bx
call DirScan
jc @@e
call CD_SFN_Follow
call SetSuchSektor_LFN
call CD_LFN_Load
mov bx,ofs Match_CD_Sectorpointer_Proc
call DirScan ;mit DX=Nummer
jc @@e ;Fehler!
call CD_LFN_Follow
call CD_Longname
clc
@@e: ret
endp
proc CD_Next_DirEnt
add bl,[(TCD_DirEnt bx).r]
adc bh,0
cmp bx,ofs CD_SektorEnde
jnc @@cknext
cmp [(TCD_DirEnt bx).r],SIZE TCD_DirEnt ;sector not filled up?
jnc @@e
@@cknext:
dec [CD_Residual] ;sector follows?
stc
jz @@e
call ReadNextSec ;hier keine FAT-Žrgernisse!
mov bx,ofs CD_Sektor
@@e: ret
endp
proc CD_NextDirScan_Circular
push bp
mov bp,sp
push [CurSector] ;bp-4
push bx ;bp-6
call ReadSec
jc @@e
mov bx,[bp-6] ;der DirEnt-Zeiger
jmp @@2
@@l: call [MatchPtr]
jbe @@e ;bei CY=1 (Fehler) oder Z=1 (gefunden)
@@2: call CD_Next_DirEnt
jnc @@1
mov eax,[Search.jol.restart]
call ReadSecEAX
mov bx,ofs CD_Sektor
jc @@e
mov ax,[Search.jol.restlen]
mov [CD_Residual],ax
@@1: cmp bx,[bp-6]
jne @@l
mov eax,[CurSector]
cmp eax,[bp-4]
jne @@l
stc
@@e: leave
ret
endp
proc Match_CD_Sectorpointer_Proc
;Nicht einfach DirEnts (DX) abz„hlen!
cmp [(TCD_DirEnt bx).r],SIZE TCD_DirEnt
jc @@e
mov eax,[SuchSektor]
cmp eax,[(TCD_DirEnt bx).sect] ;Treffer?
clc
@@e: ret
endp
proc Glob_CD_LFN_Proc
;Bug oder Feature? Unter Win9x trifft der Suchausdruck "*1" sowohl
;"Programme von 1991" (LFN) als auch "WURSTE~1" (SFN fr "Wurstegal")
;Wegen der Bereitstellung beider Namen erfordert die Funktion
;FindFirst/FindNext das st„ndige Bereithalten zweier Sektoren.
;Aber leider ist die Reihenfolge der DirEnts nicht zwangsweise gleich:-(,
;sodass der Aufwand, um ein DirEnt nicht zweimal zu finden, immens steigt!
mov ax,ofs CD_Longname
cmp [(TCD_DirEnt bx).r],SIZE TCD_DirEnt
jc @@e
call CD_CheckRootDot ;12/02
jnc @@e
call ax
call CD_Get_Attr
call Match_Attr
jnz @@e
call GlobbingEx
@@e: ret
endp
;================ common buffer (to be moved into heap) ================
align 2
tunnel dw 0 ;Zeiger auf Tunnel-Info (muss initialisiert sein!)
tunnel2 dw 0 ;Kopie fr MOVE-Vorgang
label Residente_Puffer byte
union TMedium
jol TDI_JOL <> ;all specific medium Information
ends
Medium TMedium <>
union TSearch
jol TFI_JOL <> ;all file find information
ends
Search TSearch <>
SearchAttr dw ? ;Such-Attribut, enth„lt im Low-Teil
;die invertierten Attribut-Flags und im High-Teil die
;Must-Match-Attribute. Das Attribut 88h dient (sp„ter) dem
;Aufsuchen gel”schter Eintr„ge wie bei Novell-DOS
MatchPtr dw ? ;"Virtuelle" Methode Match&Stop
SuchSektor dd ? ;fr gegenseitige Suche auf Joliet-CD
;auch: Start-Sektor Ziel-Vrz. bei mkdir, creat und move
num_cluster dw ? ;Anzahl Cluster fr Verzeichnis
subst_root dw ? ;Anzahl Zeichen fr SUBST
;in Truename: Zeiger in LongBuffer, normal LongBuffer+2
throw_fi dw ? ;Zeiger auf Exit-Behandlung (wegen lfn_move)
CD_Residual dw ? ;count of directory sectors
;fastopen_cache
fastopen_ptr dw ?
fastopen_buf db 280 dup (?) ;L„nge: 64+13 +256 +16*4: zu kurz!
;diverse Puffer
longname db 256 dup (?) ;Puffer fr LFN von NextDirEnt()
db 256+28 dup (?) ;Platz fr Unicode-LFN (Heap!!)
longbuffer db 260 dup (?) ;Zwischenpuffer fr Zerlegung/TRUENAME
label longbuffer_end byte
db ? ;1 Byte hier spart 6 Bytes im Code
alignv 4
Sektor db 512 dup (?) ;0.5K Platz fr Festplattensektor
label SektorEnde byte
Alloc_Cluster_SFN db 3+13 dup (?) ;(tempor„rer) Dateiname
Alloc_Cluster_FCB db 1+11+4 dup (?) ;unge”ffneter FCB - fr Alloc_Cluster
DefLocalHeap_FATONLY dw 2 dup (?)
ISRE_FATONLY:
; org Sektor
;cbsize dw ? ;nur fr GetDrvParam (FAT32)
;dpb TExDPB <?> ;nur fr GetDrvParam (FAT32)
org Sektor
;nur fr Rckfallmodus benutzt
old_dta dd ?
dta TSearchRec <?>
org Sektor
CD_Sektor db 2048 dup (?) ;2K fr CDFS-Sektor
label CD_SektorEnde byte
CD_Backup db 2048 dup (?)
CD_BackupSektor dd ?
DefLocalHeap dw 2 dup (?)
ISRE:
;==========================================================================
org Residente_Puffer ;keine Null-Orgien!
;==== BEGIN CRITICAL INITIALIZATION SECTION - MUST OVERLAY BUFFERS ====
String_Table dw ?
LocalHeapSize dw ? ;Angabe bei /M
WorkDir dd ? ;Arbeitsverzeichnis: .JLT/.TBL/.386 (/P)
proc LocalInit pascal
;PE: AX = size of local heap in bytes, including four "wasted" bytes
; DI = start address of local heap
add ax,0Fh ;Bis zum Paragrafen-Ende aufrunden
add ax,di
jnc @@1
mov ax,0fff0h ;begrenzen auf berechenbare 64K-16
@@1: shr ax,4
xchg bx,ax
DOS 4Ah ;Speicherblockgr”áe ver„ndern
jnc @@2
DOS 4Ah ;noch einmal (bei Fehler max. GrӇe so!)
@@2: xchg ax,bx
shl ax,4 ;wieder Bytes
sub ax,di
BRES ax,3 ;in 4-Byte-H„ppchen abrunden! (Unn”tig)
mov [LocalHeap],di
mov [LocalHeapSize],ax
push ax
lea ax,[di+4]
stosw ;Erster Freispeicher-Zeiger
xor ax,ax
stosw ;strategische Null
;verhindert auf einfache Weise das ungewollte "Zusammenfassen nach links"
stosw ;NIL-Pointer, kein weiterer Freispeicher
pop ax
sub ax,4
stosw ;Zusammenh„ngender Freispeicher
ret
endp
proc CopyWorkDir
;Kopiert [WorkDir] nach ES:DI und h„ngt ein Backslash dran,
;PA: DI=Zeiger hinter Backslash
push es
push di
push [WorkDir]
call fstrcpy ;liefert glcklicherweise AX=Zeichenzahl
add di,ax
mov al,'\'
stosb
ret
endp
proc CriticalInit
;"Kritischer Abschnitt" der Initialisierung (wegen Speicher-šberlappungen)
call LocalInit
;Arbeitsverzeichnis in Heap kopieren
push [WorkDir] ;gleich als DWord!
call fstrlen
add ax,14
call iLocalAlloc
jc @@noload ;darf hier nie passieren!
mov [argv0],di
call CopyWorkDir
mov [argv0file],di
;Unicodetabelle automatisch oder wie angefordert laden (nach Heap-Init!)
mov dx,0
UserUniFile = wo $-2 ;Angabe bei /Z
or dx,dx
jnz @@userload ;Von Hand laden
DOS 6601h
jc @@noload ;DOS weiá nichts ber Codeseiten
push [argv0] ;Dateiname (mit Pfad) fr Fehlermeldung
call LoadCP
jmp @@el1
@@userload:
push dx ;fr Fehlermeldung
call LoadUniFile
@@el1: jnc @@el2
call AusgabeStringNr
call AusgabeNL
@@el2: pop dx
@@noload:
;Zeiger verbiegen (Int21 und Int2F)
mov dx,ofs NewInt21
DOS 2521h ;Set Int21
mov dx,ofs NewInt2F
mov al,2Fh
DOS ;Set Int2F
;Environment freigeben
push es
mov es,[2ch] ;Segment Environment
DOS 49h ;ENV-Speicher ab es freigeben
pop es
;Test des Hochladens und Anzeige
mov ax,cs
cmp ah,0a0h
mov bl,1 ;$HOCH
jc @@NoHi ;unten
call AusgabeStringNr
@@NoHi: inc bl ;Installiere
;DosLFN aktivieren und Speicherverbrauch anzeigen
Activate:
or [es:Ctrl0],80h ;setzen
mov ax,[LocalHeap]
add ax,[LocalHeapSize]
add ax,4+1Fh ;hier: inklusive MCB
BRES ax,0Fh
;BL-numerierten Text ausgeben
P8086
TXTOut: push ax
call AusgabeStringNr ;Textausgabe
pop ax
;Programm beenden
mov bh,bl
call AusgabeNL
cmp bh,2 ;Meldung "Resident"?
jnz @@exi ;nein, normales Programmende
P386
mov dx,[LocalHeap]
add dx,[LocalHeapSize]
shr dx,4 ;Speicherbedarf in Paragrafen umrechnen
DOS 3100h ;Resident beenden
@@exi:
P8086
call PrintLastError
DOS 4C00h
endp
proc LoadString
;FU: String-ID (BL) in String-Zeiger (SI) und L„ngen-Info (CX) umsetzen
;VR: AX,BL,CX,SI
push es di
inc bl
xor al,al
mov di,[String_Table] ;deutsch oder englisch
LD es,ds
@@l: mov si,di ;immer Anfang merken
mov cx,-1
repne scasb ;Null suchen und L„nge bestimmen
dec bl
jnz @@l
not cx
dec cx ;jetzt CX=String-L„nge
pop di es
ple_ret:ret
endp
proc PrintLastError
;PE: ES = resident segment
;PA: LastError=0
;VR: AX,BL
xor ax,ax
xchg [es:LastError],al
or al,al
jz ple_ret
mov bl,FIRSTERRORSTRING
push ax
call AusgabeStringNr ;"Fehler: %d "
pop ax
add bl,al
call AusgabeStringNr ;Fehlerbeschreibung
; jmp AusgabeNL
;@@e: ret
endp
;*****************************
;** printf() Marke Eigenbau **
;*****************************
P286
AusgabeNL:
mov bl,0
proc AusgabeStringNr c
;FU: String aus String-Tabelle mit Nummer BL ausgeben,
; dabei Formatierung mit einer Mini-PRINTF-Funktion und 0A->0D0A-Expansion
local @@numberpuffer:BYTE:34,@@flags,@@space,@@preci
pusha
call LoadString
push es
LD es,ds
mov di,ofs printf_buffer
lea bx,[bp+4]
@@l: lodsb
or al,al
jz @@e
cmp al,'%'
je @@esc
cmp al,0ah
je @@0a
stosb
jmp @@l
@@0a:
mov ax,0a0dh
stosw
jmp @@l
@@esc:
xor ax,ax
mov [BP-6],ax
mov [BP-4],ax
mov [BP-2],ax
call EasyPrintfHandler
jmp @@l
@@e:
mov cx,di
mov dx,ofs printf_buffer
sub cx,dx ;Anzahl Zeichen
mov bx,1 ;stdout
DOS 40h ;schreiben (BlockWrite)
pop es
popa
ret
endp
;************ PRINTF: Komplette %-Behandllung ***************
SwitchChars db 'LFNhl0.-+# '
P386
proc PreprocessHandler
;NUR FšR TINY-MODELL und 386
;verarbeitet eine Sequenz, zum Verketten gemacht!
;Kann alle Pr„prozessor-Sachen: #,0,-,*,Feldbreite,Pr„zision,h,l,N,F
;
;PE: DS:SI=Eingabedaten
; ES:DI=Ausgabedaten
; SS:BP-8=PRINTF-Daten: OLen,Flags,Space,Precis
; SS:BX=Externe Daten (hier: fr "*"-Feldbreiten-Platzhalter)
;PA: DS:SI->da geht's weiter
; AL=(unbekanntes) Zeichen
; CY=1 = konnte kein End-Zeichen umsetzen
@@l: lodsb
mov cx,11
push di
mov di,ofs SwitchChars
repne scasb ;any known switch character?
pop di
jne @@nf
bts [bp-6],cx
jmp @@l
@@nf:
cmp al,'*'
je @@st
cmp al,'0'
jc @@gu
cmp al,'9'
ja @@gu
@@nu: ;scan the number
dec si
push bx
mov bx,10
call inw ;DS:SI->AX, DS:SI moved forward
pop bx
jmp @@nu0
@@st:
mov ax,[bx] ;get number from arglist
inc bx
inc bx
@@nu0:
test [by bp-6],bit 4
jnz @@pr
mov [bp-4],ax ;field width
jmp @@l
@@pr:
mov [bp-2],ax ;precision (not used if prec bit not given)
jmp @@l
@@gu: ;give up, unknown character (including zero)
ret
endp
proc printf_FillChar
;PE: AX=number of characters
xchg cx,ax
mov al,' '
test [by bp-6],bit 5
jz @@1
mov al,'0'
@@1: rep stosb
ret
endp
proc printf_strlen
;PE: DS:SI=String, AX=MaxLen (=precis oder 0FFFFh)
push di
mov di,si
mov cx,ax
push ax
mov al,0
repne scasb
inc cx
pop ax
sub ax,cx
pop di
ret
endp
proc printf_postfill
xor [by bp-6],bit 3 ;Bit kippen
endp
proc printf_prefill
;PE: AX=auszugebende Zeichenzahl
test [by bp-6],bit 3
jnz @@e ;left aligned: do nothing!
fill0:
push ax
sub ax,[bp-4]
jnc @@e0
neg ax ;free width
call printf_FillChar
@@e0: pop ax
@@e: ret
endp
proc printf_itoa
;BL=Zahlenbasis; negativ wenn Zahl vorzeichenbehaftet
;EAX=Zahl
;[BP-6]=Flags, Bit 15=1 fr groáe Hex-Buchstaben
;DI=ASCII-Puffer
;PA:DI=Ende Puffer (nicht terminiert!)
mov dx,[bp-6]
xchg ecx,eax
or bl,bl
jns @@1
neg bl ;jetzt positiv machen
or ecx,ecx
mov al,'-'
js @@putn
test dl,bit 2 ;Merker "+"
mov al,'+'
jnz @@put
test dl,bit 0 ;Merker " "
mov al,' '
jnz @@put
jmp @@1
@@putn: neg cx
@@put: stosb
@@1: test dl,bit 1 ;Merker "#"
jz @@2
cmp bl,8
mov al,'0'
jne @@no_8
stosb
@@no_8: cmp bl,2
mov ah,'b'
je @@do_2
cmp bl,16
mov ah,'x'
jne @@2
@@do_2: stosw
@@2: xchg ecx,eax ;wieder zurck!
xor cx,cx ;Z„hler der PUSHes
movzx ebx,bl
@@l1: inc cx
xor edx,edx
div ebx
push dx ;eine Ziffer
or eax,eax
jnz @@l1
@@l2: pop ax ;herausholen in umgekehrter Reihenfolge
add al,'0' ;(Alternative: Puffer von hinten fllen!)
cmp al,'9'
jbe @@3
add al,7
test [by bp-5],bit 7
jnz @@3
add al,20h ;Kleinbuchstaben
@@3: stosb
loop @@l2
ret
endp
proc EasyPrintfHandler
call PreprocessHandler
cmp al,'%' ;muss als Extrawurst gebraten werden!
je @@perc
push si
cmp al,'s'
je @@s
lea si,[bp-34-6]
cmp al,'c'
je @@c
mov dl,-10
cmp al,'d'
je @@num
cmp al,'i'
je @@num
mov dl,10
cmp al,'u'
je @@num
mov dl,8
cmp al,'o'
je @@num
mov dl,2
cmp al,'b' ;Nicht Standard, aber sehr ntzlich!
je @@num
mov dl,16
cmp al,'x'
je @@num
or [by bp-5],bit 7
cmp al,'X'
je @@num
cmp al,'p' ;Zeiger als groáe Hex-Zahlen ausgeben
je @@num
pop si
dec si
stc
ret
@@perc: stosb
ret
@@num: mov eax,[bx]
test [by bp-6],bit 6
jnz @@long
movzx eax,ax
or dl,dl
jns @@nume
movsx eax,ax
jmp @@nume
@@long: inc bx
inc bx
@@nume: push di bx
mov di,si
mov bx,dx
call printf_itoa
sub di,si ;Anzahl Zeichen
xchg di,ax ;nach AX
pop bx di
jmp @@stout
@@c:
mov si,bx ;Diese Adresse ist Quelle
mov ax,1
jmp @@stout
@@s:
mov ax,[bx]
or ax,ax ;NULL-Pointer?
jz @@stout ;Dann nichts ausgeben!
xchg si,ax
mov ax,0FFFFh
test [by bp-6],4 ;precis given?
jz @@1
mov ax,[bp-2] ;use precis as maximum length!
@@1: call printf_strlen
@@stout: ;Einsprung mit DS:SI=Stringzeiger, AX=String-L„nge
inc bx
inc bx
call printf_prefill
mov cx,ax
rep movsb
call printf_postfill
pop si
ret
endp
printf_buffer = $
;der Hilfe-String ist zwar wesentlich l„nger, aber damit endet das Programm,
;und nachfolgender Code wird nicht mehr benutzt.
Alt_String_Table = $+80 ;einige Strings im "kritischen Bereich"
;==== END CRITICAL INITIALIZATION SECTION ====
;==== dieser Init-Code wird von printf() berschrieben! ====
proc InstChk
;FU: Installations-Test
;PA: Bit7(CH)=0: Installationscheck erfolgreich, dann:
; ES: Segmentadresse der residenten Routine, sonst =DS
; Bit0(CH)=0: Zeiger Int21 nicht von anderen verbogen
; Bit1(CH)=0: Zeiger Int2F nicht von anderen verbogen
; DS:[OldInt21], DS:[OldInt2F]: gelesene Zeiger
;VR: AX,BX,CH,DX(=ES)
;Auáerhalb von InstChk: Bit6(CH)=1 wenn irgendein Schalter akzeptiert
mov dx,REQcode
DOS REQfunc ;Install-Test
xor ch,ch
cmp ax,ANScode ;gleich?
jz @@T21I
BSET ch,bit 7
mov dx,ds
@@T21I:
DOS 3521h ;Get Int21
SES [OldInt21],bx
cmp bx,ofs NewInt21
jnz @@T21FLT
mov bx,es
cmp bx,dx
je @@T21OK
@@T21FLT: inc ch ;Bit 0 setzen
@@T21OK:
DOS 352Fh ;Get Int2F
SES [OldInt2F],bx
cmp bx,ofs NewInt2F
jnz @@T2FFLT
mov bx,es
cmp bx,dx
je @@T2FOK
@@T2FFLT: BSET ch,bit 1
@@T2FOK:
mov es,dx
ret
endp
proc getargv0
;PA: [workdir] gesetzt
; Eigener Programmname auf Pfad ohne Backslash gekrzt
; AX=0
;VR: AX,CX,SI,DI
push es
mov es,[2ch] ;Segment Environment
xor di,di
xor ax,ax
db 0B9h ;mov cx,< irgendeine Zahl > 7FFF >
@@such: repne scasb
scasb
jnz @@such
scasw ;number of "extensions"
jz @@cannot ;no extension (DOS <3)
call set_workdir
mov si,di
repne scasb
dec di
mov al,'\'
std
repne scasb
cld
inc di
mov al,0
stosb ;make a path from file name
@@cannot:
pop es
ret
endp
proc transient
;== 1. Meldung ==
PRINT Text0 ;Meldung sofort
;== 2. Installations-Test ==
call InstChk ;setzt ggf. ES auf Fremdroutine
;nun ch=Statusregister:
;Bit0&1: Deinstallation nicht m”glich
;Bit4: Option Z gegeben
;Bit5: Option M gegeben
;Bit6: Schalter angegeben
;Bit7: Noch nicht installiert
test ch,bit 7
jz @@nostartup ;resident
;== 3. Standard-Sprache festlegen ==
push cx
mov dx,ofs fname_buffer
DOS 3800h ;Land-Info holen
jc @@k
xchg bx,ax ;AX ist besser im Zugriff!
or ah,ah
jnz @@k
cmp al,41 ;Schweiz
je @@de
cmp al,43 ;™sterreich
je @@de
cmp al,49 ;Deutschland
jne @@k
@@de: mov [language],'D'
@@k:
;== 4. argv[0] extrahieren, daraus Pfad fr WorkDir basteln ==
call getargv0
;== 5. Anwesenheit von MSCDEX prfen und Vorgabe stellen ==
xor bx,bx
MUX 15h ;AL=0
or bx,bx
jz @@nomscdex
BSET [ctrl0],CTRL_CDROM
@@nomscdex:
pop cx
@@nostartup:
mov al,[es:language]
call SetStringResourcePointer
;== 6. Kommandozeile parsen und Aktionen durchfhren ==
mov si,81h
cld
;==== HIERHIN DARF DER LŽNGSTE STRING REICHEN! ====
@@scancl:lodsb
call Upcase
push es
push ds
pop es
mov di,ofs cmd_verteiler
call case
pop es
jc @@scancl
call [wo di]
jmp @@scancl
endp
;all diese Routinen drfen SI (oder nur nach weiterer Parameter-
;Auswertung) und CH nicht ver„ndern!
cmd_verteiler: dvt 0dh,Install
dvt '?',help
dvt 'H',help
dvt 'U',UnInst
dvt 'D',DisActiv
dvt 'W',SetWrite
dvt '~',SetTilde
dvt 'T',SetTunnel
dvt 'C',SetCDROM
dvt 'I',SetInDOS
dvt 'R',SetRoBit
dvt 'Z',LoadUni
dvt 'M',SetHeapSize
dvt 'L',SetLang
dvt 'P',SetWorkDir
dvt 'S',ShowStatus
db 0
;**************************************
;* Kommandozeilen-Schalter-Behandlung *
;**************************************
_INW3
proc skip_one_equal_colon_space
lodsb
cmp al,':'
je @@e
cmp al,'='
je @@e
cmp al,' '
je @@e
dec si
@@e: ret
endp
proc Expect_ASCIIZ
;FU: Parst Kommandozeile nach einem Dateinamen
;PE: SI=Zeiger nach Schalterzeichen
;PA: DX=Zeiger auf Dateiname
; SI=Zeiger nach Nullterminierung des Dateinamens
; Kommandozeile fr Nullterminierung modifiziert
call skip_one_equal_colon_space
mov dx,si ;Dateiname (kurz)
@@l1: lodsb
cmp al,21h ;Ende suchen
jnc @@l1
mov [by si-1],0 ;terminieren!
cmp al,0Dh ;war letztes Argument?
jne @@1
mov [si],al ;0Dh verschieben nach hinten
@@1: ret
endp
proc LoadUni
;BE: Unicode-Tabelle im Volkov-Commander-Tabellenformat (siehe TBL.TXT) laden
; Hier noch nicht, erst nach Heap-Initialisierung m”glich!
call Expect_ASCIIZ
mov [UserUniFile],dx
BTST ch,bit 7 ;Resident?
jnz @@ex ;Nein, erst Heap initialisieren!
push dx ;fr Fehlermeldung
DOS 3D00h ;zum Lesen ”ffnen
mov bl,3 ;"Kann nicht ”ffnen"
jc @@e ;Datei nicht gefunden o.„.
push si cx ds
LD ds,es
call ReadUniFile
pop ds cx si
@@e: pop ax
jc TxtOut0
@@ex: BSET ch,bit 4 ;Merker, verhindert Auto-Load
ret
endp
proc SetHeapSize
mov bl,29
test ch,bit 7 ;Installiert?
jz txtout2 ;ja, kann HeapSize (noch) nicht ver„ndern!
call skip_one_equal_colon_space
call InW3 ;Zahl einlesen
mov bl,23
jc txtout0
cmp ax,600 ;1 Sektor und noch etwas Platz (nicht fr CD)
jc txtout0
cmp ax,50000 ;>50KB ist bei 64KB Segment kaum m”glich
ja txtout0
mov [LocalHeapSize],ax
BSET ch,bit 5
ret
endp
proc txtout2
call AusgabeStringNr
mov bl,31 ;Hinweis
txtout0:jmp txtout
endp
proc SetWorkDir
mov bl,28
test ch,bit 7
jz txtout2
call Expect_ASCIIZ
mov bl,27
push cx
mov di,ofs truename_buf
push si
mov si,dx
DOS 60h
pop si
jc txtout0
mov dx,di
DOS 4300h ;attrib->Prfen auf Verzeichnis
jc txtout0
test cl,10h
jz txtout0
push di ;leidiges nachlaufendes Backslash entfernen,
call strlenp1 ;insbesondere wegen Interpretation von
sub di,2 ;"C:\\xyz" als Netzwerkressource xyz!
cmp [by di],'\' ;Auch wenn jetzt nur "C:" brig bleibt,
jne @@1 ;ein Backslash setzt die Software noch dran.
mov [di],ah
@@1: pop di
pop cx
set_workdir:
SES [WorkDir],di
ret
endp
proc SetCDROM ;Schalter fr CD-ROM-Untersttzung
mov bl,30
test ch,bit 7
jz txtout2
mov cl,CTRL_CDROM
jmp SetPlusMinus
endp
proc SetWrite ;Schalter fr Schreibzugriff
mov cl,CTRL_Write
jmp SetPlusMinus
endp
proc SetTilde ;Schalter fr Schlangen
mov cl,CTRL_Tilde
jmp SetPlusMinus
endp
proc SetTunnel ;Schalter fr Tunneleffekt
mov cl,CTRL_Tunnel
jmp SetPlusMinus
endp
proc SetInDOS ;Schalter fr InDOS-Flag-Benutzung
mov cl,CTRL_InDOS
call SetPlusMinus
test [es:ctrl0],CTRL_InDOS
setnz al
mov [es:InDosFlagInc],al ;Code patchen
neg al
mov [es:InDosFlagDec],al ;Code patchen
ret
endp
proc SetRoBit ;Schalter fr ReadOnly-Attribut bei CDFS
mov cl,CTRL_RoBit
;jmp SetPlusMinus
endp
proc SetPlusMinus
lodsb
cmp al,'+'
je @@set
cmp al,'-'
jne help ;sonst Hilfeseite
not cl
and [es:ctrl0],cl
jmp @@e
@@set: or [es:ctrl0],cl
@@e: BSET ch,bit 6 ;irgendein Schalter
ret
endp
proc SetLang
lodsb
call Upcase
mov [es:language],al
SetStringResourcePointer:
cmp al,'D'
mov ax,ofs Texte_deutsch
je @@de
mov ax,ofs Texte_englisch
@@de: mov [String_Table],ax
ret
endp
P8086
proc help ;Hilfe Option "H" oder "?", kein Return
mov ax,ofs Downl$
push ax ;8086!
mov ax,ofs Email$
mov bl,10
jmp TXTO1
endp
;********************
;** Deinstallation **
;********************
proc UnInst ;Deinstallation(sversuch) Option "U", kein Return
mov bl,7 ;"noch nicht installiert"
test ch,bit 7
jnz TXTO1 ;Wenn nicht n”tig!
test ch,3
jz Raus
mov bl,5 ;"deaktiviert"
call AusgabeStringNr
inc bl ;"Interrupt gestohlen"
disab: and [es:Ctrl0],not 80h ;l”schen
jmp TXTOut
DisActiv:;Deaktivieren Option "D" oder Dirs ein/aus mit D+/D-
test ch,bit 7 ;Schon installiert?
mov bl,7
jnz TXTO1
mov bl,5 ;"deaktiviert"
jr disab
;Deinstallation
Raus: push ds
lds dx,[es:OldInt21]
DOS 2521h
lds dx,[es:OldInt2F]
mov al,2Fh
DOS
pop ds
DOS 49h ;den Speicher ab es freigeben
mov bl,13 ;"removed..."
TXTO1: jmp TXTOut
endp
;***********************
;** Statistik-Ausgabe **
;***********************
proc ShowStatus ;Status-Anzeige, kein Return
test ch,bit 7
mov bl,7 ;"Noch nicht installiert"
jnz TXTOut
P386
mov cl,[es:ctrl0]
test cl,80h
mov bl,5 ;"deaktiviert"
jz TXTOut
mov bl,11
call AusgabeStringNr
call AusgabeNL
call AusgabeSchalter
mov bl,14
mov si,ofs counter_read
seges lodsw
call AusgabeZaehler
inc bl
seges lodsw
call AusgabeZaehler
inc bl
seges lodsw
call AusgabeZaehler
call AusgabeHeap
call PrintLastError
DOS 4C00h
endp
proc AusgabeSchalter
;Alle Schalter ausgeben
mov cl,[es:ctrl0]
mov ch,40h
mov bl,17
@@l: push bx
call AusgabeSch
pop bx
ror ch,1
inc bl
cmp bl,23
jne @@l
ret
endp
proc AusgabeZaehler
;PE: BL=String-Nummer
; AX=Z„hlerstand
push bx
push ax
call AusgabeStringNr
pop ax
call AusgabeNL
pop bx
ret
endp
proc GetOnOffPtr
;PE: Z=0=EIN, Z=1=AUS
;PA: SI=String-Zeiger
;VR: AX,CX,SI
push bx
mov bl,24 ;"EIN"
jnz @@1
inc bl ;"AUS"
@@1: call LoadString
pop bx
ret
endp
proc AusgabeSch
push bx cx
test cl,ch
call GetOnOffPtr
push si
call LoadString
push si
mov bl,26 ;"%xxs %s\n"
call AusgabeStringNr
pop cx
pop cx
pop cx bx
ret
endp
proc AusgabeHeap
;Einfacher HeapWalker, geht nur den freien Bereich durch!
mov si,es
dec si
mov ds,si ;MCB-Zeiger
mov ax,[3] ;Paragrafen
shl ax,4 ;Bytes
inc si
mov ds,si
mov si,[LocalHeap]
sub ax,si
sub ax,4 ;Zwangsbytes nicht mitz„hlen
xchg bx,ax ;SIZE
xor cx,cx ;FREE
xor dx,dx ;MAXAVAIL
@@l: lodsw
xchg di,ax
lodsw
add cx,ax
cmp dx,ax
jnc @@1
xchg dx,ax ;Maximum
@@1: xchg ax,di
or ax,ax
xchg si,ax
jnz @@l
LD ds,cs
push dx
push cx
push bx
mov bl,34
call AusgabeStringNr
add sp,6
ret
endp
P8086
;********************************
;** Installations-Vorbereitung **
;********************************
proc GetLocalHeapSize
;Berechnet erforderliche(?) Heap-GrӇe anhand der grӇten .JLT-Datei,
;die im Arbeitsverzeichnis von DOSLFN liegt
;PA: AX=Heap-GrӇe
PUSHSTATE
P386
mov ax,[LocalHeapSize]
or ax,ax
jnz @@e ;angegebene Gr”áe (root weiá, was sie tut)
lea dx,[StdDTA]
DOS 1Ah ;DTA nach hinten setzen
lea di,[fname_buffer]
push di
call CopyWorkDir
mov dx,[UserUniFile]
or dx,dx
jnz @@userload
DOS 6601h ;Codeseite holen
jc @@noload
push di
call MakeTblFileName
pop di
lea dx,[fname_buffer]
@@userload:
mov cx,7
DOS 4Eh ;FindFirst
jc @@noload
mov eax,[StdDta.fsize]
cmp eax,50000 ;Zu groá?
jna @@load
@@noload:
xor ax,ax
@@load:
add ax,DEFHEAPSIZE ;"Pflichtteil" dazu
pop dx ;fname_buffer
BTST [ctrl0],CTRL_CDROM
jz @@e ;nur mit .TBL berechnet
push ax
lea si,[jltfilter$] ;mit grӇter .JLT dazu
call strcpy
mov di,DEFHEAPSIZE_CD-DEFHEAPSIZE ;zus„tzlicher "Pflichtteil"
mov cx,7 ;Versteckte Dateien gehen auch!
mov ah,4Eh ;FindFirst
jmp @@f
@@l: mov eax,[StdDTA.fsize]
cmp eax,32000 ;Irreales Maá!
ja @@1 ;Ignorieren
cmp ax,di
jc @@1
xchg di,ax ;neues Maá
@@1: mov ah,4Fh ;FindNext
@@f: DOS
jnc @@l
pop ax
add ax,di
@@e: ret
POPSTATE
endp
proc fstrlen pascal
arg @s:dword
uses es,di
les di,[@s]
xor ax,ax
mov cx,-1
repne scasb
mov ax,-2
sub ax,cx
ret
endp
proc CheckWinVer
MUX 160Ah ;Windows-Versionsnummer
or ax,ax
jnz @@e
cmp bh,4 ;Zu hoch?
mov bl,33
jc @@e
_out: jmp TXTOut
@@e: ret
endp
proc Install ;Installation oder Aktivierung, kein Return
test ch,bit 7
jnz @@test
call CheckWinVer
mov bl,12 ;"reaktiviert"
test ch,bit 6 ;irgendein Schalter auf Kommandozeile gewesen?
jz @@setab ;ohne, "reaktiviert"
mov bl,9 ;mit, "Schalter angenommen"
@@setab:jmp Activate
@@test: ;hier: ES=DS
;Auf Mindest-Prozessor und -Betriebssystem testen
mov bp,cx ;retten
IS386
mov bl,8 ;"Test386 versagt"
jc _out
P386
DOS 30h ;DOS-Versionsnummer
cmp al,4 ;wegen Int21/AH=6Ch
mov bl,32
jc _out
call CheckWinVer
;Zeiger auf InDOS-Flag und Ger„tetreiber-Kette beschaffen
push es ;Brauch ich's?
DOS 34h ;InDOS-Flag-Adresse beschaffen
mov [InDosFlagOfs],bx
; mov [InDosFlagOfs2],bx
mov [InDosFlagSeg],es
DOS 52h ;get NUL device driver address
add bx,22h
cmp [dword es:bx+10],' LUN' ;Is there actually a NUL header?
je @@okdev
mov bx,0FFFFh ;let scan for devices auto-terminate
@@okdev: SES [DriverChain],bx
pop es
;Hand-Relokation im residenten Bereich
mov [wo high rwrec.addr],cs
mov [wo DPB_Drive],0FFh ;kein Laufwerk beim Start
;mov [DriveType],0 ;Um Gottes Willen keinen Flush machen!
;Zeiger auf "filename uppercase table" beschaffen
mov bx,0FFFFh
mov cx,5
mov dx,bx
mov di,5Dh
DOS 6504h
mov eax,[5Eh]
sub ax,7Eh
mov [uppercase_table],eax
;Zeiger auf "DBCS lead byte table" beschaffen
DOS 6507h
mov eax,[5Eh]
add ax,2 ;L„nge bergehen
mov [lead_byte_table],eax
;5 kritische Strings umsetzen (in Sektor-Bereich)
mov bx,ofs String_Table
mov si,[bx]
mov di,ofs Alt_String_Table
mov [bx],di ;String_Table neu setzen
mov cx,5
@@l: call strcpy
loop @@l
;Initialisierung des Lokalen Heap vorbereiten
call GetLocalHeapSize
;sollte auf Paragrafengrenze aufgerundet werden!
mov di,ofs DefLocalHeap
BTST [ctrl0],CTRL_CDROM
jnz @@a1
mov di,ofs DefLocalHeap_FATONLY
@@a1: jmp CriticalInit
endp
jltfilter$: dz "*.JLT"
;***********************
;** String-Ressourcen **
;***********************
;Die einzelnen Strings sind einfach durch \0-Zeichen voneinander getrennt
;und dicht an dicht hintereinander.
;Die ersten 5 Strings werden in einen sicheren Bereich kopiert,
;bevor der Heap (ber die Strings hinweg) initialisiert wird.
FIRSTERRORSTRING = 35
Email$: dz "henrik.haftmann@e-technik.tu-chemnitz.de"
Downl$: dz "http://www.tu-chemnitz.de/~heha/hs_freeware/doslfn.zip"
Text0 db "DOSLFN 0.32n (haftmann#software 01/03): $"
Texte_deutsch:
dz 10 ;0
dz "hoch" ;1
dz "geladen, verbraucht %u Bytes." ;2
dz 10,"Kann Unicode-Datei %s nicht finden/”ffnen!" ;3
dz 10,"Falscher Inhalt der Datei %s oder Lese-Fehler!" ;4
dz "deaktiviert." ;5
dz 10,"(Andere TSR stahl Int21 und/oder Int2F)" ;6
dz "Noch nicht installiert!" ;7
dz "Ben”tigt mindestens einen 386er Prozessor!" ;8
dz "Schalter angenommen." ;9
db " (386+) ++ FREEWARE ++",10 ;10
db "Programm fr lange Dateinamen unter nacktem DOS.",10
db "Aktionen: - (nichts) TSR laden oder aktivieren",10
db " - h oder ? diese Hilfe",10
db " - d DOSLFN deaktivieren",10
db " - s Status und Einstellungen",10
db " - u TSR entfernen",10
db "Schalter: - w{+|-} * Schreibzugriffe",10
db " - ~{+|-} * Tilde (ich hasse Schlangen)",10
db " - t{+|-} * Tunneleffekt (fr Editoren)",10
db " - c{+|-} * CDROM-Untersttzung",10
db " - i{+|-} * InDOS-Flag-Wiederaufrufsperre fr TSRs",10
db " - r{+|-} * Schreibschutz-Attribut fr CDROM-Dateien",10
db " - z[:|=]table Unicode-Tabelle (.TBL-Volkov-Format) laden",10
db " - m[:|=]bytes GrӇe des internen Heaps festlegen, 600..50000",10
db " - p[:|=]path Arbeitsverzeichnis (.TBL/.JLT/.386) festlegen",10
db " - l{d|e} Sprache setzen (deutsch|englisch)",10
db "Umgebung: TZ=xxxNyyy Zeitzone N fr Zeitumrechnung, ohne DST",10
db " (nicht implementiert)",10
db "Email: %s",10
dz "Download: %s"
dz "aktiv" ;11
dz "reaktiviert." ;12
dz "vom Speicher entfernt." ;13
dz "%5u Lesezugriffe" ;14
dz "%5u Schreibzugriffe" ;15
dz "%5u Int21/AH=71-Aufrufe" ;16
dz "Schreibzugriffe" ;17
dz "Schlangen" ;18
dz "Tunneleffekt" ;19
dz "CDROM-Untersttzung" ;20
dz "InDOS-Flag-Verriegelung" ;21
dz "Schreibschutz-Attribut fr CD-Dateien" ;22
dz "Ungltige Heap-GrӇe" ;23
dz "EIN" ;24
dz "AUS" ;25
dz "%37s %s",10 ;26
dz "Verzeichnis existiert nicht!" ;27
dz "Kann Verzeichnis nicht setzen." ;28
dz "Kann Heap-Gr”áe nicht ver„ndern." ;29
dz "Kann Schalter nicht annehmen." ;30
dz 10,"Dazu vorher TSR entfernen." ;31
dz "DOS4+ erforderlich!" ;32
dz 10,"In einem DOS-Fenster dieser Windows-Version ist DOSLFN sinnlos!";33
dz "Heap: gesamt=%u, frei=%u, grӇter Block=%u Bytes",10 ;34
dz "Letzter Fehler: %u - " ;35 = 0
dz "Verbotener Schreibzugriff" ;1
dz "Konnte Verzeichnis nicht expandieren" ;2
dz "Konnte Joliet-Link-Tabelle nicht finden" ;3
dz "Nicht genug Speicher - bitte vergrӇern" ;4
dz "Konnte Unicode-Datei nicht laden" ;5
texte_englisch:
dz 10 ;0
dz "high " ;1
dz "loaded consuming %u bytes." ;2
dz 10,"Cannot find/open Unicode table file %s!" ;3
dz 10,"Wrong content of file %s or cannot read!" ;4
dz "disabled." ;5
dz 10,"(Another TSR grabbed Int21 and/or Int2F)" ;6
dz "Not yet installed!" ;7
dz "Requires at least a 386 processor!" ;8
dz "switch(es) taken" ;9
db " (386+) ++ FREEWARE ++",10 ;10
db "Program that supports long filenames in pure DOS.",10
db "USE THIS PROGRAM AT YOUR OWN RISK, DATA LOSS MAY BE POSSIBLE",10
db "Actions: - (nothing) load and/or enable TSR",10
db " - h or ? this help",10
db " - d disable DOSLFN",10
db " - s show status and settings",10
db " - u unload TSR",10
db "Switches: - w{+|-} * write access",10
db " - ~{+|-} * NameNumericTail - tilde usage (I hate snakes)",10
db " - t{+|-} * PreserveLongNames - tunnel effect",10
db " - c{+|-} * CDROM support",10
db " - i{+|-} * reenter lock via InDOS flag",10
db " - r{+|-} * read-only bit for CDROM files",10
db " - z[:|=]table load Unicode table (format Volkov .TBL)",10
db " - m[:|=]bytes declare size of internal heap, 600..50000",10
db " - p[:|=]path declare working directory for .TBL/.JLT/.386",10
db " - l{d|e} set language (german|english)",10
db "Environment: TZ=xxxNyyy time zone N for time conversion, no DST usage",10
db " (not implemented)",10
db "email: %s",10
dz "Download: %s"
dz "active" ;11
dz "enabled." ;12
dz "removed from memory." ;13
dz "%5u read accesses" ;14
dz "%5u write accesses" ;15
dz "%5u Int21/AH=71 calls" ;16
dz "write access" ;17
dz "tilde usage" ;18
dz "tunnel effect" ;19
dz "CDROM support" ;20
dz "InDOS flag usage" ;21
dz "Read-Only bit set on CD files" ;22
dz "invalid heap size" ;23
dz "ON" ;24
dz "OFF" ;25
dz "%35s %s",10 ;26
dz "directory doesn't exist!" ;27
dz "cannot set workdir" ;28
dz "cannot resize heap" ;29
dz "switch rejected" ;30
dz " - unload TSR first" ;31
dz "requires at least DOS version 4!" ;32
dz 10,"This program is useless in a DOS box of this Windows version!";33
dz "Heap: size=%u, free=%u, max-avail=%u Bytes",10 ;34
dz "Last error: %u - " ;35 = 0
dz "user had denied write access" ;1
dz "couldn't expand FAT directory" ;2
dz "couldn't find a Joliet Link Table" ;3
dz "not enough memory - increase heap" ;4
dz "couldn't auto-load Unicode table" ;5
Texte_franzoesisch:
; include "francais.inc"
Texte_japanisch:
; include "nihongo.inc"
StdDTA TSearchRec <> ;im transienten Teil
fname_buffer db 80 dup (?) ;fr HeapgrӇenbestimmung
truename_buf db 64 dup (?) ;fr WorkDir
endc
;**************************************************************************
Detected encoding: UTF-8 | 0
|