unix基础编程(3)--文件和目录

文件和目录

stat, fstat, fstatat 和 lstat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
SYNOPSIS
#include <fcntl.h> /* Definition of AT_* constants */
#include <sys/stat.h>
int fstatat(int dirfd, const char *pathname, struct stat *buf,
int flags);

关于结构 stat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 filesystem 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 */
};

文件类型

  • 1 普通文件
  • 2 目录文件
  • 3 块特殊文件(block special file).这种类型的文件提供对设备(如磁带)带缓冲的访问,每次访问以固定长度为单位进行.
  • 4 字符特殊文件.这种类型的文件提供对设备不带缓冲的访问,每次访问长度是可变的.
  • 5 FIFO 这种类型的文件用于进程间通信.
  • 6 socket 用于进程间网络通信
  • 7 符号链接

文件类型信息包含在stat结构的st_mode

文件类型
S_ISREG() 普通文件
S_ISDIR() 目录文件
S_ISCHR() 字符特殊文件
S_ISBLK() 块特殊文件
S_ISFIFO() 管道文件
S_ISLINK() 符号链接
S_ISSOCK() 套接字

POSIX.1允许实现将进程间通信(IPC)对象说明文件,使用stat结构中确定IPC对象类型,参数是指向stat结构的指针.
| 宏 | 对象类型 |
| ————- |:————-:|
| S_TYPEISMQ() | 消息队列 |
| S_TYPEISEM() | 信号量 |
| S_TYPEISSHM() | 共享存储对象 |

设置用户ID与组ID

一个进程相关联的ID有6个或者更多

| S_TYPEISMQ() | 消息队列 |
| S_TYPEISEM() | 信号量 |
| S_TYPEISSHM() | 共享存储对象 |

设置用户ID和设置组ID

实际用户ID
实际组ID

有效用户ID
有效组ID
附属组ID

保存的设置用户ID
保存的设置组ID 由exec函数保存

  • 实际用户ID和实际组ID标识我们究竟是谁,这两个字段在登录时,取自哦令文件

  • 有效用户,有效组ID以及附属组ID决定了我们的文件访问权限

  • 保存的设置用户ID和保存的设置组ID在执行一个程序时,包含了一个有效用户ID和有效组ID的副本.

每一个文件有一个所有者和组所有者,所有者由stat结构中的st_uid指定,组所有者有st_git指定.

当执行一个程序文件时,进程的有效用户ID通常就是实际用户ID,有效组ID是实际组ID,但是可以在文件模式字std_mode中设置一个特殊标志,其含义是”当执行文件时,将进程的有效用户ID设置为文件所有者用户ID”,与此类似,文件模式字中可以设置的另一位,它将执行文件的有效组ID设置未文件的组所有者ID.
可以使用S_ISUIDS_ISGID测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main(int argc, char **argv) {
int i;
struct stat buf;
char *ptr;
for(i = 1; i < argc; i++) {
printf("%s, ", argv[i]);
if (lstat(argv[i], &buf) < 0) {
printf("lstat error\n");
continue;
}
if (S_ISREG(buf.st_mode)) {
ptr = "regular";
} else if (S_ISDIR(buf.st_mode)) {
ptr = "dirctory";
} else if (S_ISCHR(buf.st_mode)) {
ptr = "char special";
} else if(S_ISBLK(buf.st_mode)) {
ptr = "kuai te shu";
} else if(S_ISFIFO(buf.st_mode)) {
ptr = "FIFO";
} else if (S_ISLNK(buf.st_mode)) {
ptr = "Link";
} else if(S_ISSOCK(buf.st_mode)) {
ptr = "SOCKET";
} else {
ptr = "UNKONWN";
}
if (buf.st_mode & S_ISUID) {
printf("suid\n");
}
if (buf.st_mode & S_ISGID) {
printf("sgid\n");
}
printf("%s\n", ptr);
}
exit(0);
}

output:

1
2
3
./a.out /usr/bin/passwd
/usr/bin/passwd, suid
regular

文件访问权限

st_mode也包含了文件的访问权限.
S_IRUSR 用户读
S_IWUSR 用户写
S_IXUSR 用户执行

