News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Adventures in programming: Treeviews, directory scanning, recursion

Started by NoCforMe, April 05, 2024, 10:36:19 AM

Previous topic - Next topic

sinsi

Looking at you original code, you might want to put those 2 big locals (fd:WIN32_FIND_DATA, pathBuffer[256]:BYTE) into an allocated buffer and just keep a local pointer to it so you can free it when the pro returns.

Faulting application name: PicView.exe, version: 0.0.0.0, time stamp: 0x6614b05f
Faulting module name: ntdll.dll, version: 10.0.22621.3374, time stamp: 0x3fddb55c
Exception code: 0xc00000fd
Fault offset: 0x0004b5a1
Faulting process ID: 0x0x3088
Faulting application start time: 0x0x1DA8A2EE32DFEC1
Faulting application path: C:\Users\xxxxx\AppData\Local\Temp\7zO400FDA49\PicView.exe
Faulting module path: C:\WINDOWS\SYSTEM32\ntdll.dll
Report ID: 991abc49-4d49-4380-bf64-f577108901da
Faulting package full name:
Faulting package-relative application ID:
🍺🍺🍺

NoCforMe

Dang, forgot all about those locals taking up stack space!

New one attached to #69 as before.

BTW, no need to "allocate" anything; I just put those two in .data.
Assembly language programming should be fun. That's why I do it.

sinsi

Time for some source code to get any further.
Faulting application name: PicView.exe, version: 0.0.0.0, time stamp: 0x6614bbd8
Faulting module name: ntdll.dll, version: 10.0.22621.3374, time stamp: 0x3fddb55c
Exception code: 0xc00000fd
Fault offset: 0x0004a9ba
Faulting process ID: 0x0x28C8
Faulting application start time: 0x0x1DA8A31FD971CFB
Faulting application path: C:\Users\xxx\AppData\Local\Temp\7zOCFE6E6EE\PicView.exe
Faulting module path: C:\WINDOWS\SYSTEM32\ntdll.dll
Report ID: fa3dea85-810f-459b-afff-17ea8e182972
Faulting package full name:
Faulting package-relative application ID:
🍺🍺🍺

NoCforMe

Assembly language programming should be fun. That's why I do it.

jj2007

Builds by simply hitting F6, and works like a charm :thumbsup:

Task Manager: Gdi and user objects are stable, but working memory leaks a bit.

Sinsi, how did you make it crash?

sinsi

Quote from: jj2007 on April 09, 2024, 05:06:41 PMSinsi, how did you make it crash?
Selected my C:. Maybe it's the depth of the directory tree. One thought I had was what happens if you try and search a junction/reparse point?
🍺🍺🍺

sinsi

You really need to read up on the functions you use, not just assume they are all the same.

FindFirstFile returns a handle if it succeeds.
If it fails, it returns INVALID_HANDLE_VALUE (which is -1, not 0 as you seem to have assumed) and GetLastError returns an error code, the one you are interested in is ERROR_FILE_NOT_FOUND.

FindNextFile returns a BOOL, so non-zero if it succeeds.
If it fails, it returns 0 and GetLastError returns an error code, the one you are interested in is ERROR_NO_MORE_FILES.

Now, when your code gets to FindFirstFile, it will never throw an error because of how you are testing for one.
The problem is when you hit a directory you don't have access to. If you checked GetLastError you would get error 5 (ACCESS_DENIED) but your code just keeps adding the failed directory name to the end of the search string, so you get something like
"C:\Windows\appcompat\appraiser\UA\UA\UA\UA\UA\UA\UA\UA"and eventually run out of stack.
🍺🍺🍺

NoCforMe

Quote from: sinsi on April 09, 2024, 07:51:14 PMThe problem is when you hit a directory you don't have access to. If you checked GetLastError you would get error 5 (ACCESS_DENIED) but your code just keeps adding the failed directory name to the end of the search string, so you get something like
"C:\Windows\appcompat\appraiser\UA\UA\UA\UA\UA\UA\UA\UA"and eventually run out of stack.
OK, just to address this one case: I'm trying to understand the proper sequence here. Are you saying that even if FindFirstFile() returns successfully after finding a directory, that the directory may be inaccessible? Meaning that FindFirstFile() will return a valid search handle but that GetLastError() will return an error code?

If that's the case then I would need to call GetLastError() every time I get a valid result from FindFirstFile(), correct?

