Page 1 of 1

file loop listing the same files twice (identify redirected folders)

Posted: 18 Jan 2018, 10:03
by jeeswg
- I am interested in ways to identify whether a folder is a proper folder or some kind of redirected folder.
- One way is two check the attributes of a folder and all of it's ancestor folders.

Based on this post by Builder:
Possible A_LoopFileLongPath bug - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 47#p194747
It also will loop over a file twice if Windows has more than one way of referencing the address....

example...
D:\Documents and Settings\Thomas\Desktop\STARTUP.ahk
D:\Users\Thomas\Desktop\STARTUP.ahk
Based on these posts by Noesis:
Possible A_LoopFileLongPath bug - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 03#p195003
Possible A_LoopFileLongPath bug - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 52#p195052

Some code to compare two folders, which doesn't help to identify folder redirection on subfolders:

Code: Select all

;from winnt.h:
;FILE_ATTRIBUTE_READONLY := 0x1
;FILE_ATTRIBUTE_HIDDEN := 0x2
;FILE_ATTRIBUTE_SYSTEM := 0x4
;FILE_ATTRIBUTE_DIRECTORY := 0x10
;FILE_ATTRIBUTE_ARCHIVE := 0x20
;FILE_ATTRIBUTE_DEVICE := 0x40
;FILE_ATTRIBUTE_NORMAL := 0x80
;FILE_ATTRIBUTE_TEMPORARY := 0x100
;FILE_ATTRIBUTE_SPARSE_FILE := 0x200
;FILE_ATTRIBUTE_REPARSE_POINT := 0x400
;FILE_ATTRIBUTE_COMPRESSED := 0x800
;FILE_ATTRIBUTE_OFFLINE := 0x1000
;FILE_ATTRIBUTE_NOT_CONTENT_INDEXED := 0x2000
;FILE_ATTRIBUTE_ENCRYPTED := 0x4000
;FILE_ATTRIBUTE_INTEGRITY_STREAM := 0x8000
;FILE_ATTRIBUTE_VIRTUAL := 0x10000
;FILE_ATTRIBUTE_NO_SCRUB_DATA := 0x20000
;FILE_ATTRIBUTE_EA := 0x40000

;from:
;File Attribute Constants (Windows)
;https://msdn.microsoft.com/en-us/library/gg258117(v=vs.85).aspx
;FILE_ATTRIBUTE_RECALL_ON_OPEN := 0x40000
;FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS := 0x400000

;FileGetAttrib
;https://autohotkey.com/docs/commands/FileGetAttrib.htm
;R = READONLY
;A = ARCHIVE
;S = SYSTEM
;H = HIDDEN
;N = NORMAL
;D = DIRECTORY
;O = OFFLINE
;C = COMPRESSED
;T = TEMPORARY

;tested on Windows 7
;e.g. 0x2416, C:\Documents and Settings
;FILE_ATTRIBUTE_NOT_CONTENT_INDEXED := 0x2000
;FILE_ATTRIBUTE_REPARSE_POINT := 0x400
;FILE_ATTRIBUTE_DIRECTORY := 0x10
;FILE_ATTRIBUTE_SYSTEM := 0x4
;FILE_ATTRIBUTE_HIDDEN := 0x2

;tested on Windows 7
;e.g. 0x11, C:\Users
;FILE_ATTRIBUTE_DIRECTORY := 0x10
;FILE_ATTRIBUTE_READONLY := 0x1

q:: ;get file attributes
;vDir1 := "C:\Documents and Settings\" A_UserName "\Desktop"
;vDir2 := "C:\Users\" A_UserName "\Desktop"
vDir1 := "C:\Documents and Settings"
vDir2 := "C:\Users"
;MsgBox, % FileGetAttrib(vDir1) "`r`n" FileGetAttrib(vDir2)
MsgBox, % FileExist(vDir1) "`r`n" FileExist(vDir2)
vAttrib1 := DllCall("kernel32\GetFileAttributes", Str,vDir1, UInt)
vAttrib2 := DllCall("kernel32\GetFileAttributes", Str,vDir2, UInt)
MsgBox, % Format("0x{:X}`r`n0x{:X}", vAttrib1, vAttrib2)
return
- Btw we would probably benefit from some sort of 'A_LoopFileAttribNum' variable for file loops, to reduce overhead, if wanting to check the attributes of every file in a folder/on the hard drive for special properties.
- The attribute number should already be available in the WIN32_FIND_DATA structure that the AutoHotkey file loop uses. E.g. see this example for more details:
259-char path limit workarounds - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 06#p170806

- Here is an 'IsRedirected' function, although 'redirected' may or may not be the proper term for this.

Code: Select all

q:: ;is a file/folder redirected
vDir1 := "C:\Documents and Settings\" A_UserName "\Desktop"
vDir2 := "C:\Users\" A_UserName "\Desktop"
MsgBox, % IsRedirected(vDir1) ;0
MsgBox, % IsRedirected(vDir2) ;0

MsgBox, % IsRedirected(vDir1, 1) ;1

vDir1 := "C:\Documents and Settings"
vDir2 := "C:\Users"
MsgBox, % IsRedirected(vDir1) ;1
MsgBox, % IsRedirected(vDir2) ;0
return

