目录操作

In the glibc implementation, the dirent structure is defined as follows:

           struct dirent {
               ino_t          d_ino;       /* Inode number */
               off_t          d_off;       /* Not an offset; see below */
               unsigned short d_reclen;    /* Length of this record */
               unsigned char  d_type;      /* Type of file; not supported
                                              by all filesystem types */
               char           d_name[256]; /* Null-terminated filename */
           };

一些常见的系统调用:
DIR opendir(char dirname),打开目录,返回的DIR类似于文件指针FILE
struct dirent readdir(DIR ptr),接受目录指针,返回一个dirent指针。注意调用该函数的过程会自动遍历目录!当遍历完成后返回NULL.
int closedir(DIR *ptr),关闭目录

文件信息

stat(char file, struct stat buf),失败返回-1
stat结构体中常用变量如下

struct stat {
        mode_t     st_mode;       //文件对应的模式,文件,目录等
        ino_t      st_ino;       //inode节点号
        dev_t      st_dev;        //设备号码
        dev_t      st_rdev;       //特殊设备号码
        nlink_t    st_nlink;      //文件的连接数
        uid_t      st_uid;        //文件所有者
        gid_t      st_gid;        //文件所有者对应的组
        off_t      st_size;       //普通文件,对应的文件字节数
        time_t     st_atime;      //文件最后被访问的时间
        time_t     st_mtime;      //文件内容最后被修改的时间
        time_t     st_ctime;      //文件状态改变时间
        blksize_t st_blksize;    //文件内容对应的块大小
        blkcnt_t   st_blocks;     //伟建内容对应的块数量
      };

使用样例:

#include<stdio.h>
#include<dirent.h>
#include<stdlib.h>
#include<string.h>
#include<sys/stat.h>
int main(int argc,char*argv[]){
    char dirname[256];
    strncpy(dirname,argv[1],255);
    DIR* direct=opendir(dirname);
    struct dirent* item;
    struct stat filestat;
    while((item=readdir(direct)) != NULL){
        char permstr[10];
        int stat_ret=stat(item->d_name,&filestat);
        if(stat_ret==-1){
            printf("Stat read error!\n");
            exit(-1);
        }
        
        mode_t filemode=filestat.st_mode;
        sprintf(permstr,"%c%c%c%c%c%c%c%c%c",(filemode & S_IRUSR)?'r':'-',
                (filemode & S_IWUSR)?'w':'-',(filemode & S_IXUSR)?'x':'-',
                (filemode & S_IRGRP)?'r':'-',(filemode & S_IWGRP)?'w':'-',
                (filemode & S_IXGRP)?'x':'-',(filemode & S_IROTH)?'r':'-',
                (filemode & S_IWOTH)?'w':'-',(filemode & S_IXOTH)?'x':'-');
        printf("%s  %s %hu\n",item->d_name,permstr,filestat.st_size);
    }
    
    
    return 0;
}

调用结果:

root@evillage:/home/woc/study/LinuxProgram# ./myls .
.  rwxr-xr-x 137
..  rwxr-xr-x 170
myls  rwxr-xr-x 16288
a.out  rwxr-xr-x 16288
myls.c  rw-r--r-- 875
testfile  rw-r--r-- 760
Adir  rwxr-xr-x 31
a  rwxr-xr-x 6
b  rwxr-xr-x 18
rename.c  rw-r--r-- 174
myls.c~  rw-r--r-- 873
mypwd.c  rw-r--r-- 877

链接

linux系统调用:
mkdir(char *path, mode_t mode),新建文件夹
rmdir(char *path)删除文件夹
unlink(const char *path)删除链接
link(const char src, const char dst)新建链接
rename(const char src, const char dst)重命名,可以用来移动文件
上述系统调用在成功时返回0,失败返回1.

linux使用“挂载”的方法将多个文件系统树整合到一个树上,具体过程是将一个新的文件系统嵌入到一个已经有的文件树中,

(LinuxProgram P117)

但是两个文件系统可能存在inode编号碰撞,因此link,rename这些系统调用会拒绝跨越文件系统的链接,编写以下测试代码:

