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:
- Use
Files.readSymbolicLink()
and then check whether the target exists. - Use
Files.exists()
with different options: If the file exists withNOFOLLOW_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
Using Bash Script to Feed Input to Command Line
Save and Restore Terminal Content
Is \D Not Supported by Grep's Basic Expressions
Add Text to File at Certain Line in Linux
Cmake:Set Environment Variables from a Script
Hadoop: «Error:Java_Home Is Not Set»
Why Is "Echo Foo | Read a ; Echo $A" Not Working as Expected
Chmod - Protect Users' File Being Accessed So Only Owner Can Access
Oracle:Io Exception: the Network Adapter Could Not Establish the Connection
Selecting a Linux I/O Scheduler
Portable Way to Get File Size (In Bytes) in the Shell
What Is the Command to Match Brackets in Emacs
Linux Execute Command Remotely
Linux Configure/Make, --Prefix
Finding Dlls Required of a Win Exe on Linux (Cross-Compiled with Mingw)