Linux下ls命令显示符号链接权限为777的探索

——深入ls、链接、文件系统与权限

by Ascii0x03,http://www.cnblogs.com/ascii0x03/p/6442420.html

一、摘要

ls是Linux和Unix下最常使用的命令之一,主要用来列举目录下的文件信息,-l参数允许查看当前目录下所有可见文件的详细属性,包括文件属性、所有者、文件大小等信息。但是,当其显示符号链接的属性时,无论其指向文件属性如何,都会显示777,即任何人可读可写可执行。本文从ls命令源码出发,由浅入深地分析该现象的原因,简略探究了Linux 4.10下的符号链接链接、文件系统与权限的源码实现。

关键词:Linux ls 符号链接 文件系统 权限 源码分析

二、引言

2.1 Linux文件权限

在Linux中每个文件有所有者、所在组、其它组的概念[11]。所有者一般为文件的创建者,谁创建了该文件,就天然的成为该文件的所有者;当某个用户创建了一个文件后,这个文件的所在组就是该用户所在的组;除开文件的所有者和所在组的用户外,系统的其它用户都是文件的其它组。ls 命令将每个由 Directory 参数指定的目录或者每个由 File 参数指定的名称写到标准输出,以及所要求的和标志一起的其它信息。ls -l中显示的内容常如下所示:

-rwxrw-r‐-1 root root 1213 Feb 2 09:39 abc

前10个字符说明了文件类型与权限。第一个字符代表文件(-)、目录(d),链接(l),其余字符每3个一组(rwx),读(r)、写(w)、执行(x)。第一组rwx:文件所有者的权限是读、写和执行;第二组rw-:与文件所有者同一组的用户的权限是读、写但不能执行;第三组r--:不与文件所有者同组的其他用户的权限是读不能写和执行。权限也可用数字表示为:r=4,w=2,x=1  因此rwx=4+2+1=7。

2.2 符号链接

如前所述,若第一个字符显示为l,说明该文件是符号链接。符号链接(软链接)是一类特殊的文件, 其包含有一条以绝对路径或者相对路径的形式指向其它文件或者目录的引用[12]。符号链接的操作是透明的:对符号链接文件进行读写的程序会表现得直接对目标文件进行操作。某些需要特别处理符号链接的程序(如备份程序)可能会识别并直接对其进行操作。一个符号链接文件仅包含有一个文本字符串,其被操作系统解释为一条指向另一个文件或者目录的路径。它是一个独立文件,其存在并不依赖于目标文件。如果删除一个符号链接,它指向的目标文件不受影响。如果目标文件被移动、重命名或者删除,任何指向它的符号链接仍然存在,但是它们将会指向一个不复存在的文件。这种情况被有时被称为被遗弃。

但是,我们常常发现,创建符号链接其权限就会显示为lrwxrwxrwx,为什么?是ls命令对符号链接进行了处理,还是文件本身权限即如此?这样会不会带来一些安全隐患?怀着这些问题,本文由浅入深,从ls命令出发,探索了其背后的系统调用至vfs文件系统实现细节,力求解释这些问题。但作者水平有限,尚有很多细节不清楚,不对之处恳请批评指正。

三、ls命令分析

ls命令是Linux shell下最常用的命令之一,主要用来列举目录下的文件信息。经过搜索引擎查找[1],要查看该命令的源代码需要下载对应软件包coreutils的源代码。其实只要知道了软件包的名字,既可以按照文献[1]的方法使用apt-get source下载,也可以从软件包coreutils的官网[2]下载。下载完毕后,使用source insight软件建立工程,即可方便地开始源码阅读。本文使用截止2017年2月18日最新版本的coreutils-8.26。

