一、文件
linux宗旨:一切皆文件
1、文件类型
d 目录
l 符号链接(软硬连接)
s 套接字文件
b 块设备文件
c 字符设备文件
p 命名管道文件
- 普通文件,或者更准确的说,不属于以上几种类型的文件
2、文件权限
r 读权限
w 写权限
x 执行权限
3、权限设置
1、查看用户列表
cat /etc/passwd
通常在Linux系统中,用户的关键信息被存放在系统的/etc/passwd文件中,系统的每一个合法用户账号对应于该文件中的一行记录。这行记录定义了每个用户账号的属性。
onlylove:x:1000:1000:lq,,,:/home/onlylove:/bin/bash
每一行用户记录的各个数据段用“:”分隔,分别定义了用户的各方面属性。各个字段的顺序和含义如下:
注册名:口令:用户标识号:组标识号:用户名:用户主目录:命令解释程序
1、注册名
2、口令
3、用户标识号
是Linux系统中惟一的用户标识,用于区别不同的用户,别称UID。
4、组标识号
组标识号与用户标识号类似,也是一个整数,被系统内部用来标识组。别称GID。
5、用户名
6、用户主目录
7、命令解释程序
2、查看用户组列表
cat /etc/group
将用户分组是Linux系统中对用户进行管理及控制访问权限的一种手段。每个用户都属于某个用户组;一个组中可以有多个用户,一个用户也可以属于不 同的组。
onlylove:x:1000:
sambashare:x:132:onlylove
用户组的所有信息都存放在/etc/group文件中。此文件的格式是由冒号(:)隔开若干个字段,这些字段具体如下:
组名:口令:组标识号:组内用户列表
1、组名
2、口令
口令字段存放的是用户组加密后的口令字。一般Linux系统的用户组都没有口令,即这个字段一般为空,或者是*。
x表示没有设置密码
3、组标识号
组标识号与用户标识号类似,也是一个整数,被系统内部用来标识组。别称GID。
4、组内用户列表
3、用户密码文件
cat /etc/shadow
前面介绍了 /etc/passwd 文件,由于该文件允许所有用户读取,易导致用户密码泄露,因此 Linux 系统将用户的密码信息从 /etc/passwd 文件中分离出来,并单独放到了此文件中。
/etc/shadow 文件只有 root 用户拥有读权限,其他用户没有任何权限,这样就保证了用户密码的安全性。
root:$6$gLGU8blJmh.YQjIt$CiCtocxXn6E5lyHh64oHCON/ntfSeI/cwHxVQeH07ae9cQ0m83WAG6NnzIAbDJjDOOxloyApqrU1fY1N4Zw8s.:18886:0:99999:7:::
onlylove:$1$Gdh.2E0J$CSARuBpEkHVu/T753H452.:18812:0:99999:7:::
文件中每行代表一个用户,同样使用 “:” 作为分隔符,不同之处在于,每行用户信息被划分为 9 个字段。每个字段的含义如下:
用户名:加密密码:最后一次修改时间:最小修改时间间隔:密码有效期:密码需要变更前的警告天数:密码过期后的宽限时间:账号失效时间:保留字段
1、用户名
2、加密密码
这里保存的是真正加密的密码。目前 Linux 的密码采用的是 SHA512 散列加密算法,原来采用的是 MD5 或 DES 加密算法。SHA512 散列加密算法的加密等级更高,也更加安全。
注意,这串密码产生的乱码不能手工修改,如果手工修改,系统将无法识别密码,导致密码失效。很多软件透过这个功能,在密码串前加上 “!”、"*" 或 “x” 使密码暂时失效。
所有伪用户的密码都是 “!!” 或 “*”,代表没有密码是不能登录的。当然,新创建的用户如果不设定密码,那么它的密码项也是 “!!”,代表这个用户没有密码,不能登录。
3、最后一次修改时间
Linux 计算日期的时间是以 1970 年 1 月 1 日作为 1 不断累加得到的时间
4、最小时间间隔
5、密码有效期
该字段的默认值为 99999,也就是 273 年,可认为是永久生效。
6、密码需要变更前的警告天数
7、密码过期后的宽限天数
8、账号失效时间
9、保留
二、文件描述符
一个非负整数,通常是小整数,来指代打开的文件设备。
文件描述符用以表示所有类型的已打开文件,包括管道(pipe)、FIFO、socket、终端、设备和普通文件。
针对每个进程,文件描述符都自成一套。
标准文件描述符:
文件描述符 | 用途 | POSIX名称 | stdio流 |
---|
0 | 标准输入 | STDIN_FILENO | stdin | 1 | 标准输出 | STDOUT_FILENO | stdout | 2 | 标准错误 | STDERR_FILENO | stderr |
三、系统调用接口
接口 | 作用 |
---|
fd = open(pathname, flags, mode) | 打开pathname所标识的文件,并返回文件描述符。 | numread = read(fd, buffer, count) | 读取打开的文件,并返回读取字节数。 | numwritten = write(fd, buffer, count) | 向打开文件写入数据,并返回写入数据的字节数 | status = close(fd) | 释放文件描述符fd及相关资源 |
四、接口分析
1、open
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
1、参数
1、pathname
要打开的文件由参数 pathname 来标识。如果 pathname 是一符号链接,会对其进行解引用。
2、flags
flags 为位掩码,用于指定文件的访问模式。
flags 参数值介绍
标志 | 用途 |
---|
O_RDONLY | 以只读方式打开 | O_WRONLY | 以只写方式打开 | O_RDWR | 以读写方式打开 | O_CLOEXEC | 设置 close-on-exec 标志 | O_CREAT | 若文件不存在则创建 | O_DIRECT | 无缓存的输入/输出 | O_DIRECTORY | 如果 pathname 不是目录,则失败 | O_EXCL | 结合 O_CREAT 参数使用,专门用于创建文件 | O_LARGEFILE | 在 32 位系统中使用此标志打开大文件 | O_NOATIME | 调用 read() 时,不修改文件最近访问时间 | O_NOCTTY | 不要让 pathname(所指向的终端设备)成为控制终端 | O_NOFOLLOW | 对符号链接不予解引用 | O_TRUNC | 截断已有文件,使其长度为零 | O_APPEND | 总在文件尾部追加数据 | O_ASYNC | 当I/O操作可行时,产生信号(signal)通知进程 | O_DSYNC | 提供同步的I/O数据完整性 | O_NONBLOCK | 以非阻塞方式打开 | O_SYNC | 以同步方式写入文件 |
3、mode
创建文件时指定创建文件的权限。
创建新文件的访问权限不仅仅依赖参数 mode,而且受到进程的 umask 值和父目录的默认访问控制列表影响。
标志 | 用途 |
---|
S_IRUSR | 所有者拥有读权限 | S_IWUSR | 所有者拥有写权限 | S_IXUSR | 所有者拥有执行权限 | S_IRGRP | 群组拥有读权限 | S_IWGRP | 群组拥有写权限 | S_IXGRP | 群组拥有执行权限 | S_IROTH | 其他用户拥有读权限 | S_IWOTH | 其他用户拥有写权限 | S_IXOTH | 其他用户拥有执行权限 |
2、返回值
如果调用成功,open() 将返回一文件描述符,用于在后续函数调用中指代该文件。
如果调用失败,则返回 -1,并将 errno 置为相应的错误标志。 函数错误:
标志 | 用途 |
---|
EACCES | 文件权限不允许调用进程以 flags 参数指定方式打开文件 | EISDIR | 所指文件属于目录,而调用者企图打开该文件进行写操作 | EMFILE | 进程已打开的文件描述符数量达到了进程资源限制所设定的上限 | ENFILE | 文件打开数量已达到系统允许的上限 | ENOENT | 1、文件不存在且未指定O_CREAT标志 2、指定O_CREAT标志,但 pathname 参数所指定路径的目录不存在 | EROFS | 指定的文件隶属于只读文件系统,而调用者企图以写方式打开文件 | ETXTBSY | 指定的文件为可执行文件,且正在运行 |
2、creat()
在早期的 UNIX 实现中,open() 只有两个参数,无法创建新文件,而是使用 creat() 系统调用来创建一个新文件。
#include <fcntl.h>
int creat(const char *pathname, mode_t mode);
creat() 系统调用根据 pathname 参数创建并打开一个文件,若文件已存在,则文件打开,并清空文件内容,将其长度清0。
creat() 返回一个文件描述符,供后续系统调用使用。
creat() 系统调用等价于如下 open() 调用:
fd = open(pathname,O_WRONLY|O_CREAT|O_TRUNC,mode);
3、read()
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
1、参数
1、fd
open() 系统调用返回的文件描述符。
2、buf
保存读取数据缓存。
3、count
size_t数据类型属于无符号整数类型。
指示buf缓存至少还有多少字节。
2、返回值
ssize_t数据类型属于有符号整数类型
read() 调用成功,将返回实际读取的字节数,如果遇到文件结束(EOF)则返回0。
read() 调用失败,则返回 -1。
4、write()
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
1、参数
1、fd
open() 系统调用返回的文件描述符。
2、buf
保存要写入数据缓存。
3、count
size_t数据类型属于无符号整数类型。
要写入的字节。
2、返回值
ssize_t数据类型属于有符号整数类型
write() 调用成功,将返回实际写入的字节数。
write() 调用失败,则返回 -1。
5、close()
#include <unistd.h>
int close(int fd);
1、参数
1、fd
open() 系统调用返回的文件描述符。
2、返回值
close() 调用成功,将返回 0。
close() 调用失败,则返回 -1。
6、lseek()
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
1、参数
1、fd
open() 系统调用返回的文件描述符。
2、offset
offset 指定一个以字节为单位的数值。
3、whence
whence 表明应参照那个基点来解释 offset 参数。
标志 | 用途 |
---|
SEEK_SET | 从文件头部起始点开始的 offset 个字节 | SEEK_CUR | 从文件当前偏移量开始的 offset 个字节 | SEEK_END | 从文件尾部开始的 offset 个字节(offset参数从文件最后一个字节之后下一个字节算起) |
2、返回值
返回新的文件偏移量。
3、备注
lseek() 并不适用所有类型的文件,不允许将lseek() 应用于管道、FIFO、socket或者终端。
7、文件空洞
文件偏移量已经跨过文件结尾,从文件结尾后到新写入数据间的这段空间被称为文件空洞。调用 read() 读取将返回0。
8、ioctl()
#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);
ioctl() 系统调用为执行文件和设备操作提供一种多用途机制。
1、参数
1、fd
open() 系统调用返回的文件描述符。
2、request
指定在 fd 上执行的控制操作。
2、返回值
五、示例
1、实现一个简版cp命令
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#ifndef BUF_SIZE
#define BUF_SIZE 1024
#endif
int main(int argc,char *argv[])
{
int input_fd,output_fd;
ssize_t read_num;
char buf[BUF_SIZE];
if(argc != 3 || strcmp(argv[1],"--help") == 0)
printf("%s old-file new-file\n",argv[1]);
input_fd = open(argv[1],O_RDONLY);
if(input_fd == -1){
printf("open file %s \n",argv[1]);
return 1;
}
output_fd = open(argv[2],O_CREAT|O_WRONLY|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
if(output_fd == -1){
printf("open file %s \n",argv[2]);
close(input_fd);
return 1;
}
while((read_num = read(input_fd,buf,BUF_SIZE)) > 0)
if(write(output_fd,buf,read_num) != read_num)
printf("couldn't write whole buffer\n");
if(close(input_fd) == -1)
printf("close inpput file\n");
if(close(output_fd) == -1)
printf("close output file\n");
return 0;
}
TAR := copy
OBJ := copy.o
SOU := copy.c
CC := gcc
$(TAR): $(OBJ)
$(CC) $(OBJ) -o $(TAR)
#$(OBJ):$(SOU)
#%.o:%.c
# $(CC) -c %.c -o %.o
.PHONY : clean
clean:
rm $(OBJ) $(TAR)
测试:
2、lseek()和read()、write()协作使用
程序说明:第一个参数为要打开的文件名称,余下参数指定在文件上执行的输入输出操作。每个表示操作的参数都以一个字母开头,紧跟以相关值(中间无空格分隔)。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
int fd,ap,j;
size_t len = 0;
off_t offset = 0;
char *endptr = NULL,*buf = NULL;
ssize_t read_num = 0,write_num = 0;
if(argc < 3 || strcmp(argv[1],"--help") == 0)
printf("%s file {r<length>|R<length>|w<string>|s<offset>}……\n",argv[0]);
fd = open(argv[1],O_RDWR|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
if(fd == -1){
printf("open file\n");
return 1;
}
for(ap=2;ap<argc;ap++){
switch(argv[ap][0]){
case 'r':
case 'R':
len = strtol(&argv[ap][1],&endptr,0);
buf = malloc(len);
if(buf == NULL){
printf("R - malloc\n");
return 1;
}
read_num = read(fd,buf,len);
if(read_num == -1){
printf("R - read\n");
return 1;
}
if(read_num == 0){
printf("%s end-of-file\n",argv[ap]);
}else{
printf("%s: ",argv[ap]);
for(j=0;j<read_num;j++){
if(argv[ap][0] == 'r')
printf("%c ",isprint(buf[j]) ? buf[j] : '?');
else
printf("%02x ",(unsigned int)buf[j]);
}
printf("\n");
}
break;
case 'w':
write_num = write(fd,&argv[ap][1],strlen(&argv[ap][1]));
if(write_num == -1){
printf("w - write\n");
return 1;
}
printf("%s: worte %ld bytes\n",argv[ap],write_num);
break;
case 's':
offset = strtol(&argv[ap][1],&endptr,0);
if(lseek(fd,offset,SEEK_SET) == -1){
printf("s - lseek\n");
return 1;
}
printf("%s: seek succeede\n",argv[ap]);
break;
default:
printf("Argument must start whit [rRws]: %s\n",argv[ap]);
break;
}
}
return 0;
}
TAR := seek_io
OBJ := seek_io.o
SOU := seek_io.c
CC := gcc
$(TAR): $(OBJ)
$(CC) $(OBJ) -o $(TAR)
#$(OBJ):$(SOU)
#%.o:%.c
# $(CC) -c %.c -o %.o
.PHONY : clean
clean:
rm $(OBJ) $(TAR)
测试:
|