#include<unistd.h>
#include<stdio.h>
#include<string.h>
int main(int argc, char *argv[]){
    char srcfile[256];
    char dstfile[256];
    strcpy(srcfile, argv[1]);
    strcpy(dstfile, argv[2]);
    int result = rename(srcfile,dstfile);
    if(result != -1){
        printf("Rename Sucessfully.\n");
    }
    else{
        printf("Failed! \n");
    }
}

结果如下:

root@evillage:/home# ls
a.out  file  test.c  woc
root@evillage:/home# lsblk
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
nvme0n1     259:0    0  1.8T  0 disk 
├─nvme0n1p1 259:1    0  100M  0 part /boot/efi
├─nvme0n1p2 259:2    0   16M  0 part 
├─nvme0n1p3 259:3    0  512G  0 part 
├─nvme0n1p4 259:4    0 1000G  0 part 
├─nvme0n1p5 259:5    0  100G  0 part 
├─nvme0n1p6 259:6    0  736M  0 part 
├─nvme0n1p7 259:7    0 74.5G  0 part /
├─nvme0n1p8 259:8    0 37.3G  0 part /home
└─nvme0n1p9 259:9    0  3.7G  0 part [SWAP]
root@evillage:/home# ./a.out file file1
Rename Sucessfully.
root@evillage:/home# ./a.out file1 /file2
Failed! 
root@evillage:/home#

通过lsblk我们可以看出,/home文件夹和根目录/处于两个不同的文件系统中,所以我们将/home下的file更名为file1能成功,但建立在/file2会失败

linux命令ln可以建立链接

root@evillage:~# touch file
root@evillage:~# ln file hard_file
root@evillage:~# ln -s file soft_file
root@evillage:~# ll -i *file
1086871 -rw-r--r-- 2 root root 0 Jul  1 19:49 file
1086871 -rw-r--r-- 2 root root 0 Jul  1 19:49 hard_file
1086872 lrwxrwxrwx 1 root root 4 Jul  1 19:49 soft_file -> file
root@evillage:~# ln -s /root/file testfile
root@evillage:~# ll -i testfile
1086873 lrwxrwxrwx 1 root root 10 Jul  1 19:53 testfile -> /root/file

我们可以看到,硬链接建立的文件与源文件inode相同,其本质是在指定目录下的block中新建了一个指向目标文件inode的部分,当file被删除后,hard_file仍能指向正确的位置。但是硬链接无法链接目录,也不能跨文件系统
而软链接则仅仅是“链接了文件名”,我们可以看到因为指向的文件file大小为4,而指向的/root/file则大小为10.
上面的file软链接soft_file文件大小仅仅为4,并没有使用绝对路径/root/file,我们可以猜测:如果将其移到其它目录,是不是就不能正常工作了呢?下面来验证:

root@evillage:~# mv testfile soft_file ..
root@evillage:~# ll -i *file
1086871 -rw-r--r-- 2 root root 0 Jul  1 19:49 file
1086871 -rw-r--r-- 2 root root 0 Jul  1 19:49 hard_file
root@evillage:~# cd ..
root@evillage:/# ll -i *file
1086872 lrwxrwxrwx 1 root root  4 Jul  1 19:49 soft_file -> file    //失效
1086873 lrwxrwxrwx 1 root root 10 Jul  1 19:53 testfile -> /root/file

因为链接testfile的时候使用的是绝对路径,因此将其移动后仍然能正常指向file,但是soft_file则会失效,我们的猜想是正确的

文件系统

linux下文件系统有下面几个重要组成部分:
1.数据块,记录真实数据
2.inode,记录文件的权限、数据块编号、最近修改的时间等等文件信息(inode并不记录文件名称,真正将inode和文件名关联的是目录),inode也可以使用间接、双间接甚至三间接方法指向数据块,以扩大能够覆盖的数据范围。
3.超级区块,记录已经使用和未使用的inode,以及文件系统的一些整体信息

mount命令基本用法:

鸟哥P248

mount [-t filesystem] LABEL=''|UUID=''|设备文件名 挂载点
-o可以加上一些参数,//待补充
如果不加-t参数,系统会自动分析相关区块内容来决定挂载什么文件系统
/etc/fstab文件所写的文件系统会在系统启动时自动挂载,使用mount -a可以重新读取该文件并挂载。
卸载文件系统时,应该先移动到其外面


StupidMagpie
6 声望0 粉丝