我如何 'cd' 到显示 "Permission denied" 的符号链接目录?

How do I 'cd' to a symbolically linked directory that says "Permission denied"?

目前我的 Linux OS 上有两个用户使用两个不同的 DE。但是,我想尽可能地消除帐户之间的文件重复性。具体来说,我一直在尝试 link ~/german-capstone 文件夹从用户 segeeslicelucifer

为此,作为 lucifer,我调用了:

ln -s /home/segeeslice/german-capstone /home/lucifer/

它按预期运行,将 link 放在正确的位置。但是,尝试访问它会引发如下错误:

bash: cd: german-capstone: Permission denied


我知道这可能只是一个权限问题,但我找不到来源!我已经尽可能让双方完全访问该文件夹及其内容,但似乎没有任何效果。我错过了什么?

Here是源码目录的权限
Here 是对 符号 link

的权限

为了回应评论,这里是完整的权限列表:

------ /home/lucifer/german-capstone ------

    drwxr-xr-x  755 root     root     /
    drwxr-xr-x  755 root     root     /home
    drwxr--r--  744 lucifer  lucifer  /home/lucifer
    lrwxrwxrwx  777 lucifer  lucifer  /home/lucifer/german-capstone
                                      -> /home/segeeslice/german-capstone
    drwxr--r--  744 segeeslice segeeslice /home/segeeslice
    drwxrwxrwx  777 segeeslice segeeslice /home/segeeslice/german-capstone

更高级别仍然具有正确的读取属性...我需要在某处授予更多权限吗?

它可以是源目录或 symlink 路径上任何地方的权限,也包括在这些东西的路径中遇到的任何其他 symlinks。

这是一个脚本,可以为您显示所有这些权限。它将显示从根目录到相关路径的所有内容的权限,如果它遇到 symlink 然后它将根据 link 目标重新启动,除了它不会对它已经显示给您的任何目录重复输出(例如,/ 的权限只显示一次)。

#!/usr/bin/perl
#
use strict;


my $usage=<<EOF;
Usage: [=10=] file [file ...]

 Shows permissions on every path component from root directory to the named
 file(s), including paths traversed while following symlinks.

 Also shows permissions and contents of any .ftpaccess or .htaccess files
 encountered.

 If multiple files are specified, gives a listing for them all, but for later
 files does not show again the permissions on a path component already shown
 for earlier files.

EOF
#----------------------------------------------------------------------

use Cwd;
my $cwd = cwd;
chomp $cwd;

if ($#ARGV==-1) {
    print $usage;
    exit 1;
};

my @history=();
my @accessfiles=();

