第4章——《文件和目录》(1)

实验环境介绍

  • gcc:4.8.5
  • glibc:glibc-2.17-222.el7.x86_64
  • os:Centos7.4
  • kernel:3.10.0-693.21.1.el7.x86_64

引言

  • 第3章的I/O函数是围绕着普通文件I/O进行的。这一章主要是描述文件系统的其他特征和文件的性质、属性。此过程中,我们说明修改这些属性的各个函数,还详细说明unix文件系统的结构以及符号链接。

函数stat、fstat、fstatat和lstat

stat函数族

struct 结构
           struct stat {
               dev_t st_dev; /* ID of device containing file */
               ino_t st_ino; /* inode number */
               mode_t st_mode; /* protection */
               nlink_t st_nlink; /* number of hard links */
               uid_t st_uid; /* user ID of owner */
               gid_t st_gid; /* group ID of owner */
               dev_t st_rdev; /* device ID (if special file) */
               off_t st_size; /* total size, in bytes */
               blksize_t st_blksize; /* blocksize for file system I/O */
               blkcnt_t st_blocks; /* number of 512B blocks allocated */
               time_t st_atime; /* time of last access */
               time_t st_mtime; /* time of last modification */
               time_t st_ctime; /* time of last status change */
           };
stat函数测试代码
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

#define err_sys(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf("\nerrno:%d %s\n", errno, strerror(errno));\
    exit(EXIT_FAILURE);\
} while (0)


/* struct stat info */
// struct stat {
// dev_t st_dev; /* ID of device containing file */
// ino_t st_ino; /* inode number */
// mode_t st_mode; /* protection */
// nlink_t st_nlink; /* number of hard links */
// uid_t st_uid; /* user ID of owner */
// gid_t st_gid; /* group ID of owner */
// dev_t st_rdev; /* device ID (if special file) */
// off_t st_size; /* total size, in bytes */
// blksize_t st_blksize; /* blocksize for file system I/O */
// blkcnt_t st_blocks; /* number of 512B blocks allocated */
// time_t st_atime; /* time of last access */
// time_t st_mtime; /* time of last modification */
// time_t st_ctime; /* time of last status change */
// };


int
main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    struct stat sb;
    if (stat(argv[1], &sb) == -1) {
        err_sys("stat");
        exit(EXIT_FAILURE);
    }

    printf("File type: ");

    switch (sb.st_mode & S_IFMT) {
    case S_IFBLK: printf("block device\n"); break;
    case S_IFCHR: printf("character device\n"); break;
    case S_IFDIR: printf("directory\n"); break;
    case S_IFIFO: printf("FIFO/pipe\n"); break;
    case S_IFLNK: printf("symlink\n"); break;
    case S_IFREG: printf("regular file\n"); break;
    case S_IFSOCK: printf("socket\n"); break;
    default: printf("unknown?\n"); break;
    }

    printf("I-node number: %ld\n", (long) sb.st_ino);

    printf("Mode: %lo (octal)\n",
           (unsigned long) sb.st_mode);

    printf("Link count: %ld\n", (long) sb.st_nlink);
    printf("Ownership: UID=%ld GID=%ld\n",
           (long) sb.st_uid, (long) sb.st_gid);

    printf("Preferred I/O block size: %ld bytes\n",
           (long) sb.st_blksize);
    printf("File size: %lld bytes\n",
           (long long) sb.st_size);
    printf("Blocks allocated: %lld\n",
           (long long) sb.st_blocks);

    printf("Last status change: %s", ctime(&sb.st_ctime));
    printf("Last file access: %s", ctime(&sb.st_atime));
    printf("Last file modification: %s", ctime(&sb.st_mtime));

    exit(EXIT_SUCCESS);
}

