File creation using Long Filenames in DOS32
- Posted by Scott Murray <FaIkon1313 at AOL.COM> Jan 31, 1999
- 450 views
While poking about with some generic test code, I was getting errors when trying to save my output file...Every time. Upon closer inspection, the cause became obvious. One of the directories in my output path was a 'long filename'. I figured somebody'd surely solved that problem by now, but I did a search of the mailing list, archive, and recent-user-contributions and couldn't find it. However, I did find doswrap.e by Jacques Deschenes, which helped me figure it out. So here it is. This code redefines open() so that it will work with long filenames on versions of DOS >= 7.0. When run on earlier versions of DOS, the original version of open() will be called, which truncates any long filenames when creating new files. (Which causes an "unable to create file" error if one of the parent directories of the file is an LFN. But that shouldn't be a problem on versions of DOS prior to 7.0.) It's a hack, not exactly efficient, and not guaranteed. But it works for me...so far. If you find any bugs in it, please let me know. (Tested on Win98, but not NT or 95 yet) ---------------------------------------------------------------- ---------------------------------------------------------------- --LFNopen.e -- --By: FaIkon1313 at aol.com --Date: January 31, 1999 (finished at 03:00 a.m., of course :) --Platform: DOS32 -- ---------------------------------------------------------------- without warning include machine.e global constant READ = 0, WRITE = 1, READ_WRITE=2 global constant LFN_OPEN = 1, LFN_TRUNC = 2, LFN_CREATE = 16 global function DosVer() sequence reg_list reg_list = repeat(0,10) reg_list[REG_AX] = #3000 reg_list = dos_interrupt( #21, reg_list ) return( remainder( reg_list[REG_AX], 256 ) + floor( reg_list[REG_AX]/256 ) / 100 ) end function global function DosClose( integer Handle ) -- close a file open with DosOpen() -- return 1 if success else return 0 sequence regs regs = repeat( 0,10 ) regs[REG_AX] = #3E00 regs[REG_BX] = Handle regs = dos_interrupt( #21,regs ) if and_bits( regs[REG_FLAGS], 1 ) then return( 0 ) end if return( 1 ) end function -- DosClose() global function DosOpenLong( sequence FileName, integer Mode, integer Attributes, integer Action, integer DN ) -- use DOS function #716C to open/create a file -- return file handle or -1 if error -- mode is 0 = read only -- 1 = write only -- 2 = read/write --Bitfields for Windows95 long-name open action: --Bit(s) Description (Table 01781) --0 open file (fail if file does not exist) --1 truncate file if it already exists (fail if file does not exist) --4 create new file if file does not already exist (fail if exists) --Note: The only valid combinations of multiple flags are bits 4&0 and 4&1 atom NameBuffer sequence regs regs = repeat( 0,10 ) if DosVer() < 7 then return( -1 ) end if NameBuffer = allocate_low( length( FileName ) +1 ) if not NameBuffer then return( -1 ) end if poke( NameBuffer, FileName & 0 ) regs[REG_AX] = #716C regs[REG_BX] = Mode regs[REG_CX] = Attributes regs[REG_DX] = Action regs[REG_DS] = floor( NameBuffer / 16 ) --address segment regs[REG_SI] = remainder( NameBuffer, 16 ) -- offset regs[REG_DI] = DN --disambiguation number regs = dos_interrupt( #21, regs ) free_low( NameBuffer ) if and_bits( regs[REG_FLAGS], 1 ) then return( -1 ) -- fail to open end if return regs[REG_AX] -- return file handle end function global function LFNopen( sequence filename, sequence mode ) integer tfn -- puts( 1, "\nLFNO called." ) if ( not find( mode, {"r","rb","w","wb","u","ub","a","ab"} ) ) or ( DosVer() < 7 )then return( -1 ) end if if ( mode[1] = 'w' ) or ( mode[1] = 'a' ) then --use LFN_OPEN as well as LFN_CREATE so that we --won't get an error if it already exists tfn = DosOpenLong( filename, WRITE, 0, or_bits( LFN_OPEN, LFN_CREATE ), 1 ) if ( tfn < 0 ) then --unable to create file return( -1 ) end if tfn = DosClose( tfn ) end if --now it exists, we can try to open it return( open( filename, mode ) ) end function function original_open( sequence filename, sequence mode ) -- puts( 1, "\nOO called." ) return( open( filename, mode ) ) end function constant ORIGINAL_OPEN = routine_id( "original_open" ) global function open( sequence filename, sequence mode ) if DosVer() < 7 then --no long filename support, use original return call_func( ORIGINAL_OPEN, { filename, mode } ) else return( LFNopen( filename, mode ) ) end if end function