打开/src/ls.c,从main函数开始,忽略开始的初始化、颜色设定等内容,1451行调用的decode_switches对参数进行了一些处理,由于研究的是ls程序,所以第一个switch(ls_mode)关注LS_LS。接下来,1703行设置dereference = DEREF_UNDEFINED。关键部分代码为1752行的一个switch(true),它根据传入的参数,设置相应的标志,如-l设置format = long_format,H、I、L设置了dereference的一些模式,由于作者平时经常使用的是ls –l,所以仅关注-l选项下的情况,dereference仍然为DEREF_UNDEFINED。同时,该函数2125行对format == long_format的情况,做了一些格式输出上的工作。

发现1467行对dereference变量的判断影响了如何处理符号链接。若仅使用-l选项,dereference赋值为DEREF_NEVER,即仅仅拷贝复制符号链接自身。

若设置了递归枚举,设置一个哈希表来检测是否出现了目录环。接下来开辟cwd_file变量空间,其是指向fileinfo结构体的向量指针,保存了要描述的文件。关于fileinfo结构体源码中已经给了很好的注释,其中struct stat类型的变量stat具体描述了文件的信息,往往由stat()或lstat()函数返回。struct stat类型的定义可以在Linux源码include\uapi\asm-generic中找到,可以看出新版本64位中与常见文档中相比增加了许多pad填充,并将类型的一些宏定义取消了,直接采用了unsigned long。

下面主要调用了gobble_file函数,添加文件到当前的文件表中,即放到cwd_file中未使用的第一个位置上。3131行的switch语句根据dereference值,调用stat()或lstat()函数,由上面分析可知,ls –l是DEREF_NEVER,故调用lstat()函数,并将结果存入fileinfo.stat中(代码中是变量f);接下来,代码再根据结构体fileinfo.stat,对fileinfo其他部分赋值,在long_format情况下,fileinfo. scontext是SELinux有关函数lgetfilecon()获得的安全上下文(context)。同时也可以看出,默认-l选项是不对符号链接进行追踪的,所以调用的函数也都是对应版本。3235行判断当文件为符号链接且模式为long_format时会成立,由此赋值了fileinfo的linkok、linkmode等值。接下来函数主要根据要输出哪些信息,将fileinfo中的值保存了下来。

最后,在main函数1538行,根据文件的数目,调用print_current_files ()来输出文件内容,print_long_format()中第3967行通过filemodestring()函数将文件的读写执行权限填入了modebuf,该函数在filemode.c中定义。在填入时,ls程序未对符号链接做特殊处理,由此可见,符号链接权限问题的关键在于lstat()函数的实现是如何填入stat结构体中st_mode的。

四、lstat系统调用

4.0 系统调用与文件系统基础

4.0.1 从C语言到系统调用

stat是用来获得文件信息的系统调用[3],要寻找该系统调用的源代码,首先要理解系统调用的流程。这里参考了文献[4][5],根据自己理解,C语言调用stat函数时,调用的是C库对该函数的实现,接着执行库中函数的具体实现的代码,其中非常关键的一句代码就是 int 0x80,中断使得进程从用户态切换到内核态,中断处理程序然后开始执行内核中对应80号中断的系统调用处理程序的代码 system_call;system_call 系统调用处理程序就根据传入的系统调用号从系统调用服务程序数组中寻找对应系统调用服务程序,最后执行完成后按照调用顺序的相反顺序一步步返回结果。

根据一般规律,系统调用定义的名字就是在函数前面加一个sys_,由此在include\linux\syscalls.h中发现了一系列stat的声明,而fs\Stat.c中是对应的定义。(内核中使用SYSCALL_DEFINE2的宏定义来定义系统调用,展开就是声明的形式。)这里会发现,4.10内核中同时存在newstat与stat,无论新旧,实现都是使用了vfs_stat函数,传入参数为kstat,差别在于宏倒数第二个参数的类型。(但是这个参数具体有什么作用?实现中好像并没有用到这个参数。)