result:
manjingliu@NGFW-DEV64 ~/apue/part_4 $ ./4_1 stat.tmp 
File type: regular file
I-node number: 13647692
Mode: 100644 (octal)
Link count: 1
Ownership: UID=1058 GID=1058
Preferred I/O block size: 4096 bytes
File size: 0 bytes
Blocks allocated: 0
Last status change: Tue Jul 17 12:01:39 2018
Last file access: Tue Jul 17 12:01:39 2018
Last file modification: Tue Jul 17 12:01:39 2018
manjingliu@NGFW-DEV64 ~/apue/part_4 $ ./4_1 4_1
File type: regular file
I-node number: 13649435
Mode: 100755 (octal)
Link count: 1
Ownership: UID=1058 GID=1058
Preferred I/O block size: 4096 bytes
File size: 8310 bytes
Blocks allocated: 24
Last status change: Tue Jul 17 12:10:30 2018
Last file access: Tue Jul 17 12:10:30 2018
Last file modification: Tue Jul 17 12:10:30 2018
manjingliu@NGFW-DEV64 ~/apue/part_4 $ ./4_1 stat.dir/
File type: directory
I-node number: 13649566
Mode: 40755 (octal)
Link count: 2
Ownership: UID=1058 GID=1058
Preferred I/O block size: 4096 bytes
File size: 4096 bytes
Blocks allocated: 8
Last status change: Tue Jul 17 12:11:05 2018
Last file access: Tue Jul 17 12:11:05 2018
Last file modification: Tue Jul 17 12:11:05 2018
manjingliu@NGFW-DEV64 ~/apue/part_4 $ ./4_1 stat.fifo 
File type: FIFO/pipe
I-node number: 13649573
Mode: 10644 (octal)
Link count: 1
Ownership: UID=1058 GID=1058
Preferred I/O block size: 4096 bytes
File size: 0 bytes
Blocks allocated: 0
Last status change: Tue Jul 17 12:11:19 2018
Last file access: Tue Jul 17 12:11:19 2018
Last file modification: Tue Jul 17 12:11:19 2018
fstat函数测试
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>

#define err_sys(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf("\nerrno:%d %s\n", errno, strerror(errno));\
    exit(EXIT_FAILURE);\
} while (0)


/* struct stat info */
// struct stat {
// dev_t st_dev; /* ID of device containing file */
// ino_t st_ino; /* inode number */
// mode_t st_mode; /* protection */
// nlink_t st_nlink; /* number of hard links */
// uid_t st_uid; /* user ID of owner */
// gid_t st_gid; /* group ID of owner */
// dev_t st_rdev; /* device ID (if special file) */
// off_t st_size; /* total size, in bytes */
// blksize_t st_blksize; /* blocksize for file system I/O */
// blkcnt_t st_blocks; /* number of 512B blocks allocated */
// time_t st_atime; /* time of last access */
// time_t st_mtime; /* time of last modification */
// time_t st_ctime; /* time of last status change */
// };


int
main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    int fd = open(argv[1], O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
    if (fd < 0) {
        err_sys("open");
    }

    struct stat sb;
    if (fstat(fd, &sb) == -1) {
        err_sys("stat");
        exit(EXIT_FAILURE);
    }

    printf("File type: ");

    switch (sb.st_mode & S_IFMT) {
    case S_IFBLK: printf("block device\n"); break;
    case S_IFCHR: printf("character device\n"); break;
    case S_IFDIR: printf("directory\n"); break;
    case S_IFIFO: printf("FIFO/pipe\n"); break;
    case S_IFLNK: printf("symlink\n"); break;
    case S_IFREG: printf("regular file\n"); break;
    case S_IFSOCK: printf("socket\n"); break;
    default: printf("unknown?\n"); break;
    }

    printf("I-node number: %ld\n", (long) sb.st_ino);

    printf("Mode: %lo (octal)\n",
           (unsigned long) sb.st_mode);

    printf("Link count: %ld\n", (long) sb.st_nlink);
    printf("Ownership: UID=%ld GID=%ld\n",
           (long) sb.st_uid, (long) sb.st_gid);

    printf("Preferred I/O block size: %ld bytes\n",
           (long) sb.st_blksize);
    printf("File size: %lld bytes\n",
           (long long) sb.st_size);
    printf("Blocks allocated: %lld\n",
           (long long) sb.st_blocks);

    printf("Last status change: %s", ctime(&sb.st_ctime));
    printf("Last file access: %s", ctime(&sb.st_atime));
    printf("Last file modification: %s", ctime(&sb.st_mtime));

    exit(EXIT_SUCCESS);
}