S_IRGRP 组读
S_IWGRP 组写
S_IXGRP 组执行

S_IROTH 其他读
S_IWOTH 其他写
S_IXOTH 其他执行

规则一,当我们用名字打开任一类型的文件时,对名字中包含的每一个目录,包括...都应该具有执行权限,目录的执行权限对应于搜索位.
对目录而言,读权限和执行权限的区别:
读权限允许我们读目录,获取该目录中所有文件列表名.
当一个目录是我们要访问的文件路径名的一个组成部分时,对该目录的执行权限使我们可以通过该目录.

1
2
3
4
5
>ll /var/log -d
drwxrwxr-x 20 root syslog 4096 7月 6 09:05 /var/log
sudo chmod 774 /var/log
>ll /var/log -d
drwxrwxr-- 20 root syslog 4096 7月 6 09:05 /var/log

结果:

1
2
3
4
ll /var/log/dmesg
ls: cannot access /var/log/dmesg: Permission denied
/var >cd log
cd: permission denied: log

可以ls,但是不能cd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
extern int errno ;
int main(int argc, char** argv) {
if (argc < 2) {
printf("usage a.out <dirname>\n");
exit(-1);
}
DIR *dptr = NULL;
struct dirent *entry;
if ((dptr = opendir(argv[1])) == NULL) {
perror("Error:");
} else {
while (entry = readdir(dptr)) {
printf("%s\n", entry->d_name);
}
closedir(dptr);
}
return 0;
}

因为对其他人都取消了执行权限,所以其他人无法通过该目录了.

为了在目录中创建一个新文件,需要有写和执行的权限

为了删除一个现有文件文件,必须对包含该文件的目录有写权限和执行权限,对该文件本身则不需要读写权限

如果用7个exec函数中的任何一个执行文件,必须对该文件具有执行权限,并且该文件为普通文件.

新文件和目录的所有权

新文件的用户ID设置为进程的有效用户ID,
新文件的组ID:可以是进程的有效组ID;也可以是所在目录的组ID.

在ubuntu下是哪种情况?
使用sudo,改变进程的有效用户,发现组ID是进程的有效组ID.
在Mac里面则是所在目录的组ID

函数accessfaccessat

open函数打开一个文件时,内核以进程的有效用户ID和有效组ID为基础进行访问权限测试.有时候,进程也希望按照实际用户ID和实际组ID来测试其访问能力.可以使用这两个函数.

1
2
3
4
SYNOPSIS
#include <unistd.h>
int access(const char *pathname, int mode);

umask函数

为一个进程设置文件模式创建屏蔽字,在进程创建一个新文件或者目录.参数是设置的umask值,返回的是之前的umask值.

1
2
3
4
5
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
mode_t umask(mode_t mask);

函数chmod, fchmodfchmodat

1
2
3
4
5
SYNOPSIS
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
int fchmod(int fd, mode_t mode);

为了能够改变一个文件的权限位,进车个的有效用户ID必须等于文件的所有者ID.

粘着位(sticky bit)

允许目录设置,如果对一个目录设置了粘着位,只有对该目录具有写权限的用户并且满足下列条件之一,才能删除或者重命名该目录下的文件.

  • 拥有此文件
  • 拥有此目录
  • 是超级用户

/tmp/var/tmp设置了粘着位,任何用户都可以创建目录,但其他人无法删除.

chown,fchown,fchownat, lchown

文件长度

其他一些操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argv, char ** args) {
if(argv > 1) {
const char * FILENAME = args[1];
int r_fd = open(FILENAME, O_RDWR);
printf("%d\n", r_fd);
off_t offeset = 2;
int ft_res = ftruncate(r_fd, offeset);
close(r_fd);
} else {
printf("%s <filename>\n", args[0]);
}
return 0;
}

fstat 获取文件的状态
stat(const char *path, struct stat *buf)
fstat(int fd, struct stat *buf)
lstat(const char *path, struct *buf) //链接文件
返回:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 */
};

坚持技术分享,您的支持将鼓励我继续创作!