BTW, you may have noticed what looks like a weird quirk in my code, which is comparing a folder/file returned to the character ':'. This is because earlier when I was using FindFirstFile() to scan a disk, I was getting these weird entities, never did find out what exactly they were, that either consisted of or started with that character, which of course is an illegal folder/filename character.
Assembly language programming should be fun. That's why I do it.

zedd151

Quote from: NoCforMe on April 10, 2024, 03:40:25 AMAre you saying that even if FindFirstFile() returns successfully after finding a directory, that the directory may be inaccessible?
You need to check the file/directory attributes.  :icon_idea: I had to tinker with that some time ago while creating an exhaustive recursive file list. The details of which attributes escape me at the moment though. Further research necessary. I do remember though that some were marked 'Hidden' or 'Archived' I think those gave some issues...
Use
wfd.dwFileAttributes to get the attributes

Some others to check for:

FILE_ATTRIBUTE_REPARSE_POINT    The file has an associated reparse point.
FILE_ATTRIBUTE_SYSTEM

attached "lister5" for your amusement
this one is hard coded to scan for all files/folders in C:
It outputs file "files.txt" in the program folder, and is not not a command line tool

I have another version that outputs 2 files, dirs.txt and files.txt.
One for directory listings (dir.txt) and the other for files (files.txt)
Ventanas diez es el mejor.  :azn:

fearless

You will probably need to check for "." and ".." in file listings as they are used as shortcuts - originally under DOS to indicate current directory "." and parent directory ".." hence why you can sometimes use a reference like ".\file_in_this_folder.txt" or "..\file_in_parent_folder.txt" or even more indirect references with multiple ones like "..\..\some_folder\some_file.txt".

Each sub-folder from the root drive will have a "." and ".."

Open a dos command prompt, goto a folder "cd c:\windows", type "dir" and see the dot references:

C:\Windows>dir
 Volume in drive C is Windows
 Volume Serial Number is 8A6D-FA9C

 Directory of C:\Windows

02/04/2024  17:56    <DIR>          .
02/04/2024  17:56    <DIR>          ..
07/12/2019  15:52    <DIR>          addins
10/05/2023  09:53        2,482,672 ampa.exe
08/06/2021  12:14            1,328 ampa.ini
27/07/2023  01:59    <DIR>          appcompat
24/01/2024  21:42    <DIR>          apppatch



NoCforMe

Quote from: fearless on April 10, 2024, 04:13:41 AMYou will probably need to check for "." and ".." in file listings as they are used as shortcuts
You obviously haven't looked at my source; that's the very first thing I do after finding a folder.

I've known about those since DOS days.
Assembly language programming should be fun. That's why I do it.

NoCforMe

Quote from: sudoku on April 10, 2024, 04:08:13 AMSome others to check for:
FILE_ATTRIBUTE_REPARSE_POINT    The file has an associated reparse point.
FILE_ATTRIBUTE_SYSTEM
That first one looks like something I should be checking for and eliminating from further search. I didn't know about that attribute.

Then there's FILE_ATTRIBUTE_VIRTUAL, of which Micro$oft says "This value is reserved for system use.".
Assembly language programming should be fun. That's why I do it.

zedd151

Quote from: NoCforMe on April 10, 2024, 04:50:10 AMThen there's FILE_ATTRIBUTE_VIRTUAL, of which Micro$oft says "This value is reserved for system use.".
I didn't know about that one.  :tongue:
I wonder what hard linked files are attributed as.
Ventanas diez es el mejor.  :azn:

sinsi

You can search C:\Windows and find a folder called appcompat
On your next recursive call you search C:\Windows\appcompat and will get an access denied error.

Your function should return an error code (0 to continue the search, GetLastError if an error occured) so you can skip the search - ejecting a CD in the middle of a search, losing a network connection etc.

    invoke FindFirstFile,...
    cmp eax,INVALID_HANDLE_VALUE
    jnz @f
        call GetLastError
        cmp eax,ERROR_FILE_NOT_FOUND
        jnz finished ;return the error
        xor eax,eax
        jmp finished ;return "all ok"
@@: ;process it
    invoke FindNextFile,...
    test eax,eax
    jnz @b
        call GetLastError
        cmp eax,ERROR_NO_MORE_FILES
        jnz finished ;return the error
        xor eax,eax
finished:
    ret
Since you build your list first, you would have to delete the object from the list, or just leave it there.
🍺🍺🍺

sinsi

You won't be able to tell if you have access to a folder until you actually try and access it, looking at dwFileAttributes won't tell you since it's an NTFS permission, not a file attribute.
🍺🍺🍺