TCC failing to read recursive symlinks

Aug 23, 2010
277
2
#1
Code:
@ECHO OFF
ECHO ECHO ===^^^> Called as ^%0 > 0.btm
MKLINK /A 1.btm 0.btm
MKLINK /A 2.btm 1.btm
DO F IN /L 2 1 0
  DIR /B %F.btm
  CALL %F.btm
ENDDO
DEL /Q ?.btm
Code:
[…]$ testlinks.btm
Symbolic link created for 1.btm <<===>> …\0.btm
Symbolic link created for 2.btm <<===>> …\1.btm
2.btm […\1.btm]
1.btm […\0.btm]
===> Called as 1.btm
0.btm
===> Called as 0.btm
 
Aug 23, 2010
277
2
#7
Argue as you wish, this is not normal program behavior and I know no way to exhibit it, short of manually resolving links. Which is absolutely unnecessary, unless you want to specifically operate on the link itself.

Also, I don't understand your last message.
 
#10
It will open the file for reading…
I've tried a number of ways to replicate the TCC behavior with the tools at hand, to no avail.
Even a program written in Delphi 7 over 13 years ago has absolutely no issues reading through symlinks.
TCC resolves the link OK, it just doesn't try to recurse when you ask what the link points to.

Code:
2018-03-25  19:54              25  0.btm
2018-03-25  19:54     <SYMLINK>    1.btm [V:\0.btm]
2018-03-25  19:54     <SYMLINK>    2.btm [V:\1.btm]
Code:
v:\> do i=0 to 2 ( type %i.btm )
ECHO ===^> Called as %0
ECHO ===^> Called as %0
ECHO ===^> Called as %0
 
#11
I tried GetFinalPathNameByHandle() in a little plugin (re-using the name "@IPOW"). It won't do everything @TRUENAME needs, but it does follow a chain of symbolic links and even sees through SUBSTs.
Code:
v:\> subst | grep V:
V:\: => H:\work

v:\> echo %@ipow[2.btm]
\\?\H:\work\0.btm

v:\> echo %@ipow[v:\2.btm]
\\?\H:\work\0.btm
And, FWIW, @TRUENAME also does not follow a chain of symbolic links.
Code:
v:\> echo %@truename[v:\2.btm]
V:\1.btm

v:\> echo %@truename[v:\1.btm]
V:\0.btm
 
Aug 23, 2010
277
2
#12
2.btm IS a link to 1.btm.
Of course. Where did I say the contrary?
TCC resolves the link OK, it just doesn't try to recurse when you ask what the link points to.
wat
You don't friggin' need to do anything specific to open a file. You don't even need to know that symlinks exist.
OS will do everything for you.
And, FWIW, @TRUENAME also does not follow a chain of symbolic links.
@TRUENAME is fundamentally broken. Don't use it. Don't rely on its behavior.
 
#13
Then I missed the point of your original post ... sorry. I thought you were pointing out that TCC doesn't give 0.btm as the target of 2.btm.

Now I see what's happening (and your original point). If I try to execute 2.btm, I get nothing.
 

rconn

Administrator
Staff member
May 14, 2008
10,639
97
#15
It's Windows that's failing, not TCC. TCC is querying (recursively) the reparse point for the file size (via a DeviceIoControl API call) so it can allocate the .BTM buffer, but the API is returning 0. So TCC thinks the batch file is empty, and executing it returns the (expected) result of nothing.

Easy workaround: use .CMD files instead of .BTM.
 
Aug 23, 2010
277
2
#17
I don't understand your problem, sorry.

Delphi 7. Year 2002. Several years before file symlinks introduction in Windows Vista.
Code:
program LinksTest;
{$APPTYPE CONSOLE}
{$D-}

uses
  Windows;

var
  f: hFile;
  pHandleInfo: _BY_HANDLE_FILE_INFORMATION;

begin
  f := CreateFile(PChar(ParamStr(1)), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

  if GetFileInformationByHandle(f, pHandleInfo) then begin
    WriteLn(ParamStr(1), ': ', pHandleInfo.nFileSizeLow);
  end;

end.
Works like a charm. No magic required at all.
 
#18
Curious ... why DeviceIoControl?

When I have 2.btm ==> 1.btm ==> 0.btm, CreateFile(L"v:\\2.btm, ...) sees right through the links and using the returned HANDLE, GetFileSizeEx gives the size of 0.btm and ReadFile reads 0.btm
 

rconn

Administrator
Staff member
May 14, 2008
10,639
97
#20
Curious ... why DeviceIoControl?

When I have 2.btm ==> 1.btm ==> 0.btm, CreateFile(L"v:\\2.btm, ...) sees right through the links and using the returned HANDLE, GetFileSizeEx gives the size of 0.btm and ReadFile reads 0.btm
Because TCC needs far more info about the reparse point than is available with CreateFile or GetFileSizeEx.
 
#21
Because TCC needs far more info about the reparse point than is available with CreateFile or GetFileSizeEx.
Admitted: I'm naive. But what, other than the size and content, does TCC need to run a batch file? If Windows automatically gives TCC the ultimate target, why does TCC even care if the file name given is the name of a reparse point?
 
#24
This is supposedly(?) fixed(?) in 22.0.42.

At least I'm unable to exhibit the issue in the environment where I observed it previously.
It doesn't look any better here.
Code:
v:\> MKLINK /A 1.btm 0.btm
Symbolic link created for 1.btm <<===>> V:\0.btm

v:\> MKLINK /A 2.btm 1.btm
Symbolic link created for 2.btm <<===>> V:\1.btm

v:\> d ?.btm
2018-03-26  21:45          11,591  0.btm
2018-05-26  13:28     <SYMLINK>    1.btm [V:\0.btm]
2018-05-26  13:28     <SYMLINK>    2.btm [V:\1.btm]

v:\> ver

TCC  22.00.42   Windows 7 [Version 6.1.7601]
 
Aug 23, 2010
277
2
#25
Original problem was that I was unable to run scripts from 2-level symlink. (dev.env -> staging ->> deployed apps)
Directory listing you show is correct as far as directory listing goes.