Detecting if a directory is a junction in Delphi
Asked Answered
Q

2

16

I've been Google searching this I may be having some brain clouds because it just isn't working.

I need to detect if a folder is a junction so my recursive file search doesn't run off into an endless loop.

I could use a simple function like

IsJunction(attr: dword): boolean; 

where attr is dwFileAttributes from TWin32FindData;

I just can't seem to get it to work. Thanks!

Quarterstaff answered 14/11, 2012 at 16:15 Comment(3)
I rolled back the question. Your edit completely changed the question. The question you asked has been answered expertly by Sertac. The next step for you is to accept that answer. If you cannot make your find function work, that can be the subject of another question. Please, one question at a time, and don't move the goal posts.Woolcott
I disagree and don't see it as a different question but whatever. Thanks.Quarterstaff
It's obviously a different question. Sertac gave you a functioning IsJunction. Suppose someone had then answered fixing the bug in your search code. Now, which of the two answers would you accept? Because a question can only have one accepted answer, it follows that questions can only ask a single question. At least, that's my take from having answered thousands of questions!! ;-)Woolcott
C
12

dwFileAttributes of TWin32FindData does not have that information, you have to look to the dwReserved0 field. See documentation.

function IsJunction(const FileName: string): Boolean;
//  IO_REPARSE_TAG_MOUNT_POINT = $A0000003;
var
  FindHandle: THandle;
  FindData: TWin32FindData;
begin
  Result := False;
  FindHandle := FindFirstFile(PChar(FileName), FindData);
  if FindHandle <> INVALID_HANDLE_VALUE then begin
    Result := (Bool(FindData.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT))
              and Bool(FindData.dwReserved0 and $80000000) // MS bit
              and Bool(FindData.dwReserved0 and $20000000) // name surrogate bit
              and (LoWord(FindData.dwReserved0) = 3); // mount point value
    winapi.windows.FindClose(FindHandle);
  end else
    RaiseLastOSError;
end;
Coonan answered 14/11, 2012 at 18:24 Comment(10)
The dwFileAttributes field includes the FILE_ATTRIBUTE_REPARSE_POINT flag (the doc you linked to even says so). You only need to look at the dwReserved0 field if you want to access the actual reparse point information, such as the reparse point tag value.Langsdon
@Remy, yes. I actually commented the same thing to David's answer and then upvoted his answer when he added the latter function. But the question indeed seems to be actually asking to identify a junction point.Coonan
+1 Very good. I simply had not realised that you can skip the DeviceIoControl call if all you need is the reparse tag. This is a much better answer than mine.Woolcott
I am still getting results like: C:\ProgramData\Application Data\Application Data\Application Data\Application Data\Application Data\Application Data\Application Data\Application Data\Application Data\Application Data\Application Data\Application Data\Application Data\Common Files\ with that function where it should be skipping the folder completely as it is a junction.Quarterstaff
@Quarterstaff - Then you've some other error in your code. I tested both this post and David's answer to return true for IsJunction for 'C:\ProgramData\Application Data'.Coonan
Indeed. When you are trying to debug a problem, don't pick a complex test environment. Pick the simplest environment possible. A simple call to IsJunction. Does it give the right answer or not? If it does, then add it in to your program. If your program then fails, you know to look at your program rather than IsJunction.Woolcott
I updated my question with the full code and how it is implemented.Quarterstaff
@David - Your answer was quite fine IMHO. First, it was not wrong, and second, it included a valuable suggestion about other reparse points.Coonan
@Sertac I know, and thanks. Yours is just better. It's the right answer to the question. I think this is a good question and it deserves your answer not to be diluted.Woolcott
@Quarterstaff - alternatively, after the 'if dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY > 0 then begin' line put 'if not IsJunction(FFindData) then' and remove the first IsJunction. (I removed my other suggestion/comment, this is better I think.)Coonan
T
7

You can try also JCL (JEDI Code Library) JclNTFS unit.
it has a few methods to deal with junctions e.g:
NtfsIsFolderMountPoint / NtfsGetJunctionPointDestination.

Tichon answered 14/11, 2012 at 17:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.