The MASM Forum Archive 2004 to 2012

General Forums => The Workshop => Topic started by: Ehtyar on October 03, 2006, 10:46:32 AM

Title: My attempt at directory recursion.
Post by: Ehtyar on October 03, 2006, 10:46:32 AM
Hi all.
I started a new project today, and sfv/md5/sha file generator, but thus far im not having much luck.
I borrowed the directory recursion code from Hutch's directory case converter, and after about 2 hours, i still havnt got it working properly. I apologise in advance for any really obvious screw-ups in here, but my brain is somewhat mushed at the moment, thanks to this un-cooperative code. If anyone could advise me on what i need to do to get this work, i'd very much appreciate it.
It should simply recurse through the directory structure below the executable itself, and print relative file paths/names to dir.txt.
Thanks, Ehtyar.
.586
.MODEL FLAT, STDCALL
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib

include \masm32\macros\macros.asm

.data
boro    db "dir.txt", 0
diry    db "*.*",0
.data?

handle  dd ?
fHand   dd ?
bytwrit dd ?

.code
start:
call main
exit

Find_Files proc hFile:DWORD, ppatn:DWORD
LOCAL hSrch :DWORD
LOCAL wfd   :WIN32_FIND_DATA
invoke FindFirstFile,ppatn,addr wfd
mov hSrch, eax
.IF hSrch != INVALID_HANDLE_VALUE
invoke szCmp, addr wfd.cFileName, chr$(".", 0)
cmp eax, 0
je @F
.IF wfd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY
invoke SetCurrentDirectory, addr wfd.cFileName
invoke Find_Files,hFile,ppatn                 ; recurse to next directory level
.ENDIF
invoke szLen, addr wfd.cFileName
mov word ptr [wfd.cFileName+eax], 0a0dh
add eax, 2
invoke WriteFile, hFile, addr wfd.cFileName, eax, addr bytwrit, 0
@@:
invoke FindNextFile,hSrch,addr wfd
test eax, eax
jz close_file
invoke szCmp, addr wfd.cFileName, chr$("..", 0)
cmp eax, 0
je @F
.IF wfd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY
invoke SetCurrentDirectory, addr wfd.cFileName
invoke Find_Files,hFile,ppatn                 ; recurse to next directory level
.ENDIF
invoke szLen, addr wfd.cFileName
mov word ptr [wfd.cFileName+eax], 0a0dh
add eax, 2
invoke WriteFile, hFile, addr wfd.cFileName, eax, addr bytwrit, 0
@@:                                     ; loop through the rest
invoke FindNextFile,hSrch,addr wfd
cmp eax, 0
je close_file
invoke szLen, addr wfd.cFileName
mov word ptr [wfd.cFileName+eax], 0a0dh
add eax, 2
invoke WriteFile, hFile, addr wfd.cFileName, eax, addr bytwrit, 0
.IF wfd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY
invoke SetCurrentDirectory, addr wfd.cFileName
invoke Find_Files,hFile,ppatn                 ; recurse to next directory level
.ENDIF
jmp @B
close_file:
invoke FindClose,hSrch
.ENDIF
invoke SetCurrentDirectory, chr$("..", 0)                              ; drop back to next lower directory
ret
Find_Files endp


main proc
invoke DeleteFile, addr boro
invoke CreateFile, addr boro, GENERIC_WRITE, 0, 0, CREATE_NEW, 0, 0
mov fHand, eax
invoke Find_Files, fHand, addr diry
invoke CloseHandle, fHand
ret
main endp


end start
Title: Re: My attempt at directory recursion.
Post by: PBrennick on October 03, 2006, 11:15:40 AM
Ehtyar,
I wanted to test your code so I could help you but I was unable to compile the code because  the MBox macro cannot be found.  I will check if this is supposed to be in macros.asm in masm32.

Paul

