file link

file link creates links in the filesystem.

Attributes

introduced in version
8.4a5

Synopsis

file link ?-linktype? linkname ?target?

Description

If only one argument is given it is the name of a link, and the result is the target of that link. If linkName isn't a link the result is an error. If two arguments are given, the first is the name of a link and the second becomes the target of that link. If linkName already exists, target doesn't exist, or the target is a link whose ultimate target does not exist, the result is an error.

-linktype is either -symbolic or -hard, and indicates the type of link to create. The default is -symbolic if the filesystem allows it. If an explicitly indicated type is not available, the result is an error. Windows 95, 98 and ME do not currently support links, but most Unix platforms support both symbolic and hard links (the latter for files only), MacOS supports symbolic links and Windows NT/2000/XP (on NTFS drives) support symbolic directory links and hard file links.

Platform-dependent note
On posix filesystems systems the target of a symbolic link can be a relative path, and that path is relative to the location of the link (not to the current working directory), but on platforms where relative links are not supported the target of a link is normalized before the link is created. Normalization proceeds relative to the current working directory.

NTFS links

On Windows NT/XP (NTFS filesystem) this can be used to create symbolic directory links (a little known feature of Windows) or hard file links (an almost as little known feature of Windows).

Intentional broken symlinks

LEG wants a -force option to forcibly create symbolic links with non-existing targets. This is e.g. needed when moving directory trees around, or when symbolic links are abused as information placeholders like it is done with the fnord webserver.

mjs agrees, the requirement that the target exist for a symbolic link is an arbitrary (and bad) choice. Perhaps the option should be -nocomplain to be consistent with e.g. glob?

EMJ 2014-02-12 : On his own page, Poor Yorick has this on a Todo list, without any suggestion of an option. If it is needed at all I think it should require -nocheck, as -force should probably mean allowing overwriting an existing file if necessary and -nocomplain is too tame for an action that is quite likely to be a bad idea. If you don't think it's a bad idea, search the web for broken symlink and dangling symlink to see all the people wanting to find and remove them as they cause so many problems. LEG's examples above of needing to do this don't convince me at all. I don't see why you need it when moving directory trees around, and any person or program that misuses symlinks (or any other OS feature) for unintended purposes deserves any blame they get from confused users. Symlinks are meant to be mostly invisible.

PYK 2014-02-12: The issue is about more than creating symlinks that don't exist, but creating symlinks that file link can't be sure exist. For example:

file link -symbolic /path/to/linkname ../../../target

If pwd is not /path/to/linkname, file link will refuse to create the link, even if ../../../target is a valid existing target.

EMJ: That statement is based on a misunderstanding, see the platform-dependent note above (which is from the file manpage).

PYK: Yes, that's true. I went back and found the scenario that prompted me to put this on my to-do list: the program creates a symlink to a target prior to creating the target. It's done this way to ensure that there are no orphan targets. If the program is interrupted after it creates the symlink and before it creates the target, the broken symlink serves as a marker to indicate where it left off, so that it can properly resume. The inability of file link to create a broken symlink also broke that workflow. The program was translated from Python, which happily creates broken symbolic links.

EMJ: Of course Unix/Linux allow dangling (their chosen word) symlinks to be created. So it would be nice to know why file link doesn't (anybody????). In your case they are transient (and presumably almost never left broken), but I still can't help thinking that there must be a better (and portable) design here. And I still think that programs should almost never create or check for symlinks.

Incidentally, what happens in your case if a (possibly scheduled) broken symlink cleaner happens by after you create the symlink and before you create the target?

PYK: Also, the fact that people don't know how to remove broken symlinks is really only indicative of the fact that people don't know how to remove broken symlinks.

EMJ: They are asking because they don't know, but my point is that it is indicative of a desire to remove them!

PYK: And that fact is only indicative of the fact that sometimes they need to be removed ;) Broken symlinks can be useful, as the workflow I described above illustrates.

AMG: I want this functionality as well.

LVwikignome - 2010-04-28 08:44:41

When you feel the topic is clear enough, the way to get the change considered is to request a TIP (Tcl Improvement Proposal) for the change. I'd recommend recruiting a champion from the TCT (Tcl Core Team) to help you through the process. Also, if you are uncertain about your ability to add the code for this change, you might recruit a Tcl C developer to look over your shoulder and help.

Good luck - it sounds like a useful change.