result:
manjingliu@NGFW-DEV64 ~/apue/part_4 $ ./4_2 stat.tmp 
File type: regular file
I-node number: 13647692
Mode: 100644 (octal)
Link count: 1
Ownership: UID=1058 GID=1058
Preferred I/O block size: 4096 bytes
File size: 0 bytes
Blocks allocated: 0
Last status change: Tue Jul 17 12:01:39 2018
Last file access: Tue Jul 17 12:01:39 2018
Last file modification: Tue Jul 17 12:01:39 2018
manjingliu@NGFW-DEV64 ~/apue/part_4 $ ./4_2 4_1
File type: regular file
I-node number: 13649435
Mode: 100755 (octal)
Link count: 1
Ownership: UID=1058 GID=1058
Preferred I/O block size: 4096 bytes
File size: 8310 bytes
Blocks allocated: 24
Last status change: Tue Jul 17 14:22:33 2018
Last file access: Tue Jul 17 14:22:33 2018
Last file modification: Tue Jul 17 14:22:33 2018
manjingliu@NGFW-DEV64 ~/apue/part_4 $ ./4_1 stat.dir/
File type: directory
I-node number: 13649566
Mode: 40755 (octal)
Link count: 2
Ownership: UID=1058 GID=1058
Preferred I/O block size: 4096 bytes
File size: 4096 bytes
Blocks allocated: 8
Last status change: Tue Jul 17 12:11:05 2018
Last file access: Tue Jul 17 12:11:05 2018
Last file modification: Tue Jul 17 12:11:05 2018
manjingliu@NGFW-DEV64 ~/apue/part_4 $ ./4_1 stat.fifo 
File type: FIFO/pipe
I-node number: 13649573
Mode: 10644 (octal)
Link count: 1
Ownership: UID=1058 GID=1058
Preferred I/O block size: 4096 bytes
File size: 0 bytes
Blocks allocated: 0
Last status change: Tue Jul 17 12:11:19 2018
Last file access: Tue Jul 17 12:11:19 2018
Last file modification: Tue Jul 17 12:11:19 2018
lstat函数测试:这个和stat一样,但是如果是符号链接,则返回符号链接文件的信息
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>

#define err_sys(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf("\nerrno:%d %s\n", errno, strerror(errno));\
    exit(EXIT_FAILURE);\
} while (0)


/* struct stat info */
// struct stat {
// dev_t st_dev; /* ID of device containing file */
// ino_t st_ino; /* inode number */
// mode_t st_mode; /* protection */
// nlink_t st_nlink; /* number of hard links */
// uid_t st_uid; /* user ID of owner */
// gid_t st_gid; /* group ID of owner */
// dev_t st_rdev; /* device ID (if special file) */
// off_t st_size; /* total size, in bytes */
// blksize_t st_blksize; /* blocksize for file system I/O */
// blkcnt_t st_blocks; /* number of 512B blocks allocated */
// time_t st_atime; /* time of last access */
// time_t st_mtime; /* time of last modification */
// time_t st_ctime; /* time of last status change */
// };


int
main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    struct stat sb;
    if (lstat(argv[1], &sb) == -1) {
        err_sys("stat");
        exit(EXIT_FAILURE);
    }

    printf("File type: ");

    switch (sb.st_mode & S_IFMT) {
    case S_IFBLK: printf("block device\n"); break;
    case S_IFCHR: printf("character device\n"); break;
    case S_IFDIR: printf("directory\n"); break;
    case S_IFIFO: printf("FIFO/pipe\n"); break;
    case S_IFLNK: printf("symlink\n"); break;
    case S_IFREG: printf("regular file\n"); break;
    case S_IFSOCK: printf("socket\n"); break;
    default: printf("unknown?\n"); break;
    }

    printf("I-node number: %ld\n", (long) sb.st_ino);

    printf("Mode: %lo (octal)\n",
           (unsigned long) sb.st_mode);

    printf("Link count: %ld\n", (long) sb.st_nlink);
    printf("Ownership: UID=%ld GID=%ld\n",
           (long) sb.st_uid, (long) sb.st_gid);

    printf("Preferred I/O block size: %ld bytes\n",
           (long) sb.st_blksize);
    printf("File size: %lld bytes\n",
           (long long) sb.st_size);
    printf("Blocks allocated: %lld\n",
           (long long) sb.st_blocks);

    printf("Last status change: %s", ctime(&sb.st_ctime));
    printf("Last file access: %s", ctime(&sb.st_atime));
    printf("Last file modification: %s", ctime(&sb.st_mtime));

    exit(EXIT_SUCCESS);
}