Title: Re: My attempt at directory recursion.
Post by: Ehtyar on October 03, 2006, 11:27:18 AM
Oh nooooo, I'm so sorry. It's a cusom one, I use it for random debugging kinda thing, I'll edit my post to remove it :'( I knew one day adding functions to the standard macros file would come back to bite me in the a** :(
Title: Re: My attempt at directory recursion.
Post by: PBrennick on October 03, 2006, 11:34:38 AM
Ehtyar,
No problem, thanks for the quick reply and I will continue testing.  Just a word of caution, you should create your own macros file.  Don't ever modify macros.asm or windows.inc or everyone who wants to help you will be frustrated.

Paul
Title: Re: My attempt at directory recursion.
Post by: Tedd on October 03, 2006, 11:43:55 AM
First problem is that you're not recursing!
This is due to the line
.IF wfd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY
which will only work if the attribute for the directory is ONLY directory (they may have others set).
So you need to 'test' instead of 'cmp' :wink
Title: Re: My attempt at directory recursion.
Post by: Tedd on October 03, 2006, 12:05:40 PM
Fixed and cleaned up :wink

It doesn't prefix the relative directories -- I've left the fun part for you :green2

Find_Files proc hFile:DWORD,ppatn:DWORD
    LOCAL hSrch :DWORD
    LOCAL wfd   :WIN32_FIND_DATA
    invoke FindFirstFile,ppatn,addr wfd
    mov hSrch, eax
    .IF hSrch != INVALID_HANDLE_VALUE
      @loopy:
        mov eax,wfd.dwFileAttributes
        test eax,FILE_ATTRIBUTE_DIRECTORY
        .IF (zero?)
            ;print the file name
            ;(we don't print directory names alone -- they should be prefixed to the files)
            invoke szLen, addr wfd.cFileName
            mov word ptr [wfd.cFileName+eax], 0a0dh
            add eax, 2
            invoke WriteFile, hFile,addr wfd.cFileName, eax, addr bytwrit, 0
        .ELSE
            ;skip "." and ".." 'directories'
            mov eax,DWORD PTR [wfd.cFileName]
            cmp eax,002eh   ;"."
            je @next
            cmp eax,002e2eh ;".."
            je @next
            ;recurse to next directory level
            invoke SetCurrentDirectory, addr wfd.cFileName
            invoke Find_Files,hFile,ppatn
        .ENDIF
      @next:
        invoke FindNextFile,hSrch,addr wfd
        cmp eax, 0
        jne @loopy

        invoke FindClose,hSrch
    .ENDIF
    invoke SetCurrentDirectory, chr$("..", 0)   ; drop back to next lower directory
    ret
Find_Files endp


This SHOULD work -- and it does in a debugger, but not if you run it directly :dazzled:
Not quite sure what's happening, but I have a feeling that the changing current directory is messing up the 'state' of the FindFirstFile handles.
Title: Re: My attempt at directory recursion.
Post by: Ehtyar on October 03, 2006, 12:42:52 PM
Thanks so much for the help guys and i'm so sorry for the initial screw up Paul. I never realised directory recursion was so damn complicated. I guess this is why i found only one example elsewhere that apparently dosnt work anyway :(
Wow Tedd, you rewrote half the code, thank you!!! You are indeed correct , works in a debugger but not elsewhere, and as you may have guessed debugging is NOT my strong suit, nor is directory recursion apparently. I must admit that i'm surprised there isnt more source available for this kind of thing, can't imagine i'm the first person who wanted this.
I guess unless we get it working somehow i'll have to skip the directory recursion bit and just do a single directory. When i finish the project though ill post the source and anyone can have a play with it, but it will be basic i think, maybe not even a dialog...
Thanks again for the help guys, least i picked up a few more tricks from the pros today ;) I'll keep on it for a little while longer but to be honest im about up to my neck in this code. Source will be posted soon, thanks again.
Ehtyar
Title: Re: My attempt at directory recursion.
Post by: PBrennick on October 03, 2006, 12:50:16 PM
Ehtyar,
There is code for this that works.  Hutch wrote a program that deletes certain files in the entire tree from the initial directory on down.  I can't quite remember what it was but I will find out for you so hold on, don't give up yet.

Paul
Title: Re: My attempt at directory recursion.
Post by: PBrennick on October 03, 2006, 01:06:59 PM
Ehtyar,
By the way, I ran the program using OllyDbg and WinDbg and they both ran it differently for some reason. Olly does the bore down starting from the location of Recursion.exe (this is the way it should work).  WinDbg, though, does the bore down starting from the location of WinDbg.exe.  This is unusual in my opinion.  It is probably because WinDbg is not working correctly, so you should not use it.

Paul
Title: Re: My attempt at directory recursion.
Post by: PBrennick on October 03, 2006, 01:11:20 PM
Ehtyar,
Here is the program that does directory recursion as I mentioned in an earlier post.



comment *
     -------------------------------------------------
    | This utility, a CONSOLE application, recurses   |
    | the directory tree from its current location    |
    | and changes the case of all filenames to lower. |
     -------------------------------------------------
*
    .386
    .model  flat,stdcall
    option  casemap:none

    include \masm32\include\windows.inc
    include \masm32\macros\macros.asm

    uselib MACRO namelist:VARARG
    FOR item, <namelist>
      include \masm32\include\item.inc
      includelib \masm32\lib\item.lib
      ENDM
    ENDM

    uselib kernel32,masm32

    Find_Files  PROTO :DWORD
    change_case PROTO :DWORD

.code
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
start:
    call    main
    exit

main    proc
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    fn  Find_Files,"*.*"
    ret
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main    endp

Find_Files  proc ppatn:DWORD
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    LOCAL   hSrch:DWORD
    LOCAL   wfd:WIN32_FIND_DATA
    LOCAL   pbuf:DWORD
    LOCAL   buffer[260]:BYTE

    mov     pbuf, ptr$(buffer)
    mov     hSrch, rv(FindFirstFile, ppatn, ADDR wfd)
    invoke  SetFileAttributes, ADDR wfd.cFileName, FILE_ATTRIBUTE_NORMAL
    .if hSrch != INVALID_HANDLE_VALUE
      lea     eax, wfd.cFileName
      switch$ eax
        case$   "."                     ; Bypass current directory character
          jmp     @F
      endsw$
      .if wfd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY
        chdir   ADDR wfd.cFileName
        fn      Find_Files, ppatn       ; Recurse to the next directory level
      .endif
      invoke  change_case, ADDR wfd.cFileName
@@:
      test    rv(FindNextFile, hSrch, ADDR wfd), eax
      jz      close_file
      invoke  SetFileAttributes, ADDR wfd.cFileName, FILE_ATTRIBUTE_NORMAL
      lea     eax, wfd.cFileName
      switch$ eax
        case$   ".."                    ; Bypass previous directory characters
          jmp     @F
      endsw$
      .if wfd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY
        chdir   ADDR wfd.cFileName
        fn      Find_Files, ppatn       ; Recurse to next directory level
      .endif
      invoke  change_case, ADDR wfd.cFileName
@@:                                     ; Loop through the rest
      test    rv(FindNextFile, hSrch, ADDR wfd), eax
      jz      close_file
      invoke  SetFileAttributes, ADDR wfd.cFileName, FILE_ATTRIBUTE_NORMAL
      invoke  change_case, ADDR wfd.cFileName
      .if wfd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY
        chdir   ADDR wfd.cFileName
        fn      Find_Files, ppatn       ; Recurse to next directory level
      .endif
      jmp     @B
close_file:
      invoke  FindClose,hSrch
    .endif
    chdir   ".."                        ; Drop back to next lower directory
    ret
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Find_Files  endp

change_case proc fname:DWORD
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    LOCAL   pbuf:DWORD
    LOCAL   buffer[260]:BYTE

    mov     pbuf, ptr$(buffer)

;   Rename file to lower case form
    invoke  MoveFile, fname, lcase$(fname)


    invoke  GetCurrentDirectory, 260, pbuf
    print   lcase$(pbuf), "\"
    print   lcase$(fname), 13, 10       ; Display the lower case name
    ret
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
change_case endp

    end     start


I hope this helps you.
Paul
Title: Re: My attempt at directory recursion.
Post by: PBrennick on October 03, 2006, 01:20:24 PM
Ehtyar,
To me, it looks like your modification to add the filename to the proc is what is screwing it up.  Leave the proc as is and call it with just the pattern as Hutch is doing and then add the stuff that writes to dir.txt into the proc instead of passing it from outside.

Do you understand my point?

Also, the program works correctly if it is run from a folder that does not have any directory entries.

Paul
Title: Re: My attempt at directory recursion.
Post by: Shantanu Gadgil on October 03, 2006, 02:10:22 PM
To Ehtyar,
Nice to see someone else too doing directory recursion. Just a suggestion though, don't use the SetCurrentDirectory or whatever equivalent (chdir, et al) calls at all. Recusrion can be achieved by just using strings :) :) and no actual calls to set directory are required!!!

I will just run you through the algo, leaving the coding upto you!  :wink :wink
Starting with some initial path, find all files (in a loop)
If it is directory (dir attrib is SET) and the directory is NOT "." or ".." then concatenate the directory name to the current directory and run the same loop again!
In case you want to run some "logic" on the files (change time/attrib etc) you have found, you can stick it in the else part of the if directory.

At the place you "went into" a directory (by concatenating the strings) you would also need to "go parent" (chop off the directory name you just "came out of").

I hope so much helps.

OR

You could check the source here:  :bg
http://www.masm32.com/board/index.php?topic=3026.msg32540#msg32540

Regards,
Shantanu
Title: Re: My attempt at directory recursion.
Post by: drizz on October 03, 2006, 08:06:22 PM
here is an example program i wrote, it searches "c:\program files" for "*.mp3"
directory is printed in the console title and file fiound to stdout.
it takes a callback in arguments so you can modify it to do something else easily.

[attachment deleted by admin]
Title: Re: My attempt at directory recursion.
Post by: Ehtyar on October 03, 2006, 11:01:04 PM
Well i am officially about to loose my mind. This is even more difficult to implement than CreateProcess (don't ask).
I just spent about another 2 hours working on this, using the example from drizz (good thing it's not working for me, i'm using your hashing routines aswell, might aswell be coded 100% by you :P) and from Tedd. I have concluded that this is entirely too much work for something that will most likely not be used. Fortunately, your examples have given me more insight into a lot of things that are going to help me a lot with this project. I'm going to make a start on it now, without the directory recursion. With any luck i'll have something by tonight or maybe tomorrow (i'm a little obsessive ;))
Generally im too pu**y to release my source code for fear i've made some stupid mistake and everyone will think i'm a dumba**. I guess that has already been accomplished today, so i thought what the hell. My first attempt, WITH source, will be posted tomorrow, thanks again for your help guys, and hope this thing is useful to you somehow.

Thankfully, Ehtyar.
Title: Re: My attempt at directory recursion.
Post by: hutch-- on October 04, 2006, 01:05:08 AM
I am not sure if I posted this one while I was playing with recursive directory code but it is basically very simple and as it only displays file names, its safe to play with without trashing anything.

I remember with some humour that one of the examples I was playing with on a spare partition that did recursive delete took everything out including the code for the recursive app. Only the EXE was left and it took out the asm file as well.  :red

[attachment deleted by admin]
Title: Re: My attempt at directory recursion.
Post by: PBrennick on October 04, 2006, 05:16:18 AM
Hutch,
Sounds like that delete program was well written!  Did you RE your executable?  :P

Paul
Title: Re: My attempt at directory recursion.
Post by: Ehtyar on October 05, 2006, 10:13:31 AM
Hey all. New post at http://www.masm32.com/board/index.php?topic=5858 for the SFV Generator. The first beta is posted.

Regards, Ehtyar.
Title: Re: My attempt at directory recursion.
Post by: Ehtyar on October 07, 2006, 01:46:32 AM
Drizz, it seems that your program does not return file names when specifying *.* as the file mask, just returns dir changes. Any thoughts?
Title: Re: My attempt at directory recursion.
Post by: ninjarider on October 07, 2006, 04:14:37 AM
what functions are you'll using for directory recursion
Title: Re: My attempt at directory recursion.
Post by: drizz on October 07, 2006, 01:47:52 PM
Quote from: Ehtyar on October 07, 2006, 01:46:32 AM
Drizz, it seems that your program does not return file names when specifying *.* as the file mask, just returns dir changes. Any thoughts?
patch :)
Quote from: FileSearch.Inc

98 invoke StrCmpi,sExt2,sExt1
99 mov edx,sExt1
100 .if !eax || word ptr [edx] == '*'


17 .if eax
18 .repeat
19 .break .if byte ptr [edx-1] == cl
20 dec edx
21 dec eax
22 .until zero?
23 invoke StrCpy,pOutBuff,edx
24 .endif

Title: Re: My attempt at directory recursion.
Post by: Ehtyar on October 08, 2006, 10:20:18 AM
Works beautifully, expect to see a better version of the SFV checker very soon :)
Title: Re: My attempt at directory recursion.
Post by: Shantanu Gadgil on October 10, 2006, 10:49:46 AM
Hi Ehtyar,
Did you try the "non-chdir" method for recursion?

Regards,
Shantanu
Title: Re: My attempt at directory recursion.
Post by: Ehtyar on October 11, 2006, 12:57:16 AM
I tried each method. Each crashed until drizz fixed his version. Now for some reason, although it works in his executable, it crashes in mine, still working on it :(
Title: Re: My attempt at directory recursion.
Post by: lingo on October 11, 2006, 06:15:00 PM
My faster proc will find recursively all files on disk c:\  :lol
When you start exe file wait and measure the time until the
exe failed
Press debug and next press two times F10 to load ecx and eax registers

ecx is all files on your disk c:\
eax is all subdirectories on your disk c:\

For example:
I have
eax=3E71h subdirs
ecx=28104h files on my disk c:\
and I need 2mins 15seconds about that

Regards,
Lingo

[attachment deleted by admin]