How to Check If There Are Symbolic Links Pointing to a Directory

Is there a way to check if there are symbolic links pointing to a directory?

I'd use the find command.

find . -lname /particular/folder

That will recursively search the current directory for symlinks to /particular/folder. Note that it will only find absolute symlinks. A similar command can be used to search for all symlinks pointing at objects called "folder":

find . -lname '*folder'

From there you would need to weed out any false positives.

How to check if a symbolic link refers to a directory

I thought all symbolic links pointed to folders

Nope. A symbolic link is an indirect reference to another path. That other path can refer to any kind of file that can be represented in any mounted file system, or to no file at all (i.e. it can be a broken link).

How to check that it points to a directory?

You mention the stat() function, but for reimplementing ls you should mostly be using lstat(), instead. The difference is that when the specified path refers to a symbolic link, stat returns information about the link's target path, whereas lstat returns information about the link itself (including information about the file type, from which you can tell that it is a link).

In the event that you encounter a symbolic link, you can simply check the same path again with stat() to find out what kind of file it points to. stat() will recursively resolve symbolic links to discover the information for the ultimate target, which will be a symbolic link only if it is a broken one. Any way around, you don't need to distinguish between a broken link and any other form of non-directory for your particular purpose.

How to find if a Path has been used as source for a symbolic link

The target of a symbolic link (at least in Linux) has no back-pointer to links that reference it. To find such links you'd have to scan the entire filesystem.

Resolve broken symbolic links without checking for existance

Turning my comment into an answer, I can see two options to figure out whether a file is a dead symbolic link:

  1. Use Files.readSymbolicLink() and then check whether the target exists.
  2. Use Files.exists() with different options: If the file exists with NOFOLLOW_LINKS but does not exist without that option then it should be a dangling symbolic link.

why are some cygwin symlinks not visible from a cmd.exe session

The reason why the links are not visible is due to their file Attribute

S = System are not visible in CMD by DOS/Windows design,

from CMD, sorry in German, we have:

$ cmd
Microsoft Windows [Version 10.0.19041.450]
(c) 2020 Microsoft Corporation. Alle Rechte vorbehalten.

D:\cygwin64\bin>attrib zipinfo
S D:\cygwin64\bin\zipinfo

D:\cygwin64\bin>dir zipinfo
Datenträger in Laufwerk D: ist DATA
Volumeseriennummer: D603-FB6E

Verzeichnis von D:\cygwin64\bin

Datei nicht gefunden

D:\cygwin64\bin>dir /A:S zipinfo
Datenträger in Laufwerk D: ist DATA
Volumeseriennummer: D603-FB6E

Verzeichnis von D:\cygwin64\bin

19.06.2018 22:17 16 zipinfo
1 Datei(en), 16 Bytes
0 Verzeichnis(se), 542.542.495.744 Bytes frei

Check if a file is real or a symbolic link

I have some source code for symlinks posted on my blog that will allow you to:

  • create symlinks
  • check whether a path is a symlink
  • retrieve the target of a symlink

It also contains NUnit test cases, that you may wish to extend.

The meaty bit is:

private static SafeFileHandle getFileHandle(string path)
{
return CreateFile(path, genericReadAccess, shareModeAll, IntPtr.Zero, openExisting,
fileFlagsForOpenReparsePointAndBackupSemantics, IntPtr.Zero);
}

public static string GetTarget(string path)
{
SymbolicLinkReparseData reparseDataBuffer;

using (SafeFileHandle fileHandle = getFileHandle(path))
{
if (fileHandle.IsInvalid)
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}

int outBufferSize = Marshal.SizeOf(typeof(SymbolicLinkReparseData));
IntPtr outBuffer = IntPtr.Zero;
try
{
outBuffer = Marshal.AllocHGlobal(outBufferSize);
int bytesReturned;
bool success = DeviceIoControl(
fileHandle.DangerousGetHandle(), ioctlCommandGetReparsePoint, IntPtr.Zero, 0,
outBuffer, outBufferSize, out bytesReturned, IntPtr.Zero);

fileHandle.Close();

if (!success)
{
if (((uint)Marshal.GetHRForLastWin32Error()) == pathNotAReparsePointError)
{
return null;
}
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}

reparseDataBuffer = (SymbolicLinkReparseData)Marshal.PtrToStructure(
outBuffer, typeof(SymbolicLinkReparseData));
}
finally
{
Marshal.FreeHGlobal(outBuffer);
}
}
if (reparseDataBuffer.ReparseTag != symLinkTag)
{
return null;
}

string target = Encoding.Unicode.GetString(reparseDataBuffer.PathBuffer,
reparseDataBuffer.PrintNameOffset, reparseDataBuffer.PrintNameLength);

return target;
}

That is:

  • Open the file with CreateFile()
  • Call DeviceIoControl() to get the reparse point data (NOTE: it could be a junction point!)
  • Check out the returned data structure to inspect. The reparse tag will tell you if it is a junction point or symbolic link. This may be all you want to do.

Are symbolic links harmful for understanding and maintaining code?

Although symbolic links by themselves shouldn't be harmful to the understanding and maintaining of the codebase, your case in kind of brutal. Puting a symlink in everyone of your files looks like overkill there. There are more options than just choosing betwen hardcodes paths and such a violent solution.

For example, you could set the path of these files in a constant that is loaded at the begining of each files through a require(), or many others solutions. In the end, it depends on the way your website works, but I doubt your solution is the most flexible you could come up with.



Related Topics



Leave a reply



Submit