aboutsummaryrefslogtreecommitdiff
path: root/fs/rawfs/dir.c
blob: 3ae96328bbee8d55f97436d8d118c9122c6a77ac (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
  RAWFS: Raw file system for NAND flash
  Copyright (C) 2012-2015  Perry Hsu <perry.hsu@mediatek.com>"

  This program can be distributed under the terms of the GNU GPL.
  See the file COPYING.
*/

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/crc32.h>
#include "rawfs.h"

int rawfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
	struct inode *inode = filp->f_path.dentry->d_inode;
	struct dentry *dentry = filp->f_path.dentry;
	struct super_block *sb = inode->i_sb;
	struct rawfs_sb_info *sbi = RAWFS_SB(sb);
	int total_cnt = 0;  /* Total entries we found in hlist */

	loff_t cpos;
	unsigned long ino;

	cpos = filp->f_pos;


	/* Read dir will execute twice. */
	if (inode->i_ino == RAWFS_ROOT_INO)
		RAWFS_PRINT(RAWFS_DBG_DIR, "rawfs_readdir, root, pos %lld\n", cpos);
	else
		RAWFS_PRINT(RAWFS_DBG_DIR, "rawfs_readdir, %s, i_id %X, i_ino %X, pos %lld\n",
		dentry->d_name.name, RAWFS_I(inode)->i_id, (unsigned)inode->i_ino, cpos);

	switch (cpos) {
	case 0:
		ino = dentry->d_inode->i_ino;
		if (filldir(dirent, ".", 1, cpos, ino, DT_DIR) < 0)
			break;
		filp->f_pos++;
		cpos++;
		/* fallthrough */
	case 1:
		ino = parent_ino(dentry);
		if (filldir(dirent, "..", 2, cpos, ino, DT_DIR) < 0)
			break;
		filp->f_pos++;
		cpos++;
		/* fallthrough */
	default:
		{
			struct rawfs_file_list_entry *entry;
			struct list_head *lists[2];
			int i;

			lists[0] =  &sbi->folder_list;
			lists[1] =  &sbi->file_list;

			mutex_lock(&sbi->file_list_lock);

			for (i = 0; i < 2; i++)	{
				list_for_each_entry(entry, lists[i], list)
				{
					 int name_len;

					 /* Matching sub-directory */
					 if (entry->file_info.i_parent_folder_id !=
						RAWFS_I(dentry->d_inode)->i_id) {
						RAWFS_PRINT(RAWFS_DBG_DIR,
							"readdir: skip %s, parent folder id %X, target folder %X\n",
						   entry->file_info.i_name,
						   entry->file_info.i_parent_folder_id,
						   RAWFS_I(dentry->d_inode)->i_id);
						continue;
					 }

					 total_cnt++;

					 if ((total_cnt+2) <= cpos) { /* skip first N + 2 (. & ..)
						entiries, if cpos doesn't start from zero */
						RAWFS_PRINT(RAWFS_DBG_DIR,
						"readdir: cpos=%lld, total cnt=%d, %s\n", cpos, total_cnt,
						entry->file_info.i_name);
						continue;
					 }

					 name_len = strlen(entry->file_info.i_name);

					 if (filldir(dirent,
						entry->file_info.i_name,
						name_len,
						cpos,
						entry->file_info.i_id,
						(S_ISDIR(entry->file_info.i_mode)?DT_DIR:DT_REG)) < 0)
						goto out;

					 filp->f_pos++;
					 cpos++;
				}
			}
		}

out:
			mutex_unlock(&sbi->file_list_lock);

			break;
	}

	return 0;
}
EXPORT_SYMBOL_GPL(rawfs_readdir);

int rawfs_file_sync(struct file *file, loff_t start, loff_t end,
	int datasync)
{
	struct inode *inode = file->f_path.dentry->d_inode;

	RAWFS_PRINT(RAWFS_DBG_DIR, "fsync, i_ino %ld\n", inode->i_ino);
	return 0;
}
EXPORT_SYMBOL_GPL(rawfs_file_sync);

MODULE_AUTHOR("Perry Hsu <perry.hsu@mediatek.com>");
MODULE_DESCRIPTION("RAW file system for NAND flash");
MODULE_LICENSE("GPL");