| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Win32::Symlinks; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 2 |  |  | 2 |  | 284239 | use 5.006; | 
|  | 2 |  |  |  |  | 16 |  | 
| 4 | 2 |  |  | 2 |  | 10 | use strict; | 
|  | 2 |  |  |  |  | 3 |  | 
|  | 2 |  |  |  |  | 52 |  | 
| 5 | 2 |  |  | 2 |  | 11 | use warnings; | 
|  | 2 |  |  |  |  | 3 |  | 
|  | 2 |  |  |  |  | 1586 |  | 
| 6 |  |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  | =encoding latin1 | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | =head1 NAME | 
| 10 |  |  |  |  |  |  |  | 
| 11 |  |  |  |  |  |  | Win32::Symlinks - A maintained, working implementation of Perl symlink built in features for Windows. | 
| 12 |  |  |  |  |  |  |  | 
| 13 |  |  |  |  |  |  | =head1 VERSION | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | Version 0.06 | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | =cut | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  | BEGIN { | 
| 20 | 2 |  |  | 2 |  | 9 | our $VERSION = '0.06'; | 
| 21 | 2 | 50 |  |  |  | 327 | if ($^O eq 'MSWin32') { | 
| 22 | 0 |  |  |  |  |  | require XSLoader; | 
| 23 | 0 |  |  |  |  |  | require Win32::Shortcut; | 
| 24 | 0 |  |  |  |  |  | require File::Spec; | 
| 25 | 0 |  |  |  |  |  | require File::Basename; | 
| 26 |  |  |  |  |  |  |  | 
| 27 | 0 |  |  |  |  |  | XSLoader::load(); | 
| 28 | 0 |  |  |  |  |  | _override_link_test(); | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | *CORE::GLOBAL::readlink = sub ($) { | 
| 31 | 0 |  |  |  |  |  | my $path = shift; | 
| 32 | 0 |  |  |  |  |  | undef $Win32::Symlinks::Type; | 
| 33 | 0 |  |  |  |  |  | $path = File::Spec->catdir(File::Spec->splitdir($path)); | 
| 34 | 0 | 0 |  |  |  |  | if ($path =~ /\.lnk$/i) { | 
| 35 | 0 |  |  |  |  |  | my $sc = Win32::Shortcut->new; | 
| 36 | 0 |  |  |  |  |  | $sc->Load($path); | 
| 37 | 0 |  |  |  |  |  | my $target = $sc->{Path}; | 
| 38 | 0 |  |  |  |  |  | $sc->Close; | 
| 39 | 0 | 0 |  |  |  |  | if ($target) { | 
| 40 | 0 |  |  |  |  |  | $Win32::Symlinks::Type = 'SHORTCUT'; | 
| 41 | 0 |  |  |  |  |  | return $target; | 
| 42 |  |  |  |  |  |  | } | 
| 43 |  |  |  |  |  |  | } | 
| 44 | 0 |  | 0 |  |  |  | my $cmd = $ENV{COMSPEC} || 'cmd.exe'; | 
| 45 | 0 |  |  |  |  |  | my $directory = File::Basename::dirname($path); | 
| 46 | 0 |  |  |  |  |  | my $item = File::Basename::basename($path); | 
| 47 | 0 |  |  |  |  |  | my @r = `"$cmd" /c dir /A:l "$directory" 2>&1`; | 
| 48 | 0 |  |  |  |  |  | for my $i (@r) { | 
| 49 | 0 | 0 |  |  |  |  | if ($i =~ m[<(JUNCTION|SYMLINK|SYMLINKD)>\s+(.*?)\s+\Q[\E([^\]]+)\Q]\E]) { | 
| 50 | 0 |  |  |  |  |  | my ($type, $name, $target) = ($1, $2, $3); | 
| 51 | 0 |  |  |  |  |  | for my $i ($type, $name, $target) { | 
| 52 | 0 |  |  |  |  |  | $i =~ s[(^\s+|\s+$)][]g; | 
| 53 |  |  |  |  |  |  | } | 
| 54 | 0 | 0 |  |  |  |  | if ($name eq $item) { | 
| 55 | 0 |  |  |  |  |  | $Win32::Symlinks::Type = $type; | 
| 56 | 0 |  |  |  |  |  | return $target; | 
| 57 |  |  |  |  |  |  | } | 
| 58 |  |  |  |  |  |  | } | 
| 59 |  |  |  |  |  |  | } | 
| 60 | 0 |  |  |  |  |  | return; | 
| 61 | 0 |  |  |  |  |  | }; | 
| 62 |  |  |  |  |  |  |  | 
| 63 |  |  |  |  |  |  | *CORE::GLOBAL::symlink = sub ($$) { | 
| 64 | 0 |  |  |  |  |  | my ($old, $new) = (shift, shift); | 
| 65 | 0 | 0 |  |  |  |  | return unless defined $old; | 
| 66 | 0 | 0 |  |  |  |  | return unless defined $new; | 
| 67 | 0 |  |  |  |  |  | $old = File::Spec->catdir(File::Spec->splitdir($old)); | 
| 68 | 0 |  |  |  |  |  | $new = File::Spec->catdir(File::Spec->splitdir($new)); | 
| 69 | 0 |  |  |  |  |  | my $r; | 
| 70 | 0 | 0 |  |  |  |  | if (-d $old) { | 
| 71 | 0 |  |  |  |  |  | $r = `mklink /d "$new" "$old" 2>&1`; | 
| 72 |  |  |  |  |  |  | } else { | 
| 73 | 0 |  |  |  |  |  | $r = `mklink "$new" "$old" 2>&1`; | 
| 74 |  |  |  |  |  |  | } | 
| 75 | 0 | 0 |  |  |  |  | return 1 if $r =~ /\Q<<===>>\E/; | 
| 76 | 0 |  |  |  |  |  | return 0; | 
| 77 | 0 |  |  |  |  |  | }; | 
| 78 |  |  |  |  |  |  |  | 
| 79 |  |  |  |  |  |  | *CORE::GLOBAL::unlink = sub ($) { | 
| 80 | 0 |  |  |  |  |  | my $path = shift; | 
| 81 | 0 | 0 |  |  |  |  | return unless defined $path; | 
| 82 | 0 |  |  |  |  |  | $path = File::Spec->catdir(File::Spec->splitdir($path)); | 
| 83 | 0 |  | 0 |  |  |  | my $cmd = $ENV{COMSPEC} || 'cmd.exe'; | 
| 84 | 0 | 0 | 0 |  |  |  | if (_test_d($path) and l($path)) { | 
|  |  | 0 |  |  |  |  |  | 
| 85 | 0 |  |  |  |  |  | my $r = `"$cmd" /c rmdir "$path" 2>&1`; | 
| 86 | 0 | 0 |  |  |  |  | return $r ? 0 : 1; | 
| 87 |  |  |  |  |  |  | } elsif (l($path)) { | 
| 88 | 0 |  |  |  |  |  | my $r = `"$cmd" /c del /Q "$path" 2>&1`; | 
| 89 | 0 | 0 |  |  |  |  | return $r ? 0 : 1; | 
| 90 |  |  |  |  |  |  | } | 
| 91 | 0 |  |  |  |  |  | return CORE::unlink($path); | 
| 92 | 0 |  |  |  |  |  | }; | 
| 93 |  |  |  |  |  |  | } | 
| 94 |  |  |  |  |  |  | } | 
| 95 |  |  |  |  |  |  |  | 
| 96 |  |  |  |  |  |  | sub l ($) { | 
| 97 | 0 | 0 |  | 0 | 0 |  | return 1 if defined readlink($_[0]); | 
| 98 | 0 |  |  |  |  |  | return 0; | 
| 99 |  |  |  |  |  |  | } | 
| 100 |  |  |  |  |  |  |  | 
| 101 |  |  |  |  |  |  | # We need this because some versions of Perl (seen in 5.18) return true for -f dir_symlink | 
| 102 |  |  |  |  |  |  | # and false for -d dir_symlink. This breaks the unlink override. | 
| 103 |  |  |  |  |  |  | sub _test_d { | 
| 104 | 0 |  |  | 0 |  |  | my $path = shift; | 
| 105 | 0 |  | 0 |  |  |  | my $cmd = $ENV{COMSPEC} || 'cmd.exe'; | 
| 106 | 0 |  |  |  |  |  | my $r = `"$cmd" /c cd "$path" 2>&1`; | 
| 107 | 0 |  |  |  |  |  | $r =~ s/(^\s+|\s+$)//g; | 
| 108 | 0 | 0 |  |  |  |  | return $r ? 0 : 1; | 
| 109 |  |  |  |  |  |  | } | 
| 110 |  |  |  |  |  |  |  | 
| 111 |  |  |  |  |  |  |  | 
| 112 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 113 |  |  |  |  |  |  |  | 
| 114 |  |  |  |  |  |  | This module enables, on Windows, symlink related Perl features that don't work by default on Windows. | 
| 115 |  |  |  |  |  |  |  | 
| 116 |  |  |  |  |  |  | Specifically, it enables the functionality that you would see on *nix OSes, for C<-l $filename>, C, C and C. | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | This features have never properly been ported to Windows by the Perl development team. They were initially unimplemented due to the | 
| 119 |  |  |  |  |  |  | limitations that Windows used to have prior to NTFS (e.g. when Windows used Fat32 as main file system). | 
| 120 |  |  |  |  |  |  |  | 
| 121 |  |  |  |  |  |  | That situation has been different for at least two decades now. Yet, Perl continues to keep these functions unimplemented on Windows. | 
| 122 |  |  |  |  |  |  |  | 
| 123 |  |  |  |  |  |  | The aim of this module is to allow Perl code to use C<-l $filename>, C, C and C seamlessly between *nix | 
| 124 |  |  |  |  |  |  | and Windows. Just by using the module, it will do its best effort to make these functions work exactly the same and as they are | 
| 125 |  |  |  |  |  |  | expected to work. | 
| 126 |  |  |  |  |  |  |  | 
| 127 |  |  |  |  |  |  | The module doesn't do anything if it is run on a *nix machine, it defaults to the built in functions. But, by being present in your | 
| 128 |  |  |  |  |  |  | code, you'll ensure these functions don't break when being executed in a Windows based Perl distribution. | 
| 129 |  |  |  |  |  |  |  | 
| 130 |  |  |  |  |  |  | Perhaps a little code snippet. | 
| 131 |  |  |  |  |  |  |  | 
| 132 |  |  |  |  |  |  | use Win32::Symlinks; | 
| 133 |  |  |  |  |  |  |  | 
| 134 |  |  |  |  |  |  | # That's it. Now symlink, readlink, unlink and -l will work correctly when | 
| 135 |  |  |  |  |  |  | # executed under Windows. | 
| 136 |  |  |  |  |  |  |  | 
| 137 |  |  |  |  |  |  | # Also, you don't need to call it everywhere. Calling it once is enough. | 
| 138 |  |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  |  | 
| 141 |  |  |  |  |  |  | =head1 EXPORT | 
| 142 |  |  |  |  |  |  |  | 
| 143 |  |  |  |  |  |  | Only when running under Windows, the built in functions C, C and C, | 
| 144 |  |  |  |  |  |  | as well as the file test C<-l>, are overriden. | 
| 145 |  |  |  |  |  |  |  | 
| 146 |  |  |  |  |  |  | If at some point you really need to make sure you are calling the built in function, | 
| 147 |  |  |  |  |  |  | you should explicitly use the CORE prefix (e.g. C). | 
| 148 |  |  |  |  |  |  |  | 
| 149 |  |  |  |  |  |  | When running on any OS that is *not* Windows, it will default to the built in | 
| 150 |  |  |  |  |  |  | Perl functions. This module doesn't do anything on non Windows platforms, which | 
| 151 |  |  |  |  |  |  | makes it perfect if you are working on a non Windows machine but want to make | 
| 152 |  |  |  |  |  |  | sure your symlink related functions will not break under Windows. | 
| 153 |  |  |  |  |  |  |  | 
| 154 |  |  |  |  |  |  | =head1 AUTHOR | 
| 155 |  |  |  |  |  |  |  | 
| 156 |  |  |  |  |  |  | Francisco Zarabozo, C<<  >> | 
| 157 |  |  |  |  |  |  |  | 
| 158 |  |  |  |  |  |  | =head1 BUGS | 
| 159 |  |  |  |  |  |  |  | 
| 160 |  |  |  |  |  |  | I'm sure there are many that I haven't been able to trigger. If you find a bug, | 
| 161 |  |  |  |  |  |  | please don't hesitate to report it. I promise I will make an effort to have it | 
| 162 |  |  |  |  |  |  | resolved ASAP. | 
| 163 |  |  |  |  |  |  |  | 
| 164 |  |  |  |  |  |  | Take into account that this implementation can only work on NTFS file systems. | 
| 165 |  |  |  |  |  |  | Symlinks are not implemented in file systems like FAT32. Windows has been using | 
| 166 |  |  |  |  |  |  | NTFS since Windows 2000, but it used FAT32 for Windows 95, 98, Millenium, etc. | 
| 167 |  |  |  |  |  |  |  | 
| 168 |  |  |  |  |  |  | Also, external devices like USB sticks, SD cards, etc., are generally formatted | 
| 169 |  |  |  |  |  |  | with FAT32 or ExFAT. So, if you try to use these functions over such devices, | 
| 170 |  |  |  |  |  |  | it will fail, unless you format them with the NTFS file system first. | 
| 171 |  |  |  |  |  |  |  | 
| 172 |  |  |  |  |  |  | Please report any bugs or feature requests to C, or through | 
| 173 |  |  |  |  |  |  | the web interface at L.  I will be notified, and then you'll | 
| 174 |  |  |  |  |  |  | automatically be notified of progress on your bug as I make changes. | 
| 175 |  |  |  |  |  |  |  | 
| 176 |  |  |  |  |  |  |  | 
| 177 |  |  |  |  |  |  |  | 
| 178 |  |  |  |  |  |  |  | 
| 179 |  |  |  |  |  |  | =head1 SUPPORT | 
| 180 |  |  |  |  |  |  |  | 
| 181 |  |  |  |  |  |  | You can find documentation for this module with the perldoc command. | 
| 182 |  |  |  |  |  |  |  | 
| 183 |  |  |  |  |  |  | perldoc Win32::Symlinks | 
| 184 |  |  |  |  |  |  |  | 
| 185 |  |  |  |  |  |  |  | 
| 186 |  |  |  |  |  |  | You can also look for information at: | 
| 187 |  |  |  |  |  |  |  | 
| 188 |  |  |  |  |  |  | =over 4 | 
| 189 |  |  |  |  |  |  |  | 
| 190 |  |  |  |  |  |  | =item * RT: CPAN's request tracker (report bugs here) | 
| 191 |  |  |  |  |  |  |  | 
| 192 |  |  |  |  |  |  | L | 
| 193 |  |  |  |  |  |  |  | 
| 194 |  |  |  |  |  |  | =item * AnnoCPAN: Annotated CPAN documentation | 
| 195 |  |  |  |  |  |  |  | 
| 196 |  |  |  |  |  |  | L | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  | =item * CPAN Ratings | 
| 199 |  |  |  |  |  |  |  | 
| 200 |  |  |  |  |  |  | L | 
| 201 |  |  |  |  |  |  |  | 
| 202 |  |  |  |  |  |  | =item * Search CPAN | 
| 203 |  |  |  |  |  |  |  | 
| 204 |  |  |  |  |  |  | L | 
| 205 |  |  |  |  |  |  |  | 
| 206 |  |  |  |  |  |  | =back | 
| 207 |  |  |  |  |  |  |  | 
| 208 |  |  |  |  |  |  |  | 
| 209 |  |  |  |  |  |  | =head1 ACKNOWLEDGEMENTS | 
| 210 |  |  |  |  |  |  |  | 
| 211 |  |  |  |  |  |  | A small part of C code was taken from the Win32_Links project from Jlevens, | 
| 212 |  |  |  |  |  |  | which has a GNU v2.0 license and can be found at | 
| 213 |  |  |  |  |  |  | L. | 
| 214 |  |  |  |  |  |  |  | 
| 215 |  |  |  |  |  |  |  | 
| 216 |  |  |  |  |  |  | =head1 LICENSE AND COPYRIGHT | 
| 217 |  |  |  |  |  |  |  | 
| 218 |  |  |  |  |  |  | This software is copyright (c) 2021 by Francisco Zarabozo. | 
| 219 |  |  |  |  |  |  |  | 
| 220 |  |  |  |  |  |  | This is free software; you can redistribute it and/or modify it under | 
| 221 |  |  |  |  |  |  | the same terms as the Perl 5 programming language system itself. | 
| 222 |  |  |  |  |  |  |  | 
| 223 |  |  |  |  |  |  |  | 
| 224 |  |  |  |  |  |  | =cut | 
| 225 |  |  |  |  |  |  |  | 
| 226 |  |  |  |  |  |  | 1; # End of Win32::Symlinks |