result:
manjingliu@NGFW-DEV64 ~/apue/part_4 $ ./4_3 stat.tmp 
File type: regular file
I-node number: 13647692
Mode: 100644 (octal)
Link count: 1
Ownership: UID=1058 GID=1058
Preferred I/O block size: 4096 bytes
File size: 0 bytes
Blocks allocated: 0
Last status change: Tue Jul 17 12:01:39 2018
Last file access: Tue Jul 17 12:01:39 2018
Last file modification: Tue Jul 17 12:01:39 2018
manjingliu@NGFW-DEV64 ~/apue/part_4 $ ./4_3 stat.link 
File type: symlink
I-node number: 13650313
Mode: 120777 (octal)
Link count: 1
Ownership: UID=1058 GID=1058
Preferred I/O block size: 4096 bytes
File size: 8 bytes
Blocks allocated: 0
Last status change: Tue Jul 17 14:29:06 2018
Last file access: Tue Jul 17 14:29:06 2018
Last file modification: Tue Jul 17 14:29:06 2018
fstatat函数
       int fstatat(int dirfd, const char *pathname, struct stat *buf,
                   int flags);
  • 如果pathname是相对路径,那么它就会被解释为相对于文件描述符dirfd所引用的目录(而不是相对于调用过程的当前工作目录)。
  • 如果pathname是相对路径,然后dirfd为AT_FDCWD,然后他就会被解释成相对于调用进程的当前工作目录解释路径名
  • 如果pathname是绝对路径,那么dirfd就被忽略
  • 测试代码一:
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <dirent.h>

#define err_sys(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf("\nerrno:%d %s\n", errno, strerror(errno));\
    exit(EXIT_FAILURE);\
} while (0)


/* struct stat info */
// struct stat {
// dev_t st_dev; /* ID of device containing file */
// ino_t st_ino; /* inode number */
// mode_t st_mode; /* protection */
// nlink_t st_nlink; /* number of hard links */
// uid_t st_uid; /* user ID of owner */
// gid_t st_gid; /* group ID of owner */
// dev_t st_rdev; /* device ID (if special file) */
// off_t st_size; /* total size, in bytes */
// blksize_t st_blksize; /* blocksize for file system I/O */
// blkcnt_t st_blocks; /* number of 512B blocks allocated */
// time_t st_atime; /* time of last access */
// time_t st_mtime; /* time of last modification */
// time_t st_ctime; /* time of last status change */
// };


int
main(int argc, char *argv[])
{
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <dirpath> <filename>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    struct stat dir_st;
    if (stat(argv[1], &dir_st) < 0)
        err_sys("stat %s", argv[1]);

    if ( !S_ISDIR(dir_st.st_mode) ) {
        fprintf(stderr, "Usage: %s is not directory\n", argv[1]);
        exit(EXIT_FAILURE);
    }

    DIR *dir = opendir(argv[1]);
    if (NULL == dir) {
        err_sys("open");
    }

    int fd = dirfd(dir);
    struct stat sb;
    if (fstatat(fd, argv[2], &sb, AT_SYMLINK_NOFOLLOW) == -1) {
    // if (fstatat(fd, argv[2], &sb, 0) == -1) {
        err_sys("fstatat");
    }

    printf("File type: ");

    switch (sb.st_mode & S_IFMT) {
    case S_IFBLK: printf("block device\n"); break;
    case S_IFCHR: printf("character device\n"); break;
    case S_IFDIR: printf("directory\n"); break;
    case S_IFIFO: printf("FIFO/pipe\n"); break;
    case S_IFLNK: printf("symlink\n"); break;
    case S_IFREG: printf("regular file\n"); break;
    case S_IFSOCK: printf("socket\n"); break;
    default: printf("unknown?\n"); break;
    }

    printf("I-node number: %ld\n", (long) sb.st_ino);

    printf("Mode: %lo (octal)\n",
           (unsigned long) sb.st_mode);

    printf("Link count: %ld\n", (long) sb.st_nlink);
    printf("Ownership: UID=%ld GID=%ld\n",
           (long) sb.st_uid, (long) sb.st_gid);

    printf("Preferred I/O block size: %ld bytes\n",
           (long) sb.st_blksize);
    printf("File size: %lld bytes\n",
           (long long) sb.st_size);
    printf("Blocks allocated: %lld\n",
           (long long) sb.st_blocks);

    printf("Last status change: %s", ctime(&sb.st_ctime));
    printf("Last file access: %s", ctime(&sb.st_atime));
    printf("Last file modification: %s", ctime(&sb.st_mtime));

    exit(EXIT_SUCCESS);
}

