Linux中的fopen()和open()是什么?


在Linux操作系统中,fopen()和open()函数的主要区别在于,open()函数是一个低级调用,而fopen()函数在被调用时会在后台简单地调用open()函数,并直接返回一个文件指针。

open()函数的调用包括调用其他几个函数,整个过程的行为在下面作为一个参考,以便更好地理解open()函数。

考虑以下代码:

int sys_open(const char *filename, int flags, int mode) {
   char *tmp = getname(filename);
   int fd = get_unused_fd();
   struct file *f = filp_open(tmp, flags, mode);
   fd_install(fd, f);
   putname(tmp);
   return fd;
}

上述代码也可以在你的Linux机器上的fs/open.c文件中找到。

现在,我们可以看到,这个函数调用了许多其他函数,例如第一个函数名为getname(),我们向其中传递文件名作为参数,getname()函数的代码如下:

#define __getname() kmem_cache_alloc(names_cachep, SLAB_KERNEL)
#define putname(name) kmem_cache_free(names_cachep, (void *)(name))

char *getname(const char *filename) {
   char *tmp = __getname(); /* allocate some memory */
   strncpy_from_user(tmp, filename, PATH_MAX + 1);
   return tmp;
}

上述代码可以在**fs/namei.c**文件中找到,其主要用途是从用户空间复制文件名并将其传递到内核空间。然后,在getname()函数之后,我们有get_unused_fd()函数,它返回一个未使用的文件描述符,它只不过是一个可增长的当前打开文件列表中的整数索引。get_unused_fd()函数的代码如下:

int get_unused_fd(void) {
   struct files_struct *files = current->files;
   int fd = find_next_zero_bit(files->open_fds, files->max_fdset, files->next_fd);
   FD_SET(fd, files->open_fds); /* in use now */
   files->next_fd = fd + 1;
   return fd;
}

现在我们有filp_open()函数,其实现如下:

struct file *filp_open(const char *filename, int flags, int mode) {
   struct nameidata nd;
   open_namei(filename, flags, mode, &nd);
   return dentry_open(nd.dentry, nd.mnt, flags);
}

上述函数起着两个关键作用:首先,它使用文件系统查找与传入路径的文件名对应的inode。接下来,如果它创建一个包含所有关于inode的基本信息的struct file,然后返回该文件。

现在,调用栈中的下一个函数是fd_install()函数,它可以在include/linux/file.h文件中找到。它用于存储filp_open()函数返回的信息。fd_install()函数的代码如下:

void fd_install(unsigned int fd, struct file *file) {
   struct files_struct *files = current->files;
   files->fd[fd] = file;
}

然后我们有store()函数,它存储从filp_open()函数返回的结构体,然后将该结构体安装到进程的打开文件列表中。

下一步是释放已分配的内核控制内存块。最后,它返回文件描述符,然后可以将其传递给其他C函数,例如close(),write()等。

更新于:2021年7月31日

5K+ 次浏览

开启你的职业生涯

通过完成课程获得认证

开始学习
广告