IsRedirected(vPath, vDoRecurse:=0)
{
	while InStr(vPath, "\")
	{
		vAttrib := DllCall("kernel32\GetFileAttributes", Str,vPath, UInt)
		;FILE_ATTRIBUTE_REPARSE_POINT := 0x400
		if (vAttrib & 0x400) && !(vAttrib = 0xFFFFFFFF)
			return 1
		if !vDoRecurse
			return 0
		SplitPath, vPath,, vPath
	}
	return 0
}

Re: file loop listing the same files twice (identify redirected folders)

Posted: 18 Jan 2018, 19:49
by Builder
I tried your function...
Perhaps because it was inside a nested file loop, it got stuck. Apparently there was an issue with the while InStr.

I am uncertain of what the loop in your function was for, and I was equally uncertain of what the SplitPath was for, so I did some trimmng.

The result I arrived at works happily anywhere, whether several layers deep in a directory, or a folder in the root.

Code: Select all

IsRedirected(vDir)
	{
	;FILE_ATTRIBUTE_REPARSE_POINT := 0x400
	return (0x400 & DllCall("kernel32\GetFileAttributes", Str,vDir, UInt))
	}
Incidently, the command propmt is able to distinguish links

A listing if links in a directory can be obtained by typing

dir *.* /a:L

The beauty of the information the command prompt provides here is that it not only specifies the link, it also provides the folder it links to, and the type of link
ex.
2009-07-13 10:53 PM <JUNCTION> Documents and Settings [D:\Users]

Re: file loop listing the same files twice (identify redirected folders)

Posted: 18 Jan 2018, 20:52
by jeeswg
- I'll explain a few things here, which you might know, but they are there generally for the benefit of anyone reading.

- I should warn you that I'm not sure if your simplified function would work correctly, it could give false positives, and here's why. If the function fails for some reason, the DllCall would return 0xFFFFFFFF. If you then do 0xFFFFFFFF & 0x400, that returns 0x400 which is considered as true (since it is nonzero).
- A common fail code is -1, when -1 is stored by computers, as an unsigned integer, it is usually stored as (256 to the power of n) - 1, where n is the size in bytes of the integer, which will be a hex number made entirely of F's.
- The DllCall function is passed UInt as its final parameter, hence it will return a number which is a UInt.
- The maximum value for a UInt (which is 4 bytes in size), is 0xFFFFFFFF, which is the equivalent of -1. I.e. if you start at 0, and subtract 1, you wrap around to 0xFFFFFFFF, the maximum number a UInt can store.
- In a bitwise-and comparison:

Code: Select all

        0xFFFFFFFF := 11111111111111111111111111111111
             0x400 := 00000000000000000000010000000000
0xFFFFFFFF & 0x400 := 00000000000000000000010000000000
- You end up with 0xFFFFFFFF & 0x400 = 0x400, and since 0x400 is not 0, AHK regards it as true.

- I believe that this simplified function would work:

Code: Select all

IsRedirectedSimple(vPath)
{
	vAttrib := DllCall("kernel32\GetFileAttributes", Str,vPath, UInt)
	;FILE_ATTRIBUTE_REPARSE_POINT := 0x400
	return !!(vAttrib & 0x400) && !(vAttrib = 0xFFFFFFFF)
}
- Here's a demonstration of how SplitPath works:

Code: Select all

q:: ;SplitPath demo
vPath := A_ScriptFullPath
SplitPath, vPath, vName, vDir, vExt, vNameNoExt, vDrive
MsgBox, % Format("{}`r`n{}`r`n{}`r`n{}`r`n{}`r`n{}", vPath, vName, vDir, vExt, vNameNoExt, vDrive)

vOutput := vPath
while InStr(vPath, "\")
{
	SplitPath, vPath,, vDir
	vPath := vDir
	vOutput .= "`r`n" vPath
}
MsgBox, % vOutput
return
- I have since updated my function in my original post. It now has a DoRecurse option. By default, it will only check if the current file/folder is redirected, if recurse is allowed, it will check if any of the ancestor folders are redirected.
- Based on what Noesis said, and as shown in my example in the OP, it appears that checking a file/folder directly, to see if it is redirected, doesn't always work, if the check states that the file is not redirected, you have to check its ancestors to be sure.

Re: file loop listing the same files twice (identify redirected folders)

Posted: 18 Jan 2018, 21:24
by jeeswg
Here's a command line example that uses dir.
E.g. (your example): 2009-07-13 10:53 PM <JUNCTION> Documents and Settings [D:\Users]

Code: Select all

;[based on 'list environment variables' example]
;jeeswg's Explorer tutorial - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?t=31755

;Dir | Microsoft Docs | Microsoft Docs
;https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-R2-and-2012/cc755121(v=ws.11)

q:: ;list dirs on C:
DetectHiddenWindows, On
Run, % ComSpec,, Hide, vPID
WinWait, % "ahk_pid " vPID
DllCall("kernel32\AttachConsole", UInt,vPID)
oShell := ComObjCreate("WScript.Shell")
oExec := oShell.Exec(ComSpec " /c dir C:\*.* /a:L")
vStdOut := ""
while !oExec.StdOut.AtEndOfStream
	vStdOut := oExec.StdOut.ReadAll()
Clipboard := vStdOut
DllCall("kernel32\FreeConsole")
Process, Close, % vPID
MsgBox, % vStdOut
return