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
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
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** :(
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
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
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.
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
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
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
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
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
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
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]
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.
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]
Hutch,
Sounds like that delete program was well written! Did you RE your executable? :P
Paul
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.
Drizz, it seems that your program does not return file names when specifying *.* as the file mask, just returns dir changes. Any thoughts?
what functions are you'll using for directory recursion
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
Works beautifully, expect to see a better version of the SFV checker very soon :)
Hi Ehtyar,
Did you try the "non-chdir" method for recursion?
Regards,
Shantanu
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 :(
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]