uc笔记06---chmod/fchmod,chown/fchown/lchown

23 篇文章 0 订阅
1.    chmod/fchmod 修改文件的权限

    #include <sys/stat.h>
    int chmod (
        const char* path, // 文件路径
        mode_t      mode  // 文件权限
    );

    int fchmod (
        int    fd,  // 文件路径
        mode_t mode // 文件权限
    );
    成功返回 0,失败返回 -1。

    mode 为以下值的位或(直接写八进制整数形式亦可,
    如 07654 - rwSr-sr-T):
          S      U      G      D
          7          6          5          4
        4 2 1    4 2 0    4 0 1    4 0 0
        ugt    rw-    r-x    r--    ->    rwSr-sr-T

        S_ISUID           - 设置用户ID
        S_ISGID           - 设置组ID
        S_ISVTX           - 粘滞
        ------------------------------
        S_IRUSR(S_IREAD)  - 属主可读
        S_IWUSR(S_IWRITE) - 属主可写
        S_IXUSR(S_IEXEC)  - 属主可执行
        ------------------------------
        S_IRGRP           - 属组可读
        S_IWGRP           - 属组可写
        S_IXGRP           - 属组可执行
        ------------------------------
        S_IROTH           - 其它可读
        S_IWOTH           - 其它可写
        S_IXOTH           - 其它可执行

    范例:chmod.c
        #include <stdio.h>
        #include <fcntl.h>
        #include <sys/stat.h>
        int main (void) {
            int fd = open ("chmod.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
            if (fd == -1) {
                perror ("open");
                return -1;
            }
        //    if (fchmod (fd, 07654) == -1) {
            if (fchmod (fd,
                S_ISUID | S_ISGID | S_ISVTX |
                S_IRUSR | S_IWUSR |
                S_IRGRP | S_IXGRP |
                S_IROTH) == -1) {
                perror ("fchmod");
                return -1;
            }
            close (fd);
            return 0;
        }


2.    chown/fchown/lchown 修改文件的属主和属组

    通过命令方式修改属主和属组:
    # chown <uid>:<gid> <file>

    通过函数方式修改属主和属组:
    #include <unistd.h>
    int chown (
        const char* path,  // 文件路径
        uid_t       owner, // 属主ID
        gid_t       group  // 属组ID
    );
    int fchown (
        int   fildes, // 文件描述符
        uid_t owner,  // 属主ID
        gid_t group   // 属组ID
    );
    int lchown (
        const char* path,  // 文件路径(不跟踪软链接)
        uid_t       owner, // 属主ID
        gid_t       group  // 属组ID
    );
    成功返回 0,失败返回 -1。

    注意:
    1. 属主和属组 ID 取 -1 表示不修改。
    2. 超级用户进程可以修改文件的属主和属组,
       普通进程必须拥有该文件才可以修改其属主和属组。

3.    truncate/ftruncate 修改文件的长度,截短丢弃,加长添零。

    #include <unistd.h>
    int truncate (
        const char* path,  // 文件路径
        off_t       length // 文件长度
    );
    int ftruncate (
        int   fd,    // 文件描述符
        off_t length // 文件长度
    );
    成功返回 0,失败返回 -1。

    范例:trunc.c
        #include <stdio.h>
        #include <string.h>
        #include <fcntl.h>
        #include <sys/mman.h>
        int main (void) {
            const char* text = "Hello, World !";
            size_t size = (strlen (text) + 1) * sizeof (text[0]);        // +1 给 \0 用
            int fd = open ("trunc.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
            if (fd == -1) {
                perror ("open");
                return -1;
            }
            if (ftruncate (fd, size) == -1) {
                perror ("ftruncate");
                return -1;
            }
            // 把文件和内存建立映射
            void* map = mmap (NULL, size, PROT_READ | PROT_WRITE,
                MAP_SHARED/*MAP_PRIVATE*/, fd, 0);
            if (map == MAP_FAILED) {
                perror ("mmap");
                return -1;
            }
            // 往内存里写
            memcpy (map, text, size);
            printf ("%s\n", map);
            // 解映射
            munmap (map, size);
            close (fd);
            return 0;
        }
        运行测试:
        #gcc trunc.c
        #hexdump -C trunc.txt    // 十六进制查看
        #./a.out
        Hello, World !
    
    在 trunc.txt 建立好的基础上,我们写下面的测试程序,实现两个程序之间共享数据:    
    范例:mmap.c
        #include <stdio.h>
        #include <fcntl.h>
        #include <sys/stat.h>
        #include <sys/mman.h>
        int main (void) {
            int fd = open ("trunc.txt", O_RDONLY);
            if (fd == -1) {
                perror ("open");
                return -1;
            }
            struct stat st;        // 用于下面求文件大小
            if (fstat (fd, &st) == -1) {
                perror ("fstat");
                return -1;
            }
            // 两个内存映射到同一个文件
            void* map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
            if (map == MAP_FAILED) {
                perror ("mmap");
                return -1;
            }
            printf ("%s\n", map);
            munmap (map, st.st_size);
            close (fd);
            return 0;
        }
        运行测试:
        #gcc mmap.c
        #hexdump -C trunc.txt    // 十六进制查看
        #./a.out
        Hello, World !

    注意:对于文件映射,
    私有映射 (MAP_PRIVATE) 将数据写到缓冲区而非文件中,只有自己可以访问。
    而对于内存映射,
    私有 (MAP_PRIVATE) 和公有 (MAP_SHARED) 没有区别,都是仅自己可以访问。

4.    link/unlink/remove/rename

    link: 创建文件的硬链接(目录条目)。

    unlink: 删除文件的硬链接(目录条目)。
    只有当文件的硬链接数降为 0 时,文件才会真正被删除。
    若该文件正在被某个进程打开,其内容直到该文件被关闭才会被真正删除。

    remove: 对文件同 unlink,对目录同 rmdir (不能删非空目录)。

    rename: 修改文件/目录名。

    #include <unistd.h>
    int link (
        const char* path1,   // 文件路径
        const char* path2    // 链接路径(硬链接)
    );
    int unlink (
        const char* path     // 链接路径
    );

    #include <stdio.h>
    int remove (
        const char* pathname // 文件/目录路径
    );
    int rename (
        const char* old,     // 原路径名
        const char* new      // 新路径名
    );
    成功返回 0,失败返回 -1。

5.    symlink/readlink

    symlink: 创建软链接;目标文件可以不存在,也可以位于另一个文件系统中。
    里面存放着目标文件的名称;

    readlink: 获取软链接文件本身(而非其目标)的内容。
    open: 不能打开软链接文件本身,打开的是软链接目标。

    #include <unistd.h>
    int symlink (
        const char* oldpath, // 文件路径(可以不存在)
        const char* newpath  // 链接路径(软链接)
    );
    成功返回 0,失败返回 -1。

    ssize_t readlink (
        const char* restrict path,   // 软链接文件路径
        char* restrict       buf,    // 缓冲区(存放目标文件路径)
        size_t               bufsize // 缓冲区大小
    );
    成功返回实际拷入缓冲区 buf 中软链接文件内容的字节数,失败返回 -1。

    范例:slink.c
        #include <stdio.h>
        #include <limits.h>
        int main (int argc, char* argv[]) {
            if (argc < 3) {
                fprintf (stderr, "用法:%s <文件> <软链接>\n", argv[0]);
                return -1;
            }
            // 建立软链接
            if (symlink (argv[1], argv[2]) == -1) {
                perror ("symlink");
                return -1;
            }
            char slink[PATH_MAX+1] = {0};                        // 目标文件路径
            if (readlink (argv[2], slink,
                sizeof (slink) - sizeof (slink[0])) == -1) {    // - sizeof (slink[0] 用于留一位给 \0
                perror ("readlink");
                return -1;
            }
            printf ("%s是%s的软链接。\n", argv[2], slink);
            return 0;
        }
        运行测试:
        #./a.out
        #./a.out none.txt slink.txt
        slink.txt 是 none.txt 的软链接。

    slink.txt 大小为 8 字节,刚好是 none.txt 的名字大小;
    而 none.txt 大小为 20 字节,里面存放的是真正的内容,所以较大;

6.    mkdir/rmdir 创建/删除空目录

    #include <sys/stat.h>
    int mkdir (
        const char* path, // 目录路径
        mode_t      mode  // 访问权限,目录的执行权限(x)表示可进入
    );

    #include <unistd.h>
    int rmdir (
        const char* path // 目录路径
    );
    成功返回 0,失败返回 -1。

7.    chdir/fchdir/getcwd

    chdir/fchdir: 更改当前工作目录。
    工作目录是进程的属性,只影响调用进程本身。

    getcwd: 获取当前工作目录(绝对路径)。

    #include <unistd.h>
    int chdir (
        const char* path // 工作目录路径
    );
    int fchdir (
        int fildes       // 工作目录描述符(由 open 函数返回)
    );
    成功返回 0,失败返回 -1。

    char* getcwd (
        char*  buf,     // 缓冲区
        size_t size     // 缓冲区大小
    );
    成功返回当前工作目录字符串指针,失败返回 NULL。

    范例:dir.c
        #include <stdio.h>
        #include <string.h>
        #include <unistd.h>
        #include <limits.h>
        int main (void) {
            char cwd[PATH_MAX+1];    // 用于装载当前目录
            if (! getcwd (cwd, sizeof (cwd))) {
                perror ("getcwd");
                return -1;
            }
            printf ("当前工作目录:%s\n", cwd);
            // 创建目录
            if (mkdir ("work", 0755) == -1) {
                perror ("mkdir");
                return -1;
            }
            // 相当于 cd,进入目录
            if (chdir ("work") == -1) {
                perror ("chdir");
                return -1;
            }
            if (! getcwd (cwd, sizeof (cwd))) {
                perror ("getcwd");
                return -1;
            }
            printf ("当前工作目录:%s\n", cwd);
            if (mkdir ("empty", 0755) == -1) {
                perror ("mkdir");
                return -1;
            }
            if (rmdir ("empty") == -1) {
                perror ("rmdir");
                return -1;
            }
            // 如果没有删除 empty,下面这段代码就会报错,因为 work 目录非空;
            if (rmdir ("../work") == -1) {
                perror ("rmdir");
                return -1;
            }
            return 0;
        }

8.    opendir/fdopendir/closedir/readdir/rewinddir/telldir/seekdir

    opendir/fdopendir: 打开目录流。
    closedir: 关闭目录流。
    readdir: 读取目录流。
    rewinddir: 复位目录流。
    telldir: 获取目录流当前位置。
    seekdir: 设置目录流当前位置。

    #include <sys/types.h>
    #include <dirent.h>
    DIR* opendir (
        const char* name // 目录路径
    );
    DIR* fdopendir (
        int fd           // 目录描述符(由open函数返回)
    );
    成功返回目录流指针,失败返回 NULL。

    int closedir (
        DIR* dirp        // 目录流指针
    );
    成功返回 0,失败返回 -1。

    struct dirent* readdir (
        DIR* dirp        // 目录流指针
    );
    成功返回下一个目录条目结构体的指针,
    到达目录尾(不置 errno)或失败(设置 errno)返回 NULL。

    struct dirent {
        ino_t          d_ino;       // i节点号
        off_t          d_off;       // 下一个条目的偏移量
                                       // 注意是磁盘偏移量,而非内存地址偏移
        unsigned short d_reclen;    // 记录长度
        unsigned char  d_type;      // 文件类型
        char           d_name[256]; // 文件名
    };

    d_type取值:
        DT_DIR     - 目录
        DT_REG     - 普通文件
        DT_LNK     - 软链接
        DT_BLK     - 块设备
        DT_CHR     - 字符设备
        DT_SOCK    - Unix域套接字
        DT_FIFO    - 有名管道
        DT_UNKNOWN - 未知

    范例:list.c
        #include <stdio.h>
        #include <dirent.h>
        #include <errno.h>
        int main (int argc, char* argv[]) {
            if (argc < 2) {
                fprintf (stderr, "用法:%s <目录>\n", argv[0]);
                return -1;
            }
            DIR* dp = opendir (argv[1]);
            if (! dp) {
                perror ("opendir");
                return -1;
            }
            errno = 0;
            struct dirent* de;
            for (de = readdir (dp); de; de = readdir (dp)) {
                switch (de -> d_type) {
                    case DT_DIR:
                        printf ("        目录:");
                        break;
                    case DT_REG:
                        printf ("    普通文件:");
                        break;
                    case DT_LNK:
                        printf ("      软链接:");
                        break;
                    case DT_BLK:
                        printf ("      块设备:");
                        break;
                    case DT_CHR:
                        printf ("    字符设备:");
                        break;
                    case DT_SOCK:
                        printf ("Unix域套接字:");
                        break;
                    case DT_FIFO:
                        printf ("    有名管道:");
                        break;
                    default:
                        printf ("        未知:");
                        break;
                }
                printf ("%s\n", de -> d_name);
            }
            if (errno) {
                perror ("readdir");
                return -1;
            }
            closedir (dp);
            return 0;
        }


    练习:打印给定路径下的目录树
    代码:tree.c
        #include <stdio.h>
        #include <dirent.h>
        #include <errno.h>
        /*
        #include <limits.h>
        */
        int tree (const char* dir, size_t depth) {
            DIR* dp = opendir (dir);
            if (! dp) {
                perror ("opendir");
                return -1;
            }
            if (chdir (dir) == -1) {        // 进入目录
                perror ("chdir");
                return -1;
            }
            errno = 0;
            struct dirent* de;
            for (de = readdir (dp); de; de = readdir (dp))
                if (de -> d_type != DT_DIR)
                    printf ("%*s%s\n", depth * 2, "", de -> d_name);    // 缩进
                else if (strcmp (de -> d_name, ".") &&                    // 不能进入本目录和父目录
                    strcmp (de -> d_name, "..")) {
                    printf ("%*s%s/\n", depth * 2, "", de -> d_name);
                    /*
                    char subdir[PATH_MAX+1];
                    sprintf (subdir, "%s/%s", dir, de -> d_name);

                    if (tree (subdir, depth + 1) == -1)
                        return -1;
                    */
                    if (tree (de -> d_name, depth + 1) == -1)
                        return -1;
                }
            if (errno) {                // errno 非零则表示出错
                perror ("readdir");
                return -1;
            }
            if (chdir ("..") == -1) {
                perror ("chdir");
                return -1;
            }
            closedir (dp);
            return 0;
        }
        int main (int argc, char* argv[]) {
            if (argc < 2) {
                fprintf (stderr, "用法:%s <目录>\n", argv[0]);
                return -1;
            }
            return tree (argv[1], 0);
        }

    回到头位置:
    void rewinddir (
        DIR* dirp // 目录流指针
    );
    得到当前位置:
    long telldir (
        DIR* dirp // 目录流指针
    );
    成功返回目录流的当前位置,失败返回 -1。
    
    设置起始位置:
    void seekdir (
        DIR* dirp,  // 目录流指针
        long offset // 位置偏移量
    );

                       +---------------------+             +-----------------------+
                     |                      v           |                       v
        +-------+----|---+-----+-------+     +-------+----|---+-----+--------+    +-------
        | d_ino | d_off | ... | a.txt | ... | d_ino | d_off | ... | b.txt | ... | d_ino
        +-------+-------+-----+-------+     +-------+--------+-----+-------+     +-------
        ^                                       ^
        |          -- readdir() ->          |

    范例:seek.c
        #include <stdio.h>
        #include <dirent.h>
        #include <errno.h>
        int main (int argc, char* argv[]) {
            if (argc < 2) {
                fprintf (stderr, "用法:%s <目录>\n", argv[0]);
                return -1;
            }
            DIR* dp = opendir (argv[1]);
            if (! dp) {
                perror ("opendir");
                return -1;
            }
            seekdir (dp, 1722002057);    // 设置起始位置
            rewinddir (dp);                // 回到头位置
            long offset = telldir (dp);
            if (offset == -1) {
                perror ("telldir");
                return -1;
            }
            errno = 0;
            struct dirent* de;
            for (de = readdir (dp); de; de = readdir (dp)) {
                printf ("[%010d %010d] ", offset, de -> d_off);
                switch (de -> d_type) {
                    case DT_DIR:
                        printf ("        目录:");
                        break;
                    case DT_REG:
                        printf ("    普通文件:");
                        break;
                    case DT_LNK:
                        printf ("      软链接:");
                        break;
                    case DT_BLK:
                        printf ("      块设备:");
                        break;
                    case DT_CHR:
                        printf ("    字符设备:");
                        break;
                    case DT_SOCK:
                        printf ("Unix域套接字:");
                        break;
                    case DT_FIFO:
                        printf ("    有名管道:");
                        break;
                    default:
                        printf ("        未知:");
                        break;
                }
                printf ("%s\n", de -> d_name);
                if ((offset = telldir (dp)) == -1) {
                    perror ("telldir");
                    return -1;
                }
            }
            if (errno) {
                perror ("readdir");
                return -1;
            }
            closedir (dp);
            return 0;
        }
       
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值