Cannot find file using search first routine

Started by kaidranzer, February 28, 2012, 07:03:17 AM

Previous topic - Next topic

kaidranzer

I am working with the following 16-bit code:

.model tiny
.code

ORG 100H

FILE_NAME EQU 9EH ;DTA Position after execution of search_first_file

START:
mov ah,9
mov dx,OFFSET STR_START
int 21H

mov ah,4EH ;Search first file
mov dx,OFFSET PATH
int 21H
jc NO_FILE_FOUND

FILE_FOUND:
mov ah,9
mov dx,OFFSET STR_FILE_FOUND
int 21H

mov ah,3DH ;Open file to write
mov al,01H
mov dx,FILE_NAME
int 21H

mov ah,9
mov dx,OFFSET STR_FILE_OPENED
int 21H

mov ah,40H ;Write code
mov bx,ax
mov dx,100H
mov cx,44
int 21H

mov ah,9
mov dx,OFFSET STR_FILE_WRITTEN
int 21H

mov ah,3EH ;Close file
int 21H

mov ah,4FH ;Search next
int 21H
jnc FILE_FOUND

NO_FILE_FOUND:
ret

PATH                              db     'C:\comfiles_folder\HOST.COM',0
STR_START                         db     'program started!',0
STR_FILE_FOUND                    db     'file found!',0
STR_FILE_OPENED                   db     'file opened!',0
STR_FILE_WRITTEN                  db     'code written!',0

END START


This code basically finds a COM file called HOST.COM at the path "C:\comfiles_folder\HOST.COM" and overwrites it. I debugged the code using CodeView and found out that it returns with error code 03h meaning "Path not found". Is there some other format in which I need to specify the path?

MichaelW

You should be using short (8.3) file and path names. Also, strings that you expect to display with Interrupt 21h Function 9 need to have a "$" terminator.
eschew obfuscation

dedndave

#2
Michael is right - your strings need help
PATH                              db     'C:\comfil~1\HOST.COM',0
STR_START                         db     'program started!',24h
STR_FILE_FOUND                    db     'file found!',24h
STR_FILE_OPENED                   db     'file opened!',24h
STR_FILE_WRITTEN                  db     'code written!',24h


also, there is no need to use the FindFirst (INT 21h,AH=4Eh) function, at all
just use OpenExistingFile (INT 21h,AX=4D01h)
if the file does not exist, the carry flag will be set
        mov     dx,offset PATH
        mov     ax,4D01h
        int     21h
        jc      NO_FILE_FOUND

even though there may be other reasons the flag is set - it will be clear only if the file exists and is opened
you don't care what the error code is - lol - the action will be the same

another problem is that you destroy the handle if open is successful
mov ah,3DH  ;Open file to write
mov al,01H
mov dx,FILE_NAME
int 21H

mov ah,9
mov dx,OFFSET STR_FILE_OPENED
int 21H

mov ah,40H ;Write code
mov bx,ax                                    ;huh ???
mov dx,100H
mov cx,44
int 21H


put the handle in BX immediately - BX is preserved across most functions that do not use it
        .MODEL  Tiny

        .CODE
        ORG     100h

START:  mov     dx,offset STR_START
        mov     ah,9
        int     21h

        mov     dx,offset PATH
        mov     ax,4D01h
        int     21h
        jc      NO_FILE_FOUND

        xchg    ax,bx
        mov     dx,offset STR_FILE_OPENED
        mov     ah,9
        int     21h

        mov     dx,START
        mov     cx,offset END_OF_FILE-START
        mov     ah,40h
        int     21h
        jc      NOT_WRITTEN

        mov     dx,offset STR_FILE_WRITTEN
        mov     ah,9
        int     21h

NOT_WRITTEN:
        mov     ah,3Eh
        int     21h

NO_FILE_FOUND:
        ret

PATH             db 'C:\comfil~1\HOST.COM',0
STR_START        db 'program started!',0Dh,0Ah,24h
STR_FILE_OPENED  db 'file opened!',0Dh,0Ah,24h
STR_FILE_WRITTEN db 'code written!',0Dh,0Ah,24h
END_OF_FILE      LABEL BYTE

        END     START