AMG, many years later: I still want this functionality, but finally I know how to implement it in pure Tcl. It's so simple that I'm embarrassed I didn't think of it a decade ago. Create a temporary file with the target name before creating the link, then delete the temporary file afterwards. Granted, this won't allow creating a broken symlink to a non-writable location (e.g. /), but it's better than what we currently have.

Additional refinement: allow broken symlinks into nonexistent directories. To make this easier to implement, rather than link to a temporary file, I link to a temporary directory. This lets me use file mkdir to create the hierarchy and the temporary target all at once.

It turns out this is tougher than I first thought! There are some tricky and dangerous corner cases involving ".." path components. The following should work though:

proc fileLink {name target} {
    set name [file normalize $name]
    set dummy [file join [file dirname $name] $target]
    if {[file exists $dummy]} {
        file link $name $target
    } else {
        set delete {}
        set prefix {}
        foreach part [file split $dummy] {
            set prefix [file normalize [file join $prefix $part]]
            if {![file exists $prefix]} {
                lappend delete $prefix
            }
        }
        try {
            file mkdir $dummy
            file link $name $target
        } finally {
            file delete -force {*}$delete
        }
    }
}

Limitations:

  • Target must be in a writable directory
  • If target directory does not exist, its nearest existing ancestor must be writable
  • Cannot make a symlink that points to itself
  • Consecutive and trailing slashes are stripped from the link target
  • All path components other than the last must be directories, symlinks to directories, or nonexistent

HE 2021-02-14: I was hit today by the same issue. It's a shame that this is not fixed since all this time. I know it is the documented behavior but, it is not possible to restore a link queried with 'file link' later. Therefore, I count this an error. It doesn't matter if a link to a non existing target is good style. It is reality and Tcl has to deal with it. For example I have a backup program written in Tcl and I'm now not able to restore the data completely.

@LVwikignome Don't ask for a TIP. I'm a Tcl user not a C programmer. So I can't implement it. And you state yourself that I not have to write the TIP only. I also have to assure that it is implemented. This is nothing I can cover.

Moreover, this is something normal maintenance should add after all the time. It is not begging for a new function. It is simply to complete an incomplete functional design.

However, my workaround for this is to use the shell command ln from inside Tcl:

proc linkCreate {target linkname} {
    exec ln -s $target $linkname
    return
}

Unwanted Slash Tidying

AMG: The [file link] documentation is unclear on the return value when given a target argument, i.e. when creating a link. By analogy with the no-target case, [file link] appears to return the link target. However, there is a discrepancy when multiple slashes are used right next to each other and/or when there is a trailing slash. The extra slashes are part of the return value, but they are not stored in the link target. This creates a problem for the fnord webserver, as LEG points out above. fnord expects symlinks taking the form http://wiki.tcl-lang.org/ and so on, which require multiple slashes in a row and have optional trailing slashes.

I think the proper solution is to make [file link] stop consolidating consecutive slashes and stripping trailing slashes when creating links. We might as well fold that change into a future TIP adding native support for creating broken symlinks.

Obsolete Discussion

On MacOS, links are also supported (often called 'aliases'), but we need a patch like the one above to allow links to be created (i.e. the TclpObjLink function in tclMacFile.c needs completing).

Windows 95/98/ME etc don't support links very much at all, but Windows NT/2000/XP using the NTFS filesystem (version 5, I think), do! See http://www.hlm.inc.ru/ for creating file-links, and http://www.rekenwonder.com/linkmagic.htm , http://windows.oreilly.com/news/win2kcommands_0401.html#linkd , http://www.codeproject.com/w2k/junctionpoints.asp , http://www.sysinternals.com/ntw2k/source/misc.shtml#junction for directory-links (the last two contain source code to create and query such links).

DKF - You could handle the 95/98 case by simply reporting that the OS/FS doesn't support links (IIRC, supposedly not all Unix FSes support links either, though I've never encountered one which had problems that wasn't a mount of something derived from CP/M,DOS,etc...) If only shortcuts weren't the work of the devil incarnate after more than a few beers!

Vince - Indeed, in Tcl 8.3 'file readlink' of course just returns 'invalid argument' under all versions of Windows. I've now uploaded a version of the patch to the sourceforge link above which contains an implementation for unix and windows.

RM: file link can not create relative links:

 sh>> ln -s ./a ./b

is different to

 tclsh>> file link -symbolic ./b ./a

The complete path can be a problem on mounted filesystems.

Vince: This has been addressed in Tcl 8.5.

Original proposal

Purpose: to discuss the possibility of adding a new 'file link' command to Tcl. [L1 ]

AMG: This URL is broken because Google.