用C语言实现Linux 下几个文件操作命令(1)(2)
rm 命令的实现
rm 命令的模拟实现
rm 命令主要是用来删除一个文件。
该命令的实现代码如下:
清单 2. rm 命令代码
#include #include #include int main(int argc , char * argv[]) { int rt; if(argc != 2){ exit(2); }else{ if((rt = unlink(argv[1])) != 0){ fprintf(stderr,"error."); exit(3); } } return 0; }
其中程序的关键是 unlink 系统调用,unlink 函数原型包含在 头文件里面。
用 strace 来跟踪命令
我们从这个程序的创建过程来分析这个程序。
这个命令的模拟程序是怎么写出来的呢?
首先,我们可以在机器上 touch test 建立一个 test 文件,然后调用 strace rm test 命令来查看 rm 命令具体使用了那些系统调用。
通过查看,我们看到主要使用的系统调用如下:
[root@localhost aa]# strace rm test execve("/bin/rm", ["rm", "test"], [/* 24 vars */]) = 0 brk(0) = 0xcc66000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2aff83ffb000 uname({sys="Linux", node="localhost.localdomain", ...}) = 0 ... ... lstat("test", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0 stat("test", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0 geteuid() = 0 getegid() = 0 getuid() = 0 getgid() = 0 access("test", W_OK) = 0 unlink("test") = 0 close(1) = 0 exit_group(0) = ?
我们可以看到起主要作用的就是 unlink(“test”) 这个系统调用。
让我们来分析一下这些输出的含义:
·首先第一行 execve 系统调用。该系统调用执行参数“/bin/rm”中的程序(以 #! 开头的可执行脚本也可以),后面第一个方括号中表示执行的参数,第二个方括号中表示执行的环境变量。
·接下来的 brk 和 mmap 命令,主要是用来给可执行命令分配内存空间。
·后面的 lstat 系统调用用来确定文件的 mode 信息,包括文件的类型和权限,文件大小等等。
·然后 access 系统调用检查当前用户进程对于 test 文件的写入访问权限。这里返回值为 0 也就是说进程对于 test 文件有写入的权限。
·最后调用 unlink 系统调用删除文件。
这里如果我们建立一个目录 test1,然后用 rm test1 去删除这个目录会有什么结果呢?
我们看到有如下输出:
rm: cannot remove `test1': Is a directory
这时我们用 strace 命令来追踪一下,发现输出主要是如下不同。
unlink("test") = -1 EISDIR (Is a directory)
这里说明了删除不掉的原因是 unlink 系统调用报错,unlink 它认为 test 是一个目录,不予处理。
那么怎么删除一个目录呢?应该是用 rmdir 系统调用,这样就不会出现上述的问题了。
评论暂时关闭