result:
manjingliu@NGFW-DEV64 ~/apue/part_4 $ ./4_4 /home/manjingliu/apue/part_4/stat.dir fstatat.tmp 
File type: regular file
I-node number: 13650317
Mode: 100644 (octal)
Link count: 1
Ownership: UID=1058 GID=1058
Preferred I/O block size: 4096 bytes
File size: 0 bytes
Blocks allocated: 0
Last status change: Tue Jul 17 14:38:09 2018
Last file access: Tue Jul 17 14:38:09 2018
Last file modification: Tue Jul 17 14:38:09 2018
manjingliu@NGFW-DEV64 ~/apue/part_4 $ ./4_4 /home/manjingliu/apue /home/manjingliu/apue/part_4/stat.dir/fstatat.tmp 
File type: regular file
I-node number: 13650317
Mode: 100644 (octal)
Link count: 1
Ownership: UID=1058 GID=1058
Preferred I/O block size: 4096 bytes
File size: 0 bytes
Blocks allocated: 0
Last status change: Tue Jul 17 14:38:09 2018
Last file access: Tue Jul 17 14:38:09 2018
Last file modification: Tue Jul 17 14:38:09 2018
manjingliu@NGFW-DEV64 ~/apue/part_4 $ ./4_4 /home/manjingliu/apue /home/manjingliu/apue/part_4/stat.dir/fstatat.link 
File type: symlink
I-node number: 13650322
Mode: 120777 (octal)
Link count: 1
Ownership: UID=1058 GID=1058
Preferred I/O block size: 4096 bytes
File size: 38 bytes
Blocks allocated: 0
Last status change: Tue Jul 17 15:16:37 2018
Last file access: Tue Jul 17 15:16:37 2018
Last file modification: Tue Jul 17 15:16:37 2018
  • 测试代码二:
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <dirent.h>

#define err_sys(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf("\nerrno:%d %s\n", errno, strerror(errno));\
    exit(EXIT_FAILURE);\
} while (0)


/* struct stat info */
// struct stat {
// dev_t st_dev; /* ID of device containing file */
// ino_t st_ino; /* inode number */
// mode_t st_mode; /* protection */
// nlink_t st_nlink; /* number of hard links */
// uid_t st_uid; /* user ID of owner */
// gid_t st_gid; /* group ID of owner */
// dev_t st_rdev; /* device ID (if special file) */
// off_t st_size; /* total size, in bytes */
// blksize_t st_blksize; /* blocksize for file system I/O */
// blkcnt_t st_blocks; /* number of 512B blocks allocated */
// time_t st_atime; /* time of last access */
// time_t st_mtime; /* time of last modification */
// time_t st_ctime; /* time of last status change */
// };


int
main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    struct stat sb;
    if (fstatat(AT_FDCWD, argv[1], &sb, AT_SYMLINK_NOFOLLOW) == -1) {
        err_sys("fstatat");
    }

    printf("File type: ");

    switch (sb.st_mode & S_IFMT) {
    case S_IFBLK: printf("block device\n"); break;
    case S_IFCHR: printf("character device\n"); break;
    case S_IFDIR: printf("directory\n"); break;
    case S_IFIFO: printf("FIFO/pipe\n"); break;
    case S_IFLNK: printf("symlink\n"); break;
    case S_IFREG: printf("regular file\n"); break;
    case S_IFSOCK: printf("socket\n"); break;
    default: printf("unknown?\n"); break;
    }

    printf("I-node number: %ld\n", (long) sb.st_ino);

    printf("Mode: %lo (octal)\n",
           (unsigned long) sb.st_mode);

    printf("Link count: %ld\n", (long) sb.st_nlink);
    printf("Ownership: UID=%ld GID=%ld\n",
           (long) sb.st_uid, (long) sb.st_gid);

    printf("Preferred I/O block size: %ld bytes\n",
           (long) sb.st_blksize);
    printf("File size: %lld bytes\n",
           (long long) sb.st_size);
    printf("Blocks allocated: %lld\n",
           (long long) sb.st_blocks);

    printf("Last status change: %s", ctime(&sb.st_ctime));
    printf("Last file access: %s", ctime(&sb.st_atime));
    printf("Last file modification: %s", ctime(&sb.st_mtime));

    exit(EXIT_SUCCESS);
}

