4

Am trying to run the below code in Perl:

symlink($oldname,$newname) or die print "$!\n";

but I get an error saying:

The symlink function is unimplemented at C:\...\CreateSymlink.pl line 14.

If I change the code to:

link($oldname,$newname) or die print "$!\n";

then the hard links are being created without errors.

Using activestate Perl and Windows 7 32-bit.

Any ideas why this is happening? I am trying to create symbolic links for a file.

P.S: I am a total newbie to Perl.

Eddy Freddy
  • 1,820
  • 1
  • 13
  • 18
Red
  • 81
  • 1
  • 1
  • 5
  • 4
    googling `windows symlink perl` returns lots and lots of information about this. The short answer is that there's no such thing as a "symlink" like there is in *nix in windows. The perl docs tell you that if the underlying OS doesn't support symlinks, `symlink` will fail. – Brian Roach Oct 22 '11 at 21:13
  • 1
    @Brian Roach Sure there is ... well, in windows versions released in the past 5 years ;-) –  Oct 22 '11 at 21:14
  • @pst - note the words "like there is in *nix". They're ... not the same. You'd think activestate would do something rather than just fail, but they don't. – Brian Roach Oct 22 '11 at 21:14
  • @Brian Roach Ever use mklink? It's not well know, but has not failed me yet for a "symbolic link"... I'm sure there are subtle differences, but I have not looked into it further. Junction-points are indeed different beasts. –  Oct 22 '11 at 21:16
  • 2
    @pst - that's not available in perl; it's a system command. Add the fact that you need to be running with elevated privileges to create an NTFS symlink and I'm going to stick with "Not the same" – Brian Roach Oct 22 '11 at 21:19
  • @Brian Roach Ah hah! So it *could* be implemented with the "restriction" which can be controlled per machine policy... I did update my answer with the restriction, I guess I'm just "always a god" on this box ;-) –  Oct 22 '11 at 21:21
  • How come NTFS hard link is being created but not the symbolic link? Running same code with the above mentioned difference. – Red Oct 22 '11 at 21:39
  • 1
    @BrianRoach Junctions (directory symlinks) at least could be created without requiring elevated permissions. – antred Nov 27 '20 at 13:28
  • @BrianRoach There are true symlinks in NTFS. As symlinks, they are the same. The implementation depends on the file system, not the OS. If symlink management has different restritions of use in Windows, that's a completely unrelated matter. Perl should create, test and read symlinks in NTFS like it does for filesystems in *nix. They work in the same way, they are different just in terms of how they are implemented. But Perl developers just haven't cared so far about the current portability in Win32, coming from a past where it was not supported and just not an existent feature in Win32. – Francisco Zarabozo Apr 23 '21 at 17:26

2 Answers2

9

Which "kind" of "symbolic link"? ;-)

Oh, and read the symbolic link Wikipedia article above for the mklink command ;-) Back-ticks (or system) can be a good friend, but note:

The default security settings in Windows Vista/Windows 7 disallow non-elevated administrators and all non-administrators from creating symbolic links. This behavior can be changed [by a security policy setting]....

Happy coding.


The WinAPI CreateSymbolicLink function might be useable directly; I am not sure if it "suffers" from the same restriction as a mklink command above. However, this thread indicates it is still in effect.


FWIW, this "works" in Strawberry Perl 5.12. YMMV, I just typed this up and have never used it otherwise :-)

use Win32::API;
$fn = Win32::API->new(
    # Note "A" function, IDK how to use Unicdoe
    "kernel32", "BOOLEAN CreateSymbolicLinkA(LPTSTR lpSymlinkFileName, LPTSTR lpTargetFileName, DWORD flags)"
);

unlink("src.txt");
unlink("lnk.txt");
open(FH,">src.txt") or die $!;
close(FH);

print "src.txt exists? " , (-f "src.txt"), "\n";
print "lnk.txt exists? " , (-f "lnk.txt"), "\n";
$hr = $fn->Call("lnk.txt", "src.txt", 0);
print "Result: ", $hr, "\n";
print "lnk.txt exists? ", (-f "lnk.txt"), "\n";

open(FH,">>src.txt") or die $!;
print FH "hello world!\n";
close(FH);

open(FH,"<lnk.txt") or die $!;
print "linked data: ", scalar(<FH>), "\n";
close(FH);

My results (ran as "Administrator" -- may not work for "other users" -- I dunno why but my cmd.exe is always opening with elevated privileges):

src.txt exists? 1
lnk.txt exists?
Result:
lnk.txt exists? 1
linked data: hello world!

Directory listing:

10/22/2011  02:53 PM    <DIR>          .
10/22/2011  02:53 PM    <DIR>          ..
10/22/2011  02:54 PM               636 foo.pl
10/22/2011  02:53 PM    <SYMLINK>      lnk.txt [src.txt]
10/22/2011  02:53 PM                14 src.txt

I have no idea what [subtle] differences there may be, if any, between NTFS symbolic links and "UNIX" symbolic links. Also, the above won't work pre-Vista/2008 -- previous versions of NTFS do not support symbolic links (and previous versions of windows do not have the CreateSymbolicLink function).

Community
  • 1
  • 1
  • kind: NTFS Symbolic Link. I am logged in as administrator and the cmd prompt does say administrator in its title. how to run mklink in perl script? – Red Oct 22 '11 at 21:35
  • Your code works fine. But when i try to integrate inside mine then nothing happens. `code` use Win32::API; $fn = Win32::API->new( # Note "A" function, IDK how to use Unicdoe "kernel32", "BOOLEAN CreateSymbolicLinkA(LPTSTR lpSymlinkFileName, LPTSTR lpTargetFileName, DWORD flags)" ); $hr = $fn->Call($oldname, $newname, 0); `code` – Red Oct 22 '11 at 23:53
  • @Red "nothing happens" or ...? –  Oct 23 '11 at 02:53
  • I added print: `code` $hr = $fn->Call($oldname, $newname, 0) or die print "$!\n"; `code` now getting in console: 1 at C:\...\CreateSymlink.pl line 20. – Red Oct 23 '11 at 08:06
  • @Red Keep in mind that windows calls [usually] return a "result" of 0 (seems to be mapped to undef??? ... in any case it's falsy) on "success". Make sure the paths (relative/absolute) are correct and remember to pass in the "directory" flag to link a directory. It's a windows call so it uses windows pathing rules. Not sure what to say otherwise :) –  Oct 23 '11 at 20:15
1

Made a workaround:

my $oldfilename = File::Spec->catfile($oldname);
my $newfilename = File::Spec->catfile($newname);
if(-f $newfilename){ } else {
    @args = ("mklink", $newfilename, $oldfilename);
    system(@args) == 0; } 
Red
  • 81
  • 1
  • 1
  • 5