接下来需要看vfs_lstat的实现,他与vfs_stat都是调用了vfs_fstatat,区别在于vfs_lstat给最后一个参数赋值为了AT_SYMLINK_NOFOLLOW,说明不要追踪符号链接。

vfs_fstatat首先对flag参数进行检查,必须有(并非等于)规定的几种标识之一;然后调用user_path_at,根据返回结果再调用vfs_getattr和path_put;之后看似是一个错误处理,会返回到retry,没有错误则函数退出返回。对关键数据stat赋值的部分应该就在vfs_getattr函数了。

4.0.2 文件系统基础

为了进行后面的分析,这里需要Linux内核文件系统有一定的了解[6][7]。Linux 有着极其丰富的文件系统,大体上可分如下几类:

网络文件系统,如 nfs、cifs 等;

磁盘文件系统,如 ext4、ext3 等;

特殊文件系统,如 proc、sysfs、ramfs、tmpfs 等。

实现以上这些文件系统并在 Linux 下共存的基础就是 Linux VFS(Virtual File System 又称 Virtual Filesystem Switch),即虚拟文件系统。VFS 作为一个通用的文件系统,抽象了文件系统的四个基本概念:文件、目录项 (dentry)、索引节点 (inode) 及挂载点,其在内核中为用户空间层的文件系统提供了相关的接口。VFS 实现了 open()、read() 、stat()等系统调并使得 cp 等用户空间程序可跨文件系统。VFS 真正实现了上述内容中:在 Linux 中除进程之外一切皆是文件。