# loop over files on command line.
FILE: foreach my $fullpath (@ARGV) {

    # prepend cwd if relative path
    $fullpath="$cwd/$fullpath" unless $fullpath =~ /^\//;

    # fix pathname..
    $fullpath=stripslashes($fullpath);

    print "\n------ $fullpath ------\n\n";

    my $len=length $fullpath;
    my $pos=-1;
    my @targets=($fullpath);

    ELEMENT: while ($pos<$len) {

    # get full pathname of next element (etc)

    my $stem=($pos>=0) ? substr($fullpath,0,$pos) : ''; # parent

    $pos=index($fullpath,'/',$pos+1);
    $pos=$len if $pos==-1;
    my $path=($pos>0) ? substr($fullpath,0,$pos) : '/';

    my $remainder=substr($fullpath,$pos);

    #
    # stat the path element.
    #
    my @stat=lstat($path);
    my $okay=($#stat != -1);

    # tidy up as follows:
    #   if trailing "/foo/.." or "/." strip it and move to next element.
    #
    # We can do this because at this stage "foo" isn't a link,
    #  or we would already have followed it, but only do it if stat
    #  succeeded as parent might not be a directory (in that case, the
    #  error trap later will be executed).
    #
    my ($newpath, $subst);
    if ($okay) {
        $subst=1;   
        if ( $path =~ /\.\.$/ ) {       
        if ($stem eq '') {
            $newpath='/';
            $fullpath=$remainder;
        } else {
            ($newpath = $stem) =~ s,/([^/]*?)$,, ;
            $fullpath=$newpath.$remainder;
            if ($newpath eq '') {$newpath='/';}
        }
        }
        elsif ( $path =~ /\.$/ ) {
        if ($stem eq '') {
            $newpath='/';
            $fullpath=$remainder;
        } else {
            $newpath = $stem;
            $fullpath=$newpath.$remainder;
        }
        }
        else {
        $subst=0;
        }
        if ($subst) {
        $path=$newpath;
        $pos=length $path;
        $len=length $fullpath;
        next ELEMENT;
        }
    }

    # have we been here before?
    my $beenthere=grep {$_ eq $path} @history;
    push @history,$path;

    # is it a symlink?
    if (-l _) {

        # yes. see where it points
        my $pointsto=readlink $path;
        my $newfile;
        if ($pointsto =~ /^\//) {
        # link is absolute pathname
        $newfile=$pointsto.substr($fullpath,$pos);
        $pos=-1;
        } else {
        # link is relative pathname
        $newfile=$stem.'/'.$pointsto.substr($fullpath,$pos);
        $pos=length $stem;
        }
        if (!$beenthere) {
        show_stat(\@stat,$path,$pointsto);
        }
        # strip extra "/"
        $newfile=stripslashes($newfile);

        # check for recursive links
        my $beenthere2=grep {$_ eq $newfile} @targets;
        push @targets,$newfile;
        if ($beenthere2) {
        print " === SYMLINK LOOP DETECTED ===\n";
        next FILE;
        }
        # follow the link (stripping extra "/"s)
        $fullpath=$newfile;
        $len=length $fullpath;
    } else {
        # no, not a symlink
        # print info, with usernames/groupnames where possible
        # unless we've been here before...
        if (!$beenthere) {
        if (! $okay) {
            print "\n*** ERROR : $path : $! ***\n";
            next FILE;
        }
        show_stat(\@stat,$path);

        #
        # check for any {.htaccess,.ftpaccess} files
        # 
        for my $name (qw(.htaccess .ftpaccess)) {
            my $file = "$path/$name";
            if (-e $file) {
            push @accessfiles,$file;
            }
        }
        }       
    }
    } # end ELEMENT loop
} # end FILE loop
continue {    
    print "\n";
}

if ($#accessfiles > -1) {
    print "Access control files of possible relevance:\n\n";
    for my $file (@accessfiles) {
    my @stat = stat($file);
    show_stat(\@stat,$file);
    if (open my $access,$file) {
        print "\n    ---- Contents of $file ----\n";
        while (defined (my $line=<$access>)){
        chomp $line;
        print "    $line\n";
        }
        close $access;
        print "    ------- End of $file -------\n";
    } else {
        print "    Could not open $file: $!\n";
    }
    }
    print "\n";
}

exit 0;

#-------------------------------------------------------------
sub stripslashes 
{    
    my $line = shift;

    # strip trailing or repeated '/'s
    $line =~ s,/*$,,;
    $line =~ s,//+,/,g;
    $line =~ s,^$,/,;

    return $line;
}

sub show_stat
{
    use Fcntl ':mode';

    my ($stat,$path,$linktarget) = @_;

    my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
    $atime,$mtime,$ctime,$blksize,$blocks) = @$stat;


    my @pwent=getpwuid($uid);
    my $username=($#pwent == -1) ? "($uid)" : $pwent[0];
    my @grent=getgrgid($gid);
    my $grpname=($#grent == -1) ? "($gid)" : $grent[0];
    printf ("%s %4o %-8s %-8s %s\n",
        symbolic_mode($mode),
        $mode&07777,$username,$grpname,$path);

    if (S_ISLNK($mode) and defined($linktarget)) {
    print "                                  -> $linktarget\n";
    }

}

sub symbolic_mode
{
    # takes a numerical mode returned by stat,
    # returns a symbolic string as per "ls -l"
    # e.g. for 0640 returns "-rw-r-----"

    my $mode = shift;

    use Fcntl ':mode';

    my $typechar = 
    S_ISREG($mode) ? '-' :
    S_ISDIR($mode) ? 'd' :
    S_ISLNK($mode) ? 'l' :
    S_ISBLK($mode) ? 'b' :
    S_ISCHR($mode) ? 'c' :
    S_ISFIFO($mode) ? 'p' :
    S_ISSOCK($mode) ? 's' : 
    '?';

    my $modestr = $typechar . 'rwxrwxrwx';
    for (my $bit=0; $bit <= 8 ; $bit++) {
    if (($mode & (1<<$bit)) == 0) {
        substchar($modestr,9-$bit,"-");
    }
    }
    if ($mode & 01000) {
    substchar($modestr,9,
          ($mode & 0001) ? "t" : "T");
    }
    if ($mode & 02000) {
    substchar($modestr,6,
          ($mode & 0010) ? "s" : "S");
    }
    if ($mode & 04000) {
    substchar($modestr,3,
          ($mode & 0100) ? "s" : "S");
    }    
    return $modestr;
}

sub substchar
{
    # substitutes a character in a string
    my ($sref, $pos, $newchar) = @_;
    my $string = $$sref;
    my $newstring = substr($string,0,$pos) . $newchar . substr($string,$pos+1);
    $$sref=$newstring;
}

示例输出:

$ mkdir -p /tmp/mydir/stuff
$ ln -s stuff /tmp/mydir/stuff2
$ cal > /tmp/mydir/stuff2/myfile
$ mkdir /tmp/mydir2
$ ls /tmp/mydir2/stuff2/myfile
ls: cannot access '/tmp/mydir2/stuff2/myfile': No such file or directory
$ ls /tmp/mydir/stuff2/
myfile
$ ln -s /tmp/mydir/stuff2/myfile  /tmp/mydir/stuff2/thingy
$ chmod 700 /tmp/mydir
$ permsto  /tmp/mydir/stuff2/thingy

------ /tmp/mydir/stuff2/thingy ------

drwxr-xr-x  755 root     root     /
drwxrwxrwt 1777 root     root     /tmp
drwx------  700 myuser   mygroup  /tmp/mydir
lrwxrwxrwx  777 myuser   mygroup  /tmp/mydir/stuff2
                                  -> stuff
drwxr-xr-x  755 myuser   mygroup  /tmp/mydir/stuff
lrwxrwxrwx  777 myuser   mygroup  /tmp/mydir/stuff/thingy
                                  -> /tmp/mydir/stuff2/myfile
-rw-r--r--  644 myuser   mygroup  /tmp/mydir/stuff/myfile

因此,您可以查看输出并一眼看出权限问题潜伏在何处。


现在问题已更新为包含相关目录的脚本输出,很明显问题出在以下目录的权限上:

    drwxr--r--  744 lucifer  lucifer  /home/lucifer
    drwxr--r--  744 segeeslice segeeslice /home/segeeslice

如果进程对目录具有读取权限但没有执行权限,它将能够列出该目录但不能以其他方式访问其中包含的任何路径。对于八进制模式 744 的目录,对于任何不是 运行 作为所有者(或根)的进程都是这种情况,这将依赖于 "group" 或 "other" 权限。如果改为八进制模式 755(即为 "group" 和 "other" 添加执行权限),那么这些将具有必要的访问权限。