前言
在Linux系统中利用ln指令产生链接,Linux链接分两种,一种被称为硬链接(Hard Link),另一种被称为符号链接(Symbolic Link)。默认情况下,ln命令产生硬链接。
硬链接
硬链接是一种通过文件系统的inode链接产生,硬链接可以认为是一个指针,指向文件inode的指针,系统并不为它重新分配inode。所以存在多个文件指向同一个inode节点,添加硬链接,会使文件的链接数增加。删除多个链接中其中一个连接并不影响inode和其它的连接,只有当最后一个连接被删除后,文件的数据块及目录的连接才会被释放。
硬链接有两个限制:
不能创建跨文件系统的硬链接。
只有超级用户才可以创建目录链接,一般用户不允许创建。(跟系统有关)
硬链接的使用
/*************
* 硬链接指令ln使用方式如下:
* ln existingfile newfile
* 说明:
* 为当前存在的文件existingfile创建新的硬链接,链接文件名为newfile.
*/
举例说明:
/********
* 举例子说明:
* 列出当前文件存在的信息,包括关键inode节点信息:
********/
$ ls -il file1 file2
10890904 -rw-rw-r-- 1 file1
10890903 -rw-rw-r-- 1 file2
$ ln file1 hardlink
$ ls -il file1 file2 hardlink
10890904 -rw-rw-r-- 2 file1
10890903 -rw-rw-r-- 1 file2
10890904 -rw-rw-r-- 2 hardlink
$ cat file1 hardlink
Hello, this is the file1.
Hello, this is the file1.
$ rm file1
$ ls -il file2 hardlink
10890903 -rw-rw-r-- 1 file2
10890904 -rw-rw-r-- 1 hardlink
$ cat hardlink
Hello, this is the file1.
$ rm hardlink
$ cat hardlink
cat: hardlink: No such file or directory <span style="font-family: Arial, Helvetica, sans-serif;"> </span>
由上面例子我们可以看出,创建硬链接之前,file1 显示的链接数目为1,创建链接后hardlink之后,file1和hardlink的链接数目都变为2,但是file1和hardlink的inode号码是一样的,说明创建硬链接并不会新建inode节点,只会增加链接数。因此,创建硬链接使多个文件指向同一个inode节点,它们具有同样的inode索引节点号和文件属性。删除其中任何一个链接,并不会删除原始文件信息,如rm file1 ,只是删除一个链接指针,链接数同时减一,只有将所有指向同一个inode节点的链接指针删除,也即链接数减为0时,内核才会把文件内容从磁盘上删除。
4.16 符号链接
可以在不同文件系统中创建符号链接,任何用户可以创建指向目录的符号链接。给ln指令加上-s选项,则是创建符号链接,它是创建一个独立的文件,而这个文件的数据操作会指向它所链接的那个文件的文件名。当所链接的源文件被删除时,符号链接则打不开该文件,即链接失效。
举例说明:
/*************
* 符号链接指令ln使用方式如下:
* ln -s existingfile newfile
* 说明:
* 为当前存在的文件existingfile创建新的符号链接,链接文件名为newfile.
* 举例子说明:
* 列出当前文件存在的信息,包括关键inode节点信息:
*/
$ ls -il file1 file2
10890912 -rw-rw-r-- 1 file1
10890903 -rw-rw-r-- 1 file2
$ ln -s file1 symblink
$ ls -il file1 file2 symblink
10890912 -rw-rw-r-- 2 file1
10890903 -rw-rw-r-- 1 file2
10890907 lrwxrwxrwx 1 symblink -> file1
$ cat file1 symblink
Hello, this is the file1.
Hello, this is the file1.
$ rm file1
$ ls -il file2 symblink
10890903 -rw-rw-r-- 1 file2
10890907 lrwxrwxrwx 1 symblink -> file1
$ cat symblink
cat: symblink: No such file or directory
创建符号链接时,会分配新的inode节点,即是新的文件,链接数目不会增加。
可以得到以下全部结论:
删除硬连接hardlink,对file1无影响;
删除原文件file1,对硬连接hardlink没有影响,符号连接symblink失效;
同时删除原文件file1,硬连接hardlink,整个文件会真正的被删除。
4.17 symblink和readlink函数
/**********
* 函数功能:创建一个符号链接。
* 返回值:若成功则返回0,若出错则返回-1;
* 函数原型: int symblink(const char *actualpath, const char *sympath);
*/
/*********
* 说明
* 该函数创建一个指向actualpath的新目录项sympath,创建符号链接时,并不要求
* actualpath存在,也可以位于不同的文件系统。 即对于一个不存在的文件或者目录,也可* 以创建符号链接,但是此时无法打开这个链接。
*/
/******************
* 函数功能:打开符号链接
* 返回值:若成功则返回读到buf中的字节数,若出错则返回-1;
* 函数原型: ssize_t readlink(const char *pathname, char *buf, size_t bufsize); */
4.18 文件时间
/* 根据stat的结构可以知道,文件有三种时间:
* st_atime 最后访问时间,即最后访问文件的时间 ls -u
* st_mtime 最后修改时间,即修改文件内容的时间 默认ls
* st_ctime 最后更改时间,即更改inode节点的时间 ls –c
* 更改文件的访问权限,用户ID,链接数都可以影响到inode
* ****/
4.19 utime函数
/* 函数功能:更改文件访问时间和文件修改时间; 不能更改状态时间 st_ctime ,当调用
* utime函数时,此字段将被自动更新
* 返回值:若成功则返回0,若出错则返回-1;
* 函数原型: int utime(const char *pathname, const struct utimbuf *times);
* 其中结构体struct utimbuf 定义如下:
* struct utimbuf
* {
* time_t actime;// access time
* time_t modtime;// modification time
* };
* 参数说明:
* pathname是要更改时间的文件;
* times若为空指针,则表示设置为当前时间;
* 若times非空指针,则设置为所指向结构体中的对应值;
* ********/
测试程序:功能是更改文件 ,但是文件时间不改变。
#include "apue.h"
#include <fcntl.h>
#include <utime.h>
int main(int argc, char *argv[])
{
int i,fd;
struct stat statbuf;
struct utimbuf timebuf;
for(i=1;i<argc;i++)
{
//获取文件的当前时间
if(stat(argv[i],&statbuf) < 0){
err_ret("%s:stat error.\n",argv[i]);
continue;
}
//将文件长度截短为0 ,但不更改文件的访问时间和修改时间
if((fd = open(argv[i],O_RDWR | O_TRUNC)) < 0){
err_ret("%s:open error.\n",argv[i]);
continue;
}
close(fd);
timebuf.actime = statbuf.st_atime;
timebuf.modtime = statbuf.st_mtime;
//把时间更改为之前通过 stat函数获得的时间,即文件虽然动了但是时间没变
if(utime(argv[i],&timebuf) < 0){
err_ret("%s:utime error.\n",argv[i]);
continue;
}
}
exit(0);
}
目录基本操作
目录的基本操作包括创建目录 mkdir 、删除目录 rmdir 、打开目录opendir、读取目录readdir、关闭目录closedir等操作,如下说明:
4.20 mkdir 和 rmdir 函数
用 mkdir 函数创建目录,用 rmdir 函数删除目录
/***********
* 目录创建
* 函数功能:创建一个空目录
* 返回值:若成功则返回0,若出错则返回-1;
* 函数原型:
* #include <sys/stat.h>
* int mkdir(const char *pathname, mode_t mode);
* 说明:
* 此函数创建一个新的空目录,其中.和..目录项是自动创建的。
* 所指定的文件访问权限mode由进程的文件模式创建屏蔽字修改。
*
* 删除空目录
* 函数功能:删除一个空的目录
* 返回值:若成功则返回0,若出错则返回-1;
* 函数原型:
* #include <unistd.h>
* int rmdir(const char *pathname);
* 说明:
* 如果调用该函数使目录的链接数为0,且没有其他进程打开该目录,则释放该目录空间。
* 若链接数为0,此时有进程打开该目录,在进程关闭前不会释放目录空间。
* ***************/
4.21 读目录
/*
* 1、 函数功能:读取目录
* 返回值:若成功返回指针,若在目录结尾或出错则返回NULL;
* 函数原型:
* #include <unistd.h>
* #include <dirent.h>
* struct dirent *readdir(DIR *dp);
* 2、打开目录opendir
* 函数功能:打开一个目录;
* 返回值:若成功返回一个目录指针,若出错则返回NULL指针;
* 函数原型:
* #include <sys/types.h>
* #include <dirent.h>
* DIR *opendir(const char *pathname);
*
* 3、重设与dp关联的目录中的位置
*
* 函数功能:重设与dp关联的在目录中的位置;
* 没有返回值;
* 函数原型:
* #include <sys/types.h>
* #include <dirent.h>
* void rewinddir(DIR *dp);
*
* 4、dp关联的在目录的当前位置return current location in directory stream.
*
* 函数功能:获取与dp关联的在目录中的当前位置;
* 返回值:若成功返回与dp关联的在目录中的当前位置,若出错返回-1;
* 函数原型:
* #include <dirent.h>
* off_t telldir(DIR *dp);
*
* 5、The seekdir() function sets the location in the directory
* stream from which the next readdir() call will start.
* seekdir() should be used with an offset returned by telldir().
*
* 函数功能:设置下一个readdir调用在目录的位置
* 无返回值
* 函数原型:
* #include <dirent.h>
* void seekdir(DIR *dp, off_t offset);
*
* 6、关闭一个已打开的目录
*
* 函数功能:关闭一个已打开的目录
* 返回值:若成功返回0,若出错返回-1;
* 函数原型:
* #include <sys/types.h>
* #include <dirent.h>
* int closedir(DIR *dp);
* **********************************/
目录信息结构
/************************************
* struct dirent结构信息
* *******/
struct dirent
{
long d_ino; /* inode number */
off_t d_off; /* offset to this dirent */
unsigned short d_reclen; /* length of this d_name */
char d_name [NAME_MAX+1]; /* file name (null-terminated) */
}; */
4.22 chdir、fchdir、getcwd 函数
/*************************
* 更改当前工作目录。
* 函数功能:更改当前的工作目录;
* 返回值:若成功则返回0,若出错则返回-1;
* 函数原型:
* #include <unistd.h>
* int chdir(const char *pathname);
* int fchdir(int filedes);
* 说明:
* 这两个函数分别用pathname或打开文件描述符来指定当前的工作目录。
* **********/
/*************
* 函数功能:获取当前工作目录的绝对路径
* 返回值:若成功则返回buf,若出错则返回NULL;
* 函数原型:
* #include <unistd.h>
* char *getcwd(char *buf, size_t size);
* 说明:buf存储绝对路径,长度size应该最够容纳绝对路径再加上一个null终止字符,否* 则返回出错。
* ***************/