Linux VFS 存在四个基本对象:超级块对象 (superblock object)、索引节点对象 (inode object)、目录项对象 (dentry object) 及文件对象 (file object)。超级块对象代表一个已安装的文件系统;索引节点对象代表一个文件;目录项对象代表一个目录项,如设备文件 event5 在路径 /dev/input/event5 中,其存在四个目录项对象:/ 、dev/ 、input/ 及 event5。文件对象代表由进程打开的文件。这四个对象与进程及磁盘文件间的关系如图,其中 d_inode 即为硬链接。为文件路径的快速解析,Linux VFS 设计了目录项缓存(Directory Entry Cache,即 dcache)。下面列出几个关键数据结构,并在关注的部分给出注释。

 struct nameidata { //文件查找临时结构体

 struct path path;//包含vfsmount挂载点和dentry目录项

 struct qstr last;

 struct path root;

 struct inode       *inode; /* path.dentry.d_inode */

 unsigned int      flags;

 unsigned   seq, m_seq;

 int             last_type; /*路径中的最后一个component的类型*/

 unsigned depth; //符号链接嵌套的级别

 int             total_link_count;

 struct saved {

           struct path link;

           struct delayed_call done;

           const char *name;

           unsigned seq;

 } *stack, internal[EMBEDDED_LEVELS];

 struct filename   *name; //保存要查找的文件名

 struct nameidata *saved;

 struct inode       *link_inode;

 unsigned   root_seq;

 int             dfd;

 };

 struct dentry {//目录项对象

 /* RCU lookup touched fields */

 unsigned int d_flags;           /* protected by d_lock */

 seqcount_t d_seq;               /* per dentry seqlock */

 struct hlist_bl_node d_hash;        /* lookup hash list */

 struct dentry *d_parent;      /* parent directory */

 struct qstr d_name;

 struct inode *d_inode;                 /* Where the name belongs to - NULL is

                                     * negative */

 unsigned char d_iname[DNAME_INLINE_LEN];     /* small names */

 /* Ref lookup also touches following */

 struct lockref d_lockref;       /* per-dentry lock and refcount */

 const struct dentry_operations *d_op;//目录项方法

 struct super_block *d_sb;    /* The root of the dentry tree */

 unsigned long d_time;                /* used by d_revalidate */

 void *d_fsdata;                   /* fs-specific data */

 union {

           struct list_head d_lru;          /* LRU list */

           wait_queue_head_t *d_wait;        /* in-lookup ones only */

 };

 struct list_head d_child;      /* child of parent list */

 struct list_head d_subdirs;   /* our children */

 /*

  * d_alias and d_rcu can share memory

  */

 union {

           struct hlist_node d_alias;     /* inode alias list */

           struct hlist_bl_node d_in_lookup_hash; /* only for in-lookup ones */

         struct rcu_head d_rcu;

 } d_u;

 };

 struct inode { //索引节点

 umode_t                    i_mode; //文件类型与访问权限,是本文所关注的重点部分

 unsigned short           i_opflags;//2.6内核中没有的字段,哪里去找这个字段注释?

 kuid_t                        i_uid;

 kgid_t                        i_gid;

 unsigned int              i_flags;

 #ifdef CONFIG_FS_POSIX_ACL

 struct posix_acl  *i_acl;

 struct posix_acl  *i_default_acl;

 #endif

 const struct inode_operations     *i_op; //索引节点的操作

 struct super_block      *i_sb;

 struct address_space  *i_mapping;

 #ifdef CONFIG_SECURITY

 void                   *i_security;

 #endif

 /* Stat data, not accessed from path walking */

 unsigned long            i_ino;

 /*

  * Filesystems may only read i_nlink directly.  They shall use the

  * following functions for modification:

  *

  *    (set|clear|inc|drop)_nlink

  *    inode_(inc|dec)_link_count

  */

 union {

           const unsigned int i_nlink;

           unsigned int __i_nlink;

 };

 dev_t                 i_rdev;

 loff_t                  i_size;

 struct timespec          i_atime;

 struct timespec          i_mtime;

 struct timespec          i_ctime;

 spinlock_t          i_lock;       /* i_blocks, i_bytes, maybe i_size */

 unsigned short          i_bytes;

 unsigned int              i_blkbits;

 blkcnt_t             i_blocks;

 #ifdef __NEED_I_SIZE_ORDERED

 seqcount_t                 i_size_seqcount;

 #endif

 /* Misc */

 unsigned long            i_state;

 struct rw_semaphore  i_rwsem;

 unsigned long            dirtied_when;     /* jiffies of first dirtying */

 unsigned long            dirtied_time_when;

 struct hlist_node        i_hash;

 struct list_head  i_io_list;     /* backing dev IO list */

 #ifdef CONFIG_CGROUP_WRITEBACK

 struct bdi_writeback   *i_wb;                /* the associated cgroup wb */

 /* foreign inode detection, see wbc_detach_inode() */

 int                     i_wb_frn_winner;

 u16                   i_wb_frn_avg_time;

 u16                   i_wb_frn_history;

 #endif

 struct list_head  i_lru;          /* inode LRU list */

 struct list_head  i_sb_list;

 struct list_head  i_wb_list;   /* backing dev writeback list */

 union {

           struct hlist_head i_dentry;

           struct rcu_head          i_rcu;

 };

 u64                   i_version;

 atomic_t            i_count;

 atomic_t            i_dio_count;

 atomic_t            i_writecount;

 #ifdef CONFIG_IMA

 atomic_t            i_readcount; /* struct files open RO */

 #endif

 const struct file_operations *i_fop;       /* former ->i_op->default_file_ops */

 struct file_lock_context       *i_flctx;

 struct address_space  i_data;

 struct list_head  i_devices;

 union {

           struct pipe_inode_info        *i_pipe;

           struct block_device     *i_bdev;

           struct cdev                 *i_cdev;

           char                   *i_link;

           unsigned           i_dir_seq;

 };

 __u32                        i_generation;

 #ifdef CONFIG_FSNOTIFY

 __u32                        i_fsnotify_mask; /* all events this inode cares about */

 struct hlist_head i_fsnotify_marks;

 #endif

 #if IS_ENABLED(CONFIG_FS_ENCRYPTION)

 struct fscrypt_info       *i_crypt_info;

 #endif

 void                   *i_private; /* fs or device private pointer */

 };

 struct file { //文件对象,描述进程怎样与一个打开的文件进行交互

 union {

           struct llist_node fu_llist;

           struct rcu_head         fu_rcuhead;

 } f_u;

 struct path         f_path;

 struct inode               *f_inode;   /* cached value */

 const struct file_operations *f_op;

 /*

  * Protects f_ep_links, f_flags.

  * Must not be taken from IRQ context.

  */

 spinlock_t          f_lock;

 atomic_long_t            f_count;

 unsigned int              f_flags;

 fmode_t                     f_mode;

 struct mutex              f_pos_lock;

 loff_t                  f_pos; //文件偏移

 struct fown_struct      f_owner;

 const struct cred        *f_cred; //进程相关安全上下文信息,如uid、权限等

 struct file_ra_state      f_ra;

 u64                   f_version;

 #ifdef CONFIG_SECURITY

 void                   *f_security;

 #endif

 /* needed for tty driver, and maybe others */

 void                   *private_data;

 #ifdef CONFIG_EPOLL

 /* Used by fs/eventpoll.c to link all the hooks to this file */

 struct list_head  f_ep_links;

 struct list_head  f_tfile_llink;

 #endif /* #ifdef CONFIG_EPOLL */

 struct address_space  *f_mapping;

 } __attribute__((aligned()));  /* lest something weird decides that 2 is OK */