one final note:
there is no need to repeat the operation with FindNextFile   :P

MichaelW

Under Windows short filenames are generated by the system, so while ~1 is a good first guess, depending on the directory structure and/or the order in which the directories/files were created, the short name could end with something other than ~1. The only way to know for sure is to get the short name from the system.

;==============================================================================
.model small, c
.386
.stack
;============================================================================== 
.data
    lfn db "C:\comfiles_folder\HOST.COM",0
    sfn db 128 dup("$")
    err db "ERROR$"
.code
;============================================================================== 
.startup
    push ds
    pop es
    mov ax, 7160h
    mov cl, 1             ; subfunction 1
    mov ch, 0             ; return true path for SUBSTed drive letter
    mov si, OFFSET lfn    ; DS:SI->lfn
    mov di, OFFSET sfn    ; ES:DI->sfn
    int 21h
    jc  @F
    mov ah, 9
    mov dx, OFFSET sfn
    int 21h
    jmp exit
  @@:
    mov ah, 9
    mov dx, OFFSET err
    int 21h
  exit:
    mov ah, 0
    int 16h
.exit
end

eschew obfuscation

FORTRANS

Hi,

   You can use DIR /X from a command line to get
the short filenames as well.

Regards,

Steve N.

dedndave

Michael,
working with long file names in 16-bit DOS is something i never figured out   :P
so - that will get you the short name - good to learn   :U

is there a way to create or rename a file and/or folder with a long name ?

MichaelW

Dave,

There is a more or less complete set of LFN functions, see RBIL for Interrupt 21h, Function 71h.
eschew obfuscation


kaidranzer

Okay so I made the changes and my code now looks like:

.model tiny
.code

ORG 100H

FILE_NAME EQU 9EH ;DTA Position after execution of search_first_file

START:
mov ah,9
mov dx,OFFSET STR_START
int 21H

mov ah,4EH ;Search first file
mov dx,OFFSET PATH
int 21H
jc NO_FILE_FOUND

FILE_FOUND:
mov ah,9
mov dx,OFFSET STR_FILE_FOUND
int 21H

mov ah,3DH ;Open file to write
mov al,01H
mov dx,FILE_NAME
int 21H

                        mov     bx,ax           ;Write code
                        mov     ah,40H 
mov dx,100H
mov cx,44
int 21H

mov ah,9
mov dx,OFFSET STR_FILE_WRITTEN
int 21H

mov ah,3EH ;Close file
int 21H

mov ah,4FH ;Search next
int 21H
jnc FILE_FOUND

NO_FILE_FOUND:
ret

PATH                    db      'C:\COMFIL~1\*.COM',0
STR_START               db      'program started!$'
STR_FILE_FOUND          db      'file found!$'
STR_FILE_OPENED         db      'file opened!$'
STR_FILE_WRITTEN        db      'code written!$'

END START


The DTA is being setup but I get ax=02h error code i.e. "file not found" while opening the file (ah = 3DH). Cant seem to find out why. Can someone please point out the error?

FORTRANS

Hi,

   I copied your code, edited it to change the PATH, created a
fake FROG.COM file pointed to by the PATH, and ran your program.
A 44 byte FROG.COM was the result.  The program output was
as follows:

program started!file found!code written!

Run in an VDM (Virtual DOS Machine) on a RAM disk, FWIW.

HTH,

Steve N.

dedndave

the filename in the DTA is not preceeded with a drive letter and path - it is just the 8.3 filename
so - unless you execute from the same path, the file will not be found when you try to open it
you can create a buffer to copy it to, with the path already set up
szOpenPath db 'C:\COMFIL~1\'
szOpenFile db 13 dup(?)

then copy the 13 characters (includes null) from the DTA to szOpenFile
and use szOpenPath to open

FORTRANS

Hi,

   As per Dave's comment; the execution path was the same
as the path specified in the PATH variable.  The program was
executed in the same directory as the target file.

Regards,

Steve

kaidranzer