实验环境介绍
- 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
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章来讨论)
设置用户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个访问权限位
新文件和目录的所有权
- 创建文件的时候,文件的用户id为进程的有效用户id
- 创建文件的时候,文件的组id,posix.1支持以下两种选择
- 新文件的组id可以是进程的有效组id
- 新文件的组id也可以是他所在目录的组id
函数access和faccess
* 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
* 这个函数用于设置进程创建文件时候的文件权限的屏蔽位
* 测试代码如下:
#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是设置粘着位的典型例子