4.1 user_path_at函数

有了基础补充后,继续4.0.1节分析系统调用。user_path_at调用并返回user_path_at_empty的返回值,user_path_at_empty 返回filename_lookup的返回值,传参数时使用了getname_flags函数(实在看不懂这个函数,但是2.6内核要简洁的多,直接返回char*,4.10多设计了一个filename *)将用户传入的文件名const char __user *name转化为了struct filename *类型,其中__user宏定义为空的,可能是为了标记该参数由用户传入吧。(为什么要一层一层来调用,不怕效率低吗?)

filename_lookup主要调用了path_lookupat函数,在之前先调用了set_nameidata,对nameidata进行了一些初始化赋值,将要查询的文件名放入了结构体nameidata中,并且将从current取出的nameidata保存下来,组成了一个链表。(这里发现current是宏定义,开始的时候source insight自动追踪变成了循环宏定义,应该是追踪错了头文件,因为有许多个current.h。后来查阅资料看是获得调用系统调用进程的数据结构信息。)

4.1.1 path_lookupat函数

接着进入path_lookupat函数,此时参数为0 | LOOKUP_RCU,即LOOKUP_ RCU。RCU(Read-Copy Update)是内核数据同步的一种锁机制。

1.函数首先调用path_init()函数,path_init()函数主要是初始化查询,将nd实例的mnt和dentry成员设置为根目录或者工作目录的对应项

a,绝对路径(以/开始),获得根目录的dentry。它存储在task_struct中fs指向的fs_struct结构中。task_struct->fs_struct.root 。

b,相对路径,直接从当前进程task_struct结构中的获得指针fs,它指向的一个fs_struct,fs_struct中有一个指向“当前工作目录”的dentry。

2,path_lookupat()然后循环调用link_path_walk()函数。link_path_walk()函数将传入的路径名转化为dentry目录项:

首先跳过路径名的’/’,如果只有'/'则直接返回0;得到正确的路径名后,进入一个循环,每次都调用may_lookup()函数对inode节点做权限检查,如果权限不够也直接返回fail,在Unix中,只有目录是可执行的,它才可以被遍历;接下来计算的哈希与目录项高速缓存有关;该循环不断更新last_type和last,如果是最后一部分的返回,若不是则调用walk_component()函数。walk_component先处理LAST_DOTS,若发现LAST_NORM类型,即普通文件,则调用lookup_fast()在缓存中查找,若没有好的结果则调用lookup_slow(),获得i_mutex,重新检查缓存并向文件系统查找,他们都会调用follow_managed来处理挂载点;若有必要,期间walk_component会更新nameidata结构体的path。

