信息安全系统设计基础第十周学习总结
第十章 系统级I/O
第七节 I/O重定向
I/O重定向操作符: >
ls > foo.txt
这句代码的含义就是使外壳加载和执行ls程序,并且将标准输出重定向到磁盘文件foo.txt。
I/O重定向函数: dup2
返回值:成功返回描述符,错误返回-1
这个函数执行的操作是,拷贝描述符表表项oldfd,覆盖描述表表项newfd,如果后者被打开,则在拷贝前关闭它。
第八节 标准I/O
1.标准I/O库:
ANSI C定义了一组高级输入输出函数,称为标准I/O库,包含:
- fopen、fclose,打开和关闭文件
- fread、fwrite,读和写字节
- fgets、fputs,读和写字符串
- scanf、printf,复杂的格式化的I/O函数
2.流——类型为FILE的流是对文件描述符和流缓冲区的抽象
标准I/O库将一个打开的文件模型化为一个流。
每个ANSI C程序开始的时候都有三个打开的流:stdin、stdout、stderr,对应于标准输入、标准输出和标准错误 。
第九节 套接字
网络套接字上最好不要使用标准I/O函数,而是使用RIO函数,原因:
如果没有清楚缓存区,输入函数后面不能接输出函数,输出函数后面也不能接输入函数,而对套接字使用lseek是非法的,打开两个流有很麻烦,所以!在网络套接字上不要使用标准I/O函数来进行输入和输出!
错误处理
附录A中主要讲了这本书中的错误处理方式,有一个方法——错误处理包装函数,这个思想很有意思,相当于给基本函数再套上一层皮,然后run这个皮,发现了错误就终止,完全正确的话就跟没有这层皮一样。
1.错误处理风格
(1)Unix风格
遇到错误后返回-1,并且将全局变量errno设置为指明错误原因的错误代码;
如果成功完成,就返回有用的结果。
(2)Posix风格
返回0表示成功,返回非0表示失败;
有用的结果在传进来的函数参数中。
(3)DNS风格
有两个函数,gethostbyname和gethostbyaddr,失败时返回NULL指针,并设置全局变量h_errno。
2.错误处理包装函数
Unix风格
成功时返回void,返回错误时包装函数打印一条信息,然后退出。
Posix风格
成功时返回void,错误返回码中不会包含有用的结果。
DNS风格
参考资料
1.《深入理解计算机系统》
实践代码
stdio.h 标准输入输出
stdlib.h C标准函数库
unistd.h Unix类系统定义符号常量
fcntl.h 定义了很多宏和open,fcntl函数原型
sys/types.h 基本系统数据类型
dirent.h unix类目录操作的头文件,包含了许多UNIX系统服务的函数原型,例如opendir函数、readdir函数。
termios.h 在Posix规范中定义的标准接口
cp
if ((in_fd = open(argv[1], O_RDONLY)) == -1)
oops("Cannot open ", argv[1]);
if ((out_fd = creat(argv[2], COPYMODE)) == -1)
oops("Cannot creat", argv[2]);
while ((n_chars = read(in_fd, buf, BUFFERSIZE)) > 0)
if (write(out_fd, buf, n_chars) != n_chars)
oops("Write error to ", argv[2]);
if (n_chars == -1)
oops("Read error from ", argv[1]);
cp的参数有两个,分别是要复制的文件,和目的目录,检查cp的第一个参数,即要复制的文件,用open打开,in_fd为open返回的描述符,如果返回-1,代表打开失败,提示错误。检查cp的第二个参数,复制的目的地址,用create在目的地址创建新文件,out_fd为open返回的描述符,如果返回-1,代表创建失败,提示错误。cp指令的动作就是读取一个文件的内容到存储器,在新的地址创建空白文件,再从存储器将内容写入新文件。
ls(1)
void do_ls( char dirname[] )
{
DIR *dir_ptr;
struct dirent *direntp;
if ( ( dir_ptr = opendir( dirname ) ) == NULL )
fprintf(stderr,"ls1: cannot open %s\n", dirname);
else
{
while ( ( direntp = readdir( dir_ptr ) ) != NULL )
printf("%s\n", direntp->d_name );
closedir(dir_ptr);
}
}
Ls函数打开一个文件夹*dir,然后将其中的其中包含的文件名输出。不输入文件夹名字时默认为当前文件夹。
who
这个函数是,从UTMP_FILE文件中读取想要的信息到存储器中,然后再用标准输出函数打印到屏幕上,最后关闭文件。
echostate 、setecho
这个代码是用来检查命令行中的提示符是否显示的,如果显示,输入的命令都可见,不显示则表示输入的命令不可见,结合setecho代码一起。
info.c_lflag |= ECHO ;/*打开提示符*/
info.c_lflag &= ~ECHO ;/*隐藏提示符*/
fileinfo
这个功能用来实现显示文件信息,建立了一个stat数据结构。
void show_stat_info(char *fname, struct stat *buf)
{
printf(" mode: %o\n", buf->st_mode);
printf(" links: %d\n", buf->st_nlink);
printf(" user: %d\n", buf->st_uid);
printf(" group: %d\n", buf->st_gid);
printf(" size: %d\n", (int)buf->st_size);
printf("modtime: %d\n", (int)buf->st_mtime);
printf(" name: %s\n", fname );
}
filesize
用st_size成员来计算文件的字节数大小。
spwd
void inum_to_name(ino_t inode_to_find , char *namebuf, int buflen)
{
DIR *dir_ptr;
struct dirent *direntp;
dir_ptr = opendir( "." );
if ( dir_ptr == NULL ){
perror( "." );
exit(1);
}
while ( ( direntp = readdir( dir_ptr ) ) != NULL )
if ( direntp->d_ino == inode_to_find )
{
strncpy( namebuf, direntp->d_name, buflen);
namebuf[buflen-1] = '\0';
closedir( dir_ptr );
return;
}
fprintf(stderr, "error looking for inum %d\n", (int) inode_to_find);
exit(1);
}
列出当前所在目录
testioctl
列出文件的行数与列数。
printf("%d rows %d columns\n", size.ws_row, size.ws_col);
return 0;
编译完成后的文件列表:
a
a.out
cp1.c
cp1
echostate.c
error
fileinfo.c
fileinfo
filesize.c
filesize
foo.txt
ls1
ls1.c
ls2
ls2.c
setecho.c
spwd
spwd.c
test
testioctl.c
who1.c
who1
who2.c
who2