result:
manjingliu@NGFW-DEV64 ~/apue/part_4 $ ./4_4 fstatat.tmp 
File type: regular file
I-node number: 13650320
Mode: 100755 (octal)
Link count: 1
Ownership: UID=1058 GID=1058
Preferred I/O block size: 4096 bytes
File size: 0 bytes
Blocks allocated: 0
Last status change: Tue Jul 17 15:04:20 2018
Last file access: Tue Jul 17 15:04:20 2018
Last file modification: Tue Jul 17 15:04:20 2018
manjingliu@NGFW-DEV64 ~/apue/part_4 $ ./4_4 stat.dir/fstatat.link 
File type: symlink
I-node number: 13650322
Mode: 120777 (octal)
Link count: 1
Ownership: UID=1058 GID=1058
Preferred I/O block size: 4096 bytes
File size: 38 bytes
Blocks allocated: 0
Last status change: Tue Jul 17 15:16:37 2018
Last file access: Tue Jul 17 15:16:37 2018
Last file modification: Tue Jul 17 15:16:37 2018
manjingliu@NGFW-DEV64 ~/apue/part_4 $ ./4_4 stat.dir/fstatat.tmp 
File type: regular file
I-node number: 13650317
Mode: 100644 (octal)
Link count: 1
Ownership: UID=1058 GID=1058
Preferred I/O block size: 4096 bytes
File size: 0 bytes
Blocks allocated: 0
Last status change: Tue Jul 17 14:38:09 2018
Last file access: Tue Jul 17 14:38:09 2018
Last file modification: Tue Jul 17 14:38:09 2018

文件类型

文件种类(按类型分类)
  • 普通文件、目录文件、块特殊文件、字符特殊文件、FIFO、socket文件、符号链接文件
  • 用于确定文件类型的宏(这些宏的参数都是stat结构中的st_mode)
    文件类型宏
  • 用于确定IPC类型的宏(这个在第15章来讨论)
    ipc宏

设置用户ID和设置组ID

与一个进程相关联的ID

进程相关的ID
* 使用stat命令可以查看一个文件的属性信息

manjingliu@NGFW-DEV64 ~/apue/part_4 $ stat stat.link 
  File: ‘stat.link’ -> ‘stat.tmp’
  Size: 8 Blocks: 0 IO Block: 4096 symbolic link
Device: 802h/2050d  Inode: 13650313 Links: 1
Access: (0777/lrwxrwxrwx) Uid: ( 1058/manjingliu) Gid: ( 1058/manjingliu)
Access: 2018-07-17 14:29:06.178981063 +0800
Modify: 2018-07-17 14:29:06.178981063 +0800
Change: 2018-07-17 14:29:06.178981063 +0800
 Birth: -
  • 实际用户ID和实际组 ID:标识我们是谁,取自口令文件中的登录项。在一个登录会话期间这些值并不改变,但是超级用户进程有方法改变它们。(第8章来讲)
  • 有效用户ID、有效组ID以及附属组ID决定了我们的文件访问权限
  • 保存的设置用户ID和保存的设置组ID在执行一个程序时包含了有效用户ID和有效组ID的副本。(第8章讨论)
    通常,有效用户ID等于实际用户ID,有效组ID等于实际组ID。但是文件的stat结构中保存了st_mode信息,可以对这个信息设置一个标志,这样在进程执行时,对这个文件的操作时,进程的有效用户ID变成文件的所有者ID(st_uid)。与此类似stat结构中的st_mode还可以设置另外一个标志,他可以让进程操作这个文件的时候,有效组ID设置成这个文件的组所有者ID(st_gid),在st_mode中这两位分别叫做设置用户ID位和设置组ID位。比如:如果一个文件的所有者是超级用户,而且设置了该文件的设置用户ID位,那么当该程序文件由一个进程执行时,该进程拥有超级权限。不管这个执行这个文件的进程的实际用户id是什么。如passwd命令,这个程序就设置了设置用户ID位
  • 获取文件的设置用户id位和设置组id位,测试代码如下:
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

#define err_sys(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf("\nerrno:%d %s\n", errno, strerror(errno));\
    exit(EXIT_FAILURE);\
} while (0)

#define PASSWD_PATH "/usr/bin/passwd"