link_path_walk会随着文件路径每部分深入,并追踪其间遇到的每个符号链接,直到其到达最后一部分,返回给nameidata.last。这个link_path_walk()函数本身非常复杂,也比较难懂,细节内容可参考文献[8][9][13],[13]对源码的注释非常清楚。link_path_walk函数主要是根据给定的路径,找到最后一个路径分量的目录项对象和安装点。

3. 在循环中还会调用trailing_symlink()函数来继续追踪最后部分的符号链接。trailing_symlink()会先调用may_follow_link(),这个函数检查符号链接的一些不安全权限情况。接着调用get_link(),先更新相关的访问时间等信息,然后调用inode中的get_link()方法完成符号链接解析;注意,原来的follow_link被get_link代替,而put_link,通过在get_link中设置set_delayed_call代替。

4. 最后对nd进行一些恢复收尾工作。

4.1.2 收尾

audit_inode调用了__audit_inode,定义在kernel/auditsc.c中,保存查找的inode和device,从名字猜测是审计用,这里先不关心。然后恢复current->nameidata,并释放name内存,与开头对应。这样filename_lookup结束,返回retval变量至user_path_at函数,即返回path_lookupat的结果。由此可见user_path_at就是检查是否存在这个文件,以及相关权限是否允许。

4.2 vfs_getattr函数

4.2.1 security_inode_getattr

security_inode_getattr定义在security/security.c,首先检查dentry的inode的i_flags是否为S_PRIVATE,即inode文件系统的安装标识。若不是,则调用call_int_hook(inode_getattr, 0, path),这个宏定义就看不懂了,涉及到security_hook_heads的很多东西,这里先忽略。

4.2.2 vfs_getattr_nosec

注释说明是在没有安全检查的情况下获得属性,即没有调用security_inode_getattr,实现很简单,从dentry目录项中获得inode,然后调用inode索引节点对象的getattr方法,再用generic_fillattr填充到返回的stat中,stat->mode=inode->i_mode。Inode方法中保存的函数指针,就指向了每个具体文件操作系统的的函数。

五、结论

通过分析,ls –l获得的符号链接就是vfs下层文件系统getattr返回的信息,那么下层文件系统getattr如何实现?这取决于不同的具体文件系统,《深入理解Linux内核》中提到ext2使用generic_getattr,但是在4.10源码中已经难以寻找到了,再深入的内容需要额外的耐心。那么如何查看inode的信息呢?Debugfs是一种特殊的文件系统,提供了把内核信息传递到用户空间的方式,与/proc类似。在debugfs中执行mi命令+要查看的文件,可以得到完整的inode信息。如下图所示,符号链接inode中的mode值确实为0120777。这会不会有什么安全隐患,为什么要这样设计?

文献[10]也有这样的描述“Symbolic links (sometimes called soft links) do not link to inodes, but create a name to name mapping. Symbolic links are created with ln -s. As you can see below, the symbolic link gets an inode of its own. Permissions on a symbolic link have no meaning, since the permissions of the target apply. Hard links are limited to their own partition (because they point to an inode), symbolic links can link anywhere (other file systems, even networked).”大意为“符号链接不链接到inode结点,而是创建名字到名字的映射。符号链接拥有自己的inode结点,其权限是没有意义的,因为应用的是链接目标文件的权限。符号链接可以链接至任何地方,如跨文件系统,甚至网络”。在path_lookupat查找路径时,已经对目录进行了权限检查,一般情况,如open系统调用,在路径寻找的时候都会使用do_follow_link函数来自动解析掉符号链接,(之前分析的path_lookupat循环中trailing_symlink也是用来追踪最后一个分量dentry为符号链接的情况,但应该由于设置了falg没有继续追踪符号链接。奇怪的是根据flag没有发现可以不调用trailing_symlink。)所以符号链接本身的权限没有意义;对文件系统详细分析的优秀文档可见[14]。

