• 作者:老汪软件技巧
  • 发表时间:2024-10-29 15:09
  • 浏览量:

stat

int stat(const char *path, struct stat *struct_stat);
int lstat(const char *path,struct stat *struct_stat);
int fstat(int fdp, struct stat *struct_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;     //伟建内容对应的块数量
};

有两个比较相似的字段:

dev_t     st_dev;         /* ID of device containing file */
dev_t     st_rdev;        /* Device ID (if special file) */

这两个存的都是主次设备号,都要通过宏major和minor来取出来

空洞文件

st_size 表示文件的字节数,但是并不表示文件占用的实际大小。有个空洞文件的概念,就是我们可以创建一个非常大的文件,但是实际上文件里面没有东西,利用下面这两个函数,就可以在距离文件很远的位置,写一个字符,然后关闭文件,这样就得到一个非常大的,但是实际上只写入了一个字符的文件。

Java 里面使用RandomAccessFile可以做到同样的效果。

fopen()
lseek()
write()
close()

由于实际上只写入了一个字符,linux的文件系统很聪明,它就只会分配你实际上占用的磁盘空间,4K大小。

所以,计算磁盘占用空间,需要使用:st_blksize * st_blocks。

文件属性

st_mode

0~8 bit : 文件访问权限

9~11 bit : 文件访问权限控制

12~15 bit:文件类型

umask

langzi989.github.io/2017/09/13/…

若没有文件掩码时,文件的默认权限为0666,文件夹的默认权限为0777。

原因:创建文件一般是用来读写,所以默认情况下所有用户都具有读写权限,但是没有可执行权限,所以文件创建的默认权限为0666而文件夹的x权限表示的是打开权限,所以这个权限必须要有,所以文件夹的默认权限为0777。

上述的权限是在没有umask情况下的默认权限。但是系统为了保护用户创建文件和文件夹的权限,此时系统会有一个默认的用户掩码(umask),大多数的Linux系统的默认掩码为022。用户掩码的作用是用户在创建文件时从文件的默认权限中去除掩码中的权限。所以文件创建之后的权限实际为:

#文件创建权限
默认权限(文件0666,文件夹0777)-umask

所以在用户不修改umask的情况下,创建文件的权限为:0666-0022=0644。创建文件夹的权限为:0777-0022=0755

粘住位

是 st_mode 的 T 位。

当目录被设置了粘住位之后,即便用户对该目录有写入权限,也不能删除该目录中其他用户的文件数据,只有该文件的所有者以及root用户才能删除。

设置了该位之后,可以保持一种动态平衡:允许所有用户在该目录写入/删除文件,但是不能删除其他用户文件。

/tmp 目录就设置了该位。

chdir/fchdir

chdir是一个用于改变当前工作目录的系统调用和命令。在 UNIX 和类 UNIX 系统(如 Linux)中,chdir允许用户或程序切换到指定的目录,这对于文件操作和脚本执行非常重要。

#include 
#include 
int main() {
    if (chdir("/usr/local/bin") != 0) {
        perror("chdir failed");
        return 1;
    }
    printf("Changed directory to /usr/local/bin\n");
    return 0;
}

越权问题:

假设有一个 Linux 系统,用户alice有权限访问自己的主目录/home/alice,但没有权限访问另一个用户bob的主目录/home/bob。

正常权限设置:越权操作:潜在的越权风险:

这种情况提醒我们在系统中进行严格的权限管理,确保用户不能访问或更改不属于自己的资源。

glob

glob函数用于文件名模式匹配。它可以根据指定的模式查找符合条件的文件路径名,常用于脚本编程和命令行操作。

在 C 语言中,glob的函数原型通常如下:

#include 
int glob(const char *pattern, int flags, int (*errfunc)(const char *epath, int eerrno), glob_t *pglob);

参数说明

glob_t结构体包含以下字段:

#include 
#include 
#include 
int main() {
    glob_t globbuf;
    
    // 初次调用
    globbuf.gl_offs = 0// 从数组开始位置
    if (glob("*.c"0NULL, &globbuf) == 0) {
        for (size_t i = 0; i < globbuf.gl_pathc; i++) {
            printf("C files: %s\n", globbuf.gl_pathv[i]);
        }
    }
    // 设置偏移量,存储结果
    globbuf.gl_offs = globbuf.gl_pathc; // 从已存在结果后开始
    if (glob("*.h"0NULL, &globbuf) == 0) {
        for (size_t i = 0; i < globbuf.gl_pathc; i++) {
            printf("Header files: %s\n", globbuf.gl_pathv[i]);
        }
    }
    globfree(&globbuf); // 释放资源
    return 0;
}

glob函数接收一个回调函数作为参数,主要是为了处理在匹配过程中可能遇到的错误情况。glob函数的回调参数中的错误码与函数返回值的错误码并不完全相同,但它们都是用于表示错误情况。比如在某些情况下,glob的返回值为非零(例如,GLOB_ERR),这可能是因为在处理某个特定文件时发生了错误,而这个错误可以通过回调函数捕获到。

尽管两者都涉及错误处理,但它们的用途和范围不同。函数返回值提供了匹配结果的总体状态,而回调函数中的错误码则提供了更细致的错误信息。

opendir

除了opendir,还有其他一些常用的操作目录的 API。以下是一些主要的函数及其用途:

#include 
#include 
#include 
#include 
#include 
int main() {
    // 创建目录
    mkdir("test_dir"0755);
    // 打开目录
    DIR *dir = opendir("test_dir");
    if (dir == NULL) {
        perror("无法打开目录");
        return EXIT_FAILURE;
    }
    // 读取目录(此时应该为空)
    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        printf("目录条目: %s\n", entry->d_name);
    }
    closedir(dir);
    // 重命名目录
    rename("test_dir""new_test_dir");
    // 删除空目录
    rmdir("new_test_dir");
    return EXIT_SUCCESS;
}