Linux driver 遍历指定文件夹查找文件

linux 应用层可以使用opendir, readdir, closedir接口进行文件夹遍历.

API接口位于 linux/fs/readdir.c

 

before 3.11

linux driver层, 则可以使用file_operation中的readdir(3.11以前)接口进行读取.

typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned);

struct file_operations {

	int (*readdir) (struct file *, void *, filldir_t);
};

 

 

示例如下:

以下是查找指定目录下的.txt或.ini文件

static int tmp_filldir(void *buf, const char *name, int namelen,
	loff_t offset, u64 ino, unsigned d_type)
{
	unsigned long d_ino;

	d_ino = ino;
	if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
		return -EOVERFLOW;
	}
	if (namelen > 0) {
		memcpy(buf, name, namelen);
		return 0;
	}
	return -ENOENT;
}

static int linux_get_file_path(const char *dirpath, char *full_path)
{
	struct file *pfile;
	mm_segment_t old_fs;
	char read_buf[100] = {0};
	int ret;
	int err;

	pfile = filp_open(dirpath, O_RDONLY, 0);
	if (IS_ERR(pfile)) {
		pr_err("Open %s failed!\n", dirpath);
		return -EINVAL; 
	}
	old_fs = get_fs();
	set_fs(KERNEL_DS);

	err = -ENOENT;
	if (pfile->f_op->readdir) {
		while (true) {
			ret = pfile->f_op->readdir(pfile, read_buf, tmp_filldir);
			if (ret || (read_buf[0] == '\0')) {
				break;
			}
			if (strstr(read_buf, ".txt") || strstr(read_buf, ".TXT") ||
				strstr(read_buf, ".ini") || strstr(read_buf, ".ini")) {
					// for too long filename
					*(extstr+4) = '\0';
					snprintf(full_path, PATH_MAX, "%s/%s", dirpath, read_buf);
					pr_err("find file: %s\n", read_buf);
					err = 0;
					break;
			}
			memset(read_buf, 0, 100);
		}
	}

	filp_close(pfile, NULL);
	set_fs(old_fs);
	return err;
}

After 3.11

3.11以后由iterate接口代替了readdir

static char g_buffer[1024] = {0};
static int linux_filldir(void *unused, const char *name, int namelen,
	loff_t offset, u64 ino, unsigned int d_type) 
{
	pr_info("(%d)%s", namelen, name);
	if (namelen > 0) {
		memcpy(g_buffer, name, namelen);
		return 0;
	}
	return -ENOENT;
}

static int linux_get_file_path(const char *dirpath, char **full_path)
{
	struct file *pfile;
	mm_segment_t old_fs;
	char *read_buf = NULL;
	int ret;
	int err;
	char *extstr;
	struct dir_context ctx = {.actor = linux_filldir};

	pfile = filp_open(dirpath, O_RDONLY, 0);
	if (IS_ERR(pfile)) {
		pr_err("Open %s failed!\n", dirpath);
		return -EINVAL; 
	}
	old_fs = get_fs();
	set_fs(KERNEL_DS);

	err = -ENOENT;

	if (pfile->f_op->iterate) {
		
		while (true) {
			ret = pfile->f_op->iterate(pfile, &ctx);
			if (ret || (g_buffer[0] == '\0')) {
				break;
			}
			if ((extstr = strstr(g_buffer, ".txt")) || 
				(extstr = strstr(g_buffer, ".TXT")) ||
				(extstr = strstr(g_buffer, ".ini")) || 
				(extstr = strstr(g_buffer, ".INI"))) {
					// for long filename
					*(extstr+4) = '\0';
					snprintf(*full_path, PATH_MAX, "%s/%s", dirpath, read_buf);
					pr_err("find file: %s\n", g_buffer);
					err = 0;
					break;
			}
			memset(g_buffer, 0, PATH_MAX);
		}
	}

err_out:
	filp_close(pfile, NULL);
	set_fs(old_fs);
	return err;
}

 

调用示例:

 

 

#define MY_DIR		"/sdcard/my/dir"

char *filepath = NULL;

filepath = kzalloc(PATH_MAX, GFP_KERNEL);
if (!filepath) {
	pr_err("allocate mem for porch failed!\n");
	return;
}
ret = linux_get_file_path(MY_DIR, filepath);
if (ret) {
	pr_err("file not found, use default porch.txt!\n");
	snprintf(filepath, PATH_MAX, "%s/%s", MY_DIR, "porch.txt");
}

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值