但是,在分析源码过程中见到的may_follow_link()函数就考虑了一些可能的安全隐患。此外,假想一种场景,若系统或A app想使用B app的凭证文件key,恶意的B app可以将key这个文件符号链接至其他任何地方,如C app的凭证,会不会引发这样的一些问题?仍待探索。

六、反思

1. 想看懂Linux内核源码,甚至只是filesystem这一部分的源码,都需要对整个Linux内核源码有一定的认识。如遇到的系统调用,进程相关current,安全相关security.c的内容。

2. 看源码前一定尽力找文档!看源码前一定尽力找文档!看源码前一定尽力找文档!开始作者仅根据《深入理解Linux内核》这本书在探索path_lookupat,发现4.10与书上的2.6内核有不少的差别,所以一定要参考源码目录下的document目录下的文档(没有国人翻译成中文吗?),里面讲了源码的实现细节,并且和现役版本对应。另外也可以搜索其他人分析源码的博客,但往往比较旧。

3. 不要完全相信source insight的自动查找,遇见问题要相信自己的眼睛,再结合网上的Linux源码索引,优先用google不要用百度。

4. 使用source insight建立工程太大的话同步符号要好久,所以不妨先只加入自己关注的部分,比如只加入fs文件夹下的源码,这样效率比较高。

5. 对内核中使用的数据结构和设计思路越清楚,越有利于看懂源码。

6. 有了一定基础后,看懂源码不是梦,但非常非常需要耐心与时间,尤其是细节部分。由于自己最近耐心不佳,基础也欠缺,所以没有在意太多细节,仅力求了解全貌。

参考文献

[1] Linux命令源码的查看. http://blog.chinaunix.net/uid-27177626-id-3389673.html

[2] Coreutils - GNU core utilities. http://www.gnu.org/software/coreutils/coreutils.html

[3] stat (C System Call). http://codewiki.wikidot.com/c:system-calls:stat

[4] Linux 系统调用内核源码分析. http://woshijpf.github.io/2016/05/10/Linux-%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8%E5%86%85%E6%A0%B8%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/

[5] Linux系统调用(syscall)原理. http://gityuan.com/2016/05/21/syscall/

[6] 理解 Linux 的硬链接与软链接. https://www.ibm.com/developerworks/cn/linux/l-cn-hardandsymb-links/#major4

[7] Linux 的虚拟文件系统--各结构之间的联系. http://scudong.blogbus.com/logs/11599350.html

[8] link_path_walk()路径名查找.http://blog.chinaunix.net/uid-12567959-id-160996.html

[9] 《深入理解Linux内核》P495-P504

[10] Chapter 9. file links. http://linux-training.be/security/ch09.html#idp65315008

[11] Linux下用户组、文件权限详解. http://www.cnblogs.com/123-/p/4189072.html

[12] 符号链接. https://zh.wikipedia.org/zh/%E7%AC%A6%E5%8F%B7%E9%93%BE%E6%8E%A5

[13] Linux文件系统(七)---系统调用之open操作(三) 之 open_namei函数. http://blog.csdn.net/shanshanpt/article/details/39927553

[14] linux内核follow_link分析. http://blog.csdn.net/sanwenyublog/article/details/50856837

