实验一、系统调用基础
一、实验题目
在第2.3节中,我们描述了一个复制一个文件内容的程序
到目标文件。这个程序的工作原理是首先提示用户输入
源文件和目标文件的名称。使用以下命令编写这个程序
Windows或POSIX API。确保包含所有必要的错误
检查,包括确保源文件存在。
一旦你正确地设计和测试了程序,如果你
使用支持它的系统,使用跟踪的实用程序运行程序
fopen 创建文件系统调用。Linux系统提供strace实用程序,Solaris和
Mac OS X系统使用dtrace命令。和Windows系统一样
如果不提供这些功能,您将不得不通过Windows进行跟踪
版本本程序使用调试器。
二、相关原理与知识
(完成实验所用到的相关原理与知识)
Linux 系统调用相关基础知识
Linux C 文件读写相关基础知识
strace的使用
三、实验过程
(清晰展示实际操作过程,相关截图及解释)
为了模拟cp命令,我们主要通过命令行来传递参数,对于参数数量不符合的输入则直接终止程序。
if (argc != 3)
{
puts("Usage: ./mycp source_file_path destination_file_path");
exit(0);
}
对于要被拷贝的源文件,比较常规的思路是逐字节读入,若是读到 EOF 则说明读取到了文件末尾;但是在 Linux 下我们可以直接使用 fstat() 函数将一个文件的所有相关信息记录到一个stat结构体中,通过其st_size成员直接获取其长度,之后就可以直接通过 read(fd, buf, st.st_size) 读入文件内容。
src_fd = open(argv[1], O_RDONLY);
if (src_fd == -1)
{
puts("Failed to open the source file!");
exit(-1);
}
printf("fd of src: %d\n", src_fd);
fstat(src_fd, &src_st); // get source file length
buf = (char*) malloc(sizeof(char) * src_st.st_size);
if (buf == NULL)
{
puts("Malloc error!");
exit(-1);
}
read(src_fd, buf, src_st.st_size);
写入文件则可以通过 fwrite 完成,相比起我们手动通过文件描述符对文件进行操作而言,由glibc封装的相关文件操作更为方便,这里便不再赘叙。需要注意的便是在程序结束时别忘了关闭对应的文件流。
fwrite(buf, sizeof(char), src_st.st_size, dst_file);
puts("Done.");
fclose(dst_file);
close(src_fd);
四、实验结果与分析
由图上我们可以看出在进入到我们的主函数main之前程序首先先通过 mmap 系统调用将ld与libc等文件都映射到该进程的内存空间中,并使用mprotect()函数修改各数据段的读写执行权限,这些操作按照笔者的推测应当是由操作系统来完成的
接下来才是我们的程序的执行流程,我们可以看到虽然我们使用的是open()函数来打开目标文件,但是其所使用的系统调用为openat(系统调用号257)而不是open(系统调用号3),这是由于我们所传入的路径为相对路径而非绝对路径的原因,对于绝对路径openat会退化为open,不过并非本篇重点这里暂且不赘叙;随后我们的程序通过fstat系统调用获取到文件相关信息
接下来我们的程序使用write系统调用向stdout(文件描述符1)写入内容,在这里我们可以看出 printf 内部会真正用到的系统调用为write,且传递给系统调用的字符串为经过参数代换后的格式化字符串。
接下来我们可以看到,在fopen()函数创建文件时不仅会使用 openat 系统调用创建文件,还会使用fstat系统调用获取文件的相关信息;在这里笔者的程序虽然设定是先写入文件再输出 ”Done.” 字符串,但是从strace的结果来看似乎并非如此,笔者推测是由编译器将这个流程进行了优化。
最后便是关闭文件流,在这里虽然笔者分别使用了 “close() 关闭文件描述符”与“fclose()关闭FILE指针”这两种操作,但是我们不难看出其背后所使用的都是“通过close 系统调用关闭文件
描述符”这一方法
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论