|
Linux 下几个文件操作命令的代码实现(二)
|
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 系统调用,这样就不会出现上述的问题了。
mkdir 命令的实现 mkdir 命令的模拟实现 再让我们来看看 mkdir 的实现。 完整的代码如下: 清单 3. mkdir 实现代码
|
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
int main(int argc, char *argv[]){
int rt;
if( (rt = mkdir (argv[1],10705)) == -1 ){
fprintf(stderr,"cannot mkdir");
}
return 0;
}
|
这段代码也比较简单,我这里就不逐行解释了,主要说以下几点: 首先 mkdir 函数是定义于 <sys/stat.h> 和 <sys/types.h> 头文件之中的。 而 fprintf 函数是位于 <stdio.h> 文件之中的。 mkdir 的函数原型如下: | int mkdir(const char *pathname, mode_t mode);
|
mode 声明为 mode_t 类型。 那么 mode_t 数据类型是什么数据类型,应该从哪个文件去查看它的定义呢? mode_t 数据类型究竟是什么类型 让我们逐步查找一下。 首先从文件 /usr/include/sys/stat.h 中找到 mode_t 类型 /usr/include/sys/stat.h -> typedef __mode_t mode_t; 说明 mode_t 只是对 __mode_t 的一种定义。 然后从 /usr/include/bits/types.h 中找到 __mode_t 类型 /usr/include/bits/types.h -> __STD_TYPE __MODE_T_TYPE __mode_t; 说明 __mode_t 也只是对 __MODE_T_TYPE 的一种定义。 /usr/include/bits/typesizes.h -> #define __MODE_T_TYPE __U32_TYPE 说明 __MODE_T_TYPE 是对 __U32_TYPE 的一种定义。 /usr/include/bits/types.h -> #define __U32_TYPE unsigned int 最后 __U32_TYPE 是一种无符号的整数的定义。 从上述推导可以看出,mode_t 实际上也就是一种无符号整数。 另外如下结构 struct stat 定义中的 st_mode 成员变量也是使用的 mode_t 类型的变量。 从 man 2 stat 中可以找到结构 struct stat 的定义,如下: | 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 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 */
};
|
该结构也是我们在后面的 tac 命令实现中需要用到的结构体。我们需要用到结构体中的 st_size 成员,该成员反映了被读取的文件描述符对应的文件的大小。
tac 命令的实现 tac 命令的模拟实现 tac 命令主要用来以倒序的方式显示一个文本文件的内容,也就是先显示最后一行的内容,最后显示第一行的内容。代码如下: 清单 4. tac 命令实现代码
|
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#define SIZE 1000001
#define NLINE '\n'
int main(int argc , char *argv[]){
char buf[SIZE];
char *p1,*p2,*p3,*p4;
struct stat *fp;
int fd;
fp=(struct stat *)malloc(sizeof(struct stat));
if(argc != 2){
fprintf(stderr,"input error %s \n");
exit(1);
}
if( (fd=open(argv[1],O_RDONLY)) == -1 ){
fpri |
|