Linux下ls命令显示符号链接权限为777的探索的更多相关文章

  1. Linux下 ls 命令的高级用法8例

    Linux下 ls 命令的高级用法8例 在Linux下,ls这个命令大家肯定太熟悉了,良许相信只要是Linux工程师,每天都会离不开这个命令,而且一天会使用个几百次.但是,除了 ls -l 以外,你还 ...

  2. linux下history命令显示历史指令记录的使用方法

    Linux系统当你在shell(控制台)中输入并执行命令时,shell会自动把你的命令记录到历史列表中,一般保存在用户目录下的.bash_history文件中.默认保存1000条,你也可以更改这个值 ...

  3. Linux下ls命令使用详解(转)

    说明:我们在linux下使用ll时,其实就是ls -l.ls才是最终的命令程序. ls命令是linux下最常用的命令之一,ls跟dos下的dir命令是一样的都是用来列出目录下的文件,List即列表的意 ...

  4. Changing the Color of Linux ls Command 改变Linux的ls命令显示的颜色

    Linux command ls basically use the file /etc/DIR_COLORS or /etc/DIR_COLORS.xterm to define the color ...

  5. linux下history命令显示执行时间

    想在输入history命令之后,显示自己历史的命令执行的时间,需要在用户目录下~/.bashrc的文件末尾追加添加如下几行 之前一直想看一下自己历史命令执行的时间,找了很多教程都没有卵用,最终参考了如 ...

  6. linux 下ln命令--笔记

    linux 下ln命令 ln命令用来为文件创建连接,连接类型分为硬连接和符号连接两种,默认的连接类型是硬连接.如果要创建符号连接必须使用"-s"选项.注意:符号链接文件不是一个独立 ...

  7. linux下svn命令使用大全

    最近经常使用svn进行代码管理,这些命令老是记不住,得经常上网查,终于找了一个linux下svn命令使用大全:1.将文件checkout到本地目录 svn checkout path(path是服务器 ...

  8. Linux下高频命令分类辑录(基本使用篇)

    本文目的:总结linux下常用命令的基本使用方法 文件权限: 文档权限设置命令:chmod 数字模式: 文档权限由-rwxrwxrwx十个字符组成,其中第一个代表文档类型,后面九个字符按照顺序分为三组 ...

  9. Linux下svn命令详解

    本文主要是说明linux下svn命令的使用方法,同时记录自己在使用中遇到的一些疑惑. 1.Linux命令行下将文件checkout到本地目录 svn checkout url(url是服务器上的目录) ...

随机推荐

  1. 自己实现一个IOC(控制翻转,DI依赖注入)容器

    1.新建一个控制台应用程序 TestIOC 2.新增一个 IocFactory类 using System; using System.Collections.Generic; using Syste ...

  2. UVa 10925 - Krakovia

    题目大意:关于大数的加法和除法的,用Java的BigInteger可以方便地解决. import java.io.*; import java.util.*; import java.math.*; ...

  3. java web开发中的奇葩事web.xml中context-param中的注释

    同事提交了代码.结果除同事之外,其他人全部编译报错.报错说web.xml中配置的一个bean 没有定义.按照报错提示,各种找,无果. 由于代码全部都是提交到svn主干,之前也没有做过备份,只能一步一步 ...

  4. redis php sort 函数

    很多人把redis当成一种数据库,其实是利用redis来构造数据库的模型,有那种数据库的味道.但是在怎么构建还是key和value的关系.根真正的关系型数据库还是不一样的.效率高,不方便:方便的,效率 ...

  5. linux 下 tomcat 之 配置静态资源路径

    1.找到配置文件 找到tomcat\conf\server.xml 2.找到Host 3. 添加 Context <Host name="localhost" appBase ...

  6. JS 工具 构建工具

    1.gruntjs http://www.gruntjs.net/ 2.bootstrap http://www.bootcss.com/ 3.

  7. Java div 使用说明

    1. 置于底部 position:absolute; bottom:0;

  8. Raphael的set使用

    Raphael的set使用 $(function() { initRaphael(); }); function initRaphael(e) { var paper = Raphael(0, 0, ...

  9. jackson - 生成jason工具-简单示例

    主页: http://jackson.codehaus.org/ https://github.com/FasterXML/jackson 当前jackson分为三部分,需要分别下载: jackson ...

  10. HDU5477(模拟)

    A Sweet Journey Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)T ...