/* struct stat info */
// struct stat {
// dev_t st_dev; /* ID of device containing file */
// ino_t st_ino; /* inode number */
// mode_t st_mode; /* protection */
// nlink_t st_nlink; /* number of hard links */
// uid_t st_uid; /* user ID of owner */
// gid_t st_gid; /* group ID of owner */
// dev_t st_rdev; /* device ID (if special file) */
// off_t st_size; /* total size, in bytes */
// blksize_t st_blksize; /* blocksize for file system I/O */
// blkcnt_t st_blocks; /* number of 512B blocks allocated */
// time_t st_atime; /* time of last access */
// time_t st_mtime; /* time of last modification */
// time_t st_ctime; /* time of last status change */
// };


int
main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    struct stat sb;
    if (stat(argv[1], &sb) == -1) {
        err_sys("stat");
        exit(EXIT_FAILURE);
    }

    printf("File type: ");

    switch (sb.st_mode & S_IFMT) {
    case S_IFBLK: printf("block device\n"); break;
    case S_IFCHR: printf("character device\n"); break;
    case S_IFDIR: printf("directory\n"); break;
    case S_IFIFO: printf("FIFO/pipe\n"); break;
    case S_IFLNK: printf("symlink\n"); break;
    case S_IFREG: printf("regular file\n"); break;
    case S_IFSOCK: printf("socket\n"); break;
    default: printf("unknown?\n"); break;
    }

    printf("I-node number: %ld\n", (long) sb.st_ino);

    printf("Mode: %lo (octal)\n",
           (unsigned long) sb.st_mode);

    printf("Link count: %ld\n", (long) sb.st_nlink);
    printf("Ownership: UID=%ld GID=%ld\n",
           (long) sb.st_uid, (long) sb.st_gid);

    printf("Preferred I/O block size: %ld bytes\n",
           (long) sb.st_blksize);
    printf("File size: %lld bytes\n",
           (long long) sb.st_size);
    printf("Blocks allocated: %lld\n",
           (long long) sb.st_blocks);

    printf("Last status change: %s", ctime(&sb.st_ctime));
    printf("Last file access: %s", ctime(&sb.st_atime));
    printf("Last file modification: %s", ctime(&sb.st_mtime));
    printf("set user-id on execution: %s\n", (sb.st_mode & S_ISUID) == S_ISUID ? "Yes" : "No");
    printf("set group-id on execution: %s\n",(sb.st_mode & S_ISGID) == S_ISGID ? "Yes" : "No");
    exit(EXIT_SUCCESS);

}
result:
[manjingliu@localhost part_4]$ ./4_1 /usr/bin/passwd 
File type: regular file
I-node number: 50774440
Mode: 104755 (octal)
Link count: 1
Ownership: UID=0 GID=0
Preferred I/O block size: 4096 bytes
File size: 27832 bytes
Blocks allocated: 56
Last status change: Wed Apr 25 22:45:22 2018
Last file access: Tue Jun 10 14:27:56 2014
Last file modification: Tue Jun 10 14:27:56 2014
set user-id on execution: Yes
set group-id on execution: No

[manjingliu@localhost part_4]$ ./4_1 /usr/sbin/ifconfig 
File type: regular file
I-node number: 325991
Mode: 100755 (octal)
Link count: 1
Ownership: UID=0 GID=0
Preferred I/O block size: 4096 bytes
File size: 82000 bytes
Blocks allocated: 168
Last status change: Wed Apr 25 22:44:38 2018
Last file access: Sat Jul 28 12:36:06 2018
Last file modification: Thu Aug 3 17:17:33 2017
set user-id on execution: No
set group-id on execution: No

文件访问权限

  • 所有的文件都有访问权限,以下为文件的9个访问权限位
    st_mode

新文件和目录的所有权

  • 创建文件的时候,文件的用户id为进程的有效用户id
  • 创建文件的时候,文件的组id,posix.1支持以下两种选择
    • 新文件的组id可以是进程的有效组id
    • 新文件的组id也可以是他所在目录的组id

函数access和faccess

access
* faccessat函数的flag参数可以设置AT_ACCESS,那么检查的时候是用调用进程的有效用户id而不是真实的id
* 函数测试代码:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#define err_sys(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf(", errno:%d %s\n", errno, strerror(errno));\
    /*exit(EXIT_FAILURE);*/\
} while (0)

#define PASSWD_PATH "/usr/bin/passwd"

int
main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    /* use access to test */
    if(access(argv[1], F_OK)==0)
        printf("File exist\n");
    else
        err_sys("access F_OK");
    if(access(argv[1], R_OK)==0)  
        printf("READ OK\n");
    else
        err_sys("access READ");

    if(access(argv[1], W_OK)==0)  
        printf("WRITE OK\n");
    else
        err_sys("access WRITE");
    if(access(argv[1], X_OK)==0)  
        printf("EXEC OK\n");
    else
        err_sys("access EXEC");

    /* use faccess to test */
    if(faccessat(AT_FDCWD, argv[1], F_OK, AT_EACCESS)==0)
        printf("File exist\n");
    else
        err_sys("access F_OK");
    if(faccessat(AT_FDCWD, argv[1], R_OK, AT_EACCESS)==0)  
        printf("READ OK\n");
    else
        err_sys("faccessat READ");

    if(faccessat(AT_FDCWD, argv[1], W_OK, AT_EACCESS)==0)  
        printf("WRITE OK\n");
    else
        err_sys("faccessat WRITE");
    if(faccessat(AT_FDCWD, argv[1], X_OK, AT_EACCESS)==0)  
        printf("EXEC OK\n");
    else
        err_sys("faccessat EXEC");

    exit(EXIT_SUCCESS);

}

result:
[root@localhost part_4]# ./4_2 /usr/bin/passwd 
File exist
READ OK
WRITE OK
EXEC OK
File exist
READ OK
WRITE OK
EXEC OK
[root@localhost part_4]# exit
exit
[manjingliu@localhost part_4]$ ./4_2 /usr/bin/passwd 
File exist
READ OK
access WRITE, errno:13 Permission denied
EXEC OK
File exist
READ OK
faccessat WRITE, errno:13 Permission denied
EXEC OK


[manjingliu@localhost part_4]$ su 
Password: 
[root@localhost part_4]# chown root:root 4_2
[root@localhost part_4]# chmod u+s 4_2
[root@localhost part_4]# exit
exit
[manjingliu@localhost part_4]$ ls -l 4_2
-rwsrwxr-x 1 root root 8840 Jul 29 21:22 4_2
[manjingliu@localhost part_4]$ ./4_2 /usr/bin/passwd 
File exist
READ OK
access WRITE, errno:13 Permission denied
EXEC OK
File exist
READ OK
WRITE OK
EXEC OK 

函数umask

umask
* 这个函数用于设置进程创建文件时候的文件权限的屏蔽位
* 测试代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#define err_sys(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf(", errno:%d %s\n", errno, strerror(errno));\
    /*exit(EXIT_FAILURE);*/\
} while (0)

#define RWRWRW (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
#define MASK (S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)

int
main(int argc, char *argv[])
{
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <filename1 <filename2>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    umask(0);
    if (creat(argv[1], RWRWRW) < 0)
        err_sys("creat %s", argv[1]);

    umask(MASK);
    if (creat(argv[2], RWRWRW) < 0)
        err_sys("creat %s", argv[2]);

    exit(EXIT_SUCCESS);

}

result:
[manjingliu@localhost part_4]$ umask 
0002
[manjingliu@localhost part_4]$ ./4_3 foo bar
[manjingliu@localhost part_4]$ ls -l foo bar
-rw------- 1 manjingliu manjingliu 0 Jul 29 21:39 bar
-rw-rw-rw- 1 manjingliu manjingliu 0 Jul 29 21:39 foo

chmod、fchmod和fchmodat

  • 忽略
  • 注意,chmod会清除两个位:
    • 当chmod使用普通用户修改普通文件的粘着位(S_ISVTX)时,没有超级权限,则粘着位关闭,即只有超级用户才能设置粘着位
    • 如果新文件的组id不等于进程的有效组id或者进程附属组中的一个(因为新文件可能是跟父目录的组id一致),而且进程没有超级权限,那么这个文件的设置组id会被关闭

粘着位


  • 只有目录才能设置粘着位
  • 只有对该目录有写权限,且满足一下3个条件之一的的进程用户,才能删除、移动、重命名这个目录下的文件
    • 拥有此文件
    • 拥有此目录
    • 是超级用户

/tmp和/var/tmp是设置粘着位的典型例子

猜你喜欢

转载自blog.csdn.net/u012570105/article/details/81103728