summaryrefslogtreecommitdiff
path: root/t/win32/symlink.t
blob: 084712e9caa7d6839bbbba6580a7a79b12d2e324 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!./perl

BEGIN {
    chdir 't' if -d 't';
    @INC = '../lib';
    require "./test.pl";
}

use Errno;

Win32::FsType() eq 'NTFS'
    or skip_all("need NTFS");

plan skip_all => "no symlink available in this Windows"
    if !symlink('', '') && $! == &Errno::ENOSYS;

my $tmpfile1 = tempfile();
my $tmpfile2 = tempfile();

my $ok = symlink($tmpfile1, $tmpfile2);
plan skip_all => "no access to symlink as this user"
     if !$ok && $! == &Errno::EPERM;

ok($ok, "create a dangling symbolic link");
ok(-l $tmpfile2, "-l sees it as a symlink");
ok(unlink($tmpfile2), "and remove it");

ok(mkdir($tmpfile1), "make a directory");
ok(!-l $tmpfile1, "doesn't look like a symlink");
ok(symlink($tmpfile1, $tmpfile2), "and symlink to it");
ok(-l $tmpfile2, "which does look like a symlink");
ok(!-d _, "-d on the lstat result is false");
ok(-d $tmpfile2, "normal -d sees it as a directory");
is(readlink($tmpfile2), $tmpfile1, "readlink works");
check_stat($tmpfile1, $tmpfile2, "check directory and link stat are the same");
ok(unlink($tmpfile2), "and we can unlink the symlink (rather than only rmdir)");

# test our various name based directory tests
{
    use Win32API::File qw(GetFileAttributes FILE_ATTRIBUTE_DIRECTORY
                          INVALID_FILE_ATTRIBUTES);
    # we can't use lstat() here, since the directory && symlink state
    # can't be preserved in it's result, and normal stat would
    # follow the link (which is broken for most of these)
    # GetFileAttributes() doesn't follow the link and can present the
    # directory && symlink state
    my @tests =
        (
         "x:",
         "x:\\",
         "x:/",
         "unknown\\",
         "unknown/",
         ".",
         "..",
        );
    for my $path (@tests) {
        ok(symlink($path, $tmpfile2), "symlink $path");
        my $attr = GetFileAttributes($tmpfile2);
        ok($attr != INVALID_FILE_ATTRIBUTES && ($attr & FILE_ATTRIBUTE_DIRECTORY) != 0,
           "symlink $path: treated as a directory");
        unlink($tmpfile2);
    }
}

# to check the unlink code for symlinks isn't mis-handling non-symlink
# directories
ok(!unlink($tmpfile1), "we can't unlink the original directory");

ok(rmdir($tmpfile1), "we can rmdir it");

ok(open(my $fh, ">", $tmpfile1), "make a file");
close $fh if $fh;
ok(symlink($tmpfile1, $tmpfile2), "link to it");
ok(-l $tmpfile2, "-l sees a link");
ok(!-f _, "-f on the lstat result is false");
ok(-f $tmpfile2, "normal -f sees it as a file");
is(readlink($tmpfile2), $tmpfile1, "readlink works");
check_stat($tmpfile1, $tmpfile2, "check file and link stat are the same");
ok(unlink($tmpfile2), "unlink the symlink");

# make a relative link
unlike($tmpfile1, qr([\\/]), "temp filename has no path");
ok(symlink("./$tmpfile1", $tmpfile2), "UNIX (/) relative link to the file");
ok(-f $tmpfile2, "we can see it through the link");
system "dir";
ok(unlink($tmpfile2), "unlink the symlink");

ok(unlink($tmpfile1), "and the file");

# test we don't treat directory junctions like symlinks
ok(mkdir($tmpfile1), "make a directory");

# mklink is available from Vista onwards
# this may only work in an admin shell
# MKLINK [[/D] | [/H] | [/J]] Link Target
if (system("mklink /j $tmpfile2 $tmpfile1") == 0) {
    ok(-l $tmpfile2, "junction does look like a symlink");
    like(readlink($tmpfile2), qr/\Q$tmpfile1\E$/,
         "readlink() works on a junction");
    ok(unlink($tmpfile2), "unlink magic for junctions");
}
rmdir($tmpfile1);

done_testing();

sub check_stat {
    my ($file1, $file2, $name) = @_;

    my @stat1 = stat($file1);
    my @stat2 = stat($file2);

    is("@stat1", "@stat2", $name);
}