dfs_romfs.c 6.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 * File      : dfs_romfs.c
 * This file is part of Device File System in RT-Thread RTOS
 * COPYRIGHT (C) 2004-2011, RT-Thread Development Team
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.rt-thread.org/license/LICENSE.
 *
 * Change Logs:
 * Date           Author       Notes
 */

B
bernard.xiong 已提交
14 15 16 17 18
#include <rtthread.h>
#include <dfs.h>
#include <dfs_fs.h>
#include "dfs_romfs.h"

19
int dfs_romfs_mount(struct dfs_filesystem *fs, unsigned long rwflag, const void *data)
B
bernard.xiong 已提交
20
{
21
	struct romfs_dirent *root_dirent;
B
bernard.xiong 已提交
22

23 24
	if (data == RT_NULL)
		return -DFS_STATUS_EIO;
B
bernard.xiong 已提交
25

26
	root_dirent = (struct romfs_dirent *)data;
B
bernard.xiong 已提交
27 28 29 30 31
	fs->data = root_dirent;

	return DFS_STATUS_OK;
}

32
int dfs_romfs_unmount(struct dfs_filesystem *fs)
B
bernard.xiong 已提交
33 34 35 36
{
	return DFS_STATUS_OK;
}

37
int dfs_romfs_ioctl(struct dfs_fd *file, int cmd, void *args)
B
bernard.xiong 已提交
38 39 40 41
{
	return -DFS_STATUS_EIO;
}

42
struct romfs_dirent *dfs_romfs_lookup(struct romfs_dirent *root_dirent, const char *path, rt_size_t *size)
B
bernard.xiong 已提交
43
{
44
	rt_size_t index, found;
B
bernard.xiong 已提交
45
	const char *subpath, *subpath_end;
46
	struct romfs_dirent *dirent;
47
	rt_size_t dirent_size;
B
bernard.xiong 已提交
48

49 50 51 52 53
	if (path[0] == '/' && path[1] == '\0') 
	{
		*size = root_dirent->size;
		return root_dirent;
	}
B
bernard.xiong 已提交
54

55
	/* goto root directy entries */
56
	dirent = (struct romfs_dirent *)root_dirent->data;
57
	dirent_size = root_dirent->size;
B
bernard.xiong 已提交
58 59 60 61

	/* get the end position of this subpath */
	subpath_end = path;
	/* skip /// */
62 63
	while (*subpath_end && *subpath_end == '/')
		subpath_end ++;
B
bernard.xiong 已提交
64
	subpath = subpath_end;
65 66
	while ((*subpath_end != '/') && *subpath_end)
		subpath_end ++;
B
bernard.xiong 已提交
67 68 69

	while (dirent != RT_NULL)
	{
70 71
		found = 0;
		
B
bernard.xiong 已提交
72
		/* search in folder */
73
		for (index = 0; index < dirent_size; index ++)
B
bernard.xiong 已提交
74 75 76
		{
			if (rt_strncmp(dirent[index].name, subpath, (subpath_end - subpath)) == 0)
			{
77 78
				dirent_size = dirent[index].size;

B
bernard.xiong 已提交
79
				/* skip /// */
80 81
				while (*subpath_end && *subpath_end == '/')
					subpath_end ++;
B
bernard.xiong 已提交
82
				subpath = subpath_end;
83 84
				while ((*subpath_end != '/') && *subpath_end)
					subpath_end ++;
B
bernard.xiong 已提交
85

86 87 88 89 90
				if (!(*subpath))
				{
					*size = dirent_size;
					return &dirent[index];
				}
B
bernard.xiong 已提交
91 92 93

				if (dirent[index].type == ROMFS_DIRENT_DIR)
				{
94
					/* enter directory */
B
bernard.xiong 已提交
95
					dirent = (struct romfs_dirent*)dirent[index].data;
96
					found = 1;
B
bernard.xiong 已提交
97 98
					break;
				}
99 100 101
				else 
				{
					/* return file dirent */
102 103
					if (subpath != RT_NULL)
						break; /* not the end of path */
104
					
105 106
					return &dirent[index];
				}
B
bernard.xiong 已提交
107 108
			}
		}
109

110 111
		if (!found)
			break; /* not found */
B
bernard.xiong 已提交
112 113 114 115 116 117
	}

	/* not found */
	return RT_NULL;
}

118
int dfs_romfs_read(struct dfs_fd *file, void *buf, rt_size_t count)
B
bernard.xiong 已提交
119 120
{
	rt_size_t length;
121
	struct romfs_dirent *dirent;
B
bernard.xiong 已提交
122 123 124 125 126 127 128 129 130 131 132 133

	dirent = (struct romfs_dirent *)file->data;
	RT_ASSERT(dirent != RT_NULL);

	if (count < file->size - file->pos)
		length = count;
	else
		length = file->size - file->pos;

	if (length > 0)
		memcpy(buf, &(dirent->data[file->pos]), length);

134 135 136
	/* update file current position */
	file->pos += length;

B
bernard.xiong 已提交
137 138 139
	return length;
}

140
int dfs_romfs_lseek(struct dfs_fd *file, rt_off_t offset)
B
bernard.xiong 已提交
141
{
B
bernard.xiong 已提交
142
	if (offset <= file->size)
B
bernard.xiong 已提交
143 144 145 146 147 148 149 150
	{
		file->pos = offset;
		return file->pos;
	}

	return -DFS_STATUS_EIO;
}

151
int dfs_romfs_close(struct dfs_fd *file)
B
bernard.xiong 已提交
152 153 154 155 156
{
	file->data = RT_NULL;
	return DFS_STATUS_OK;
}

157
int dfs_romfs_open(struct dfs_fd *file)
B
bernard.xiong 已提交
158
{
159
	rt_size_t size;
160 161
	struct romfs_dirent *dirent;
	struct romfs_dirent *root_dirent;
B
bernard.xiong 已提交
162

163
	root_dirent = (struct romfs_dirent *)file->fs->data;
B
bernard.xiong 已提交
164

B
bernard.xiong 已提交
165
	if (file->flags & (DFS_O_CREAT | DFS_O_WRONLY | DFS_O_APPEND | DFS_O_TRUNC | DFS_O_RDWR))
B
bernard.xiong 已提交
166 167
		return -DFS_STATUS_EINVAL;

168
	dirent = dfs_romfs_lookup(root_dirent, file->path, &size);
169 170
	if (dirent == RT_NULL)
		return -DFS_STATUS_ENOENT;
B
bernard.xiong 已提交
171

172 173 174
	/* entry is a directory file type */
	if (dirent->type == ROMFS_DIRENT_DIR)
	{
175
		if (!(file->flags & DFS_O_DIRECTORY))
176 177 178 179 180 181 182 183
			return -DFS_STATUS_ENOENT;
	}
	else
	{
		/* entry is a file, but open it as a directory */
		if (file->flags & DFS_O_DIRECTORY)
			return -DFS_STATUS_ENOENT;
	}
184

185 186
	file->data = dirent;
	file->size = size;
B
bernard.xiong 已提交
187
	file->pos = 0;
188

B
bernard.xiong 已提交
189 190 191
	return DFS_STATUS_OK;
}

192
int dfs_romfs_stat(struct dfs_filesystem *fs, const char *path, struct stat *st)
B
bernard.xiong 已提交
193
{
194
	rt_size_t size;
195 196
	struct romfs_dirent *dirent;
	struct romfs_dirent *root_dirent;
B
bernard.xiong 已提交
197

198
	root_dirent = (struct romfs_dirent *)fs->data;
199
	dirent = dfs_romfs_lookup(root_dirent, path, &size);
B
bernard.xiong 已提交
200

201 202
	if (dirent == RT_NULL)
		return -DFS_STATUS_ENOENT;
B
bernard.xiong 已提交
203 204

	st->st_dev = 0;
B
bernard.xiong@gmail.com 已提交
205 206
	st->st_mode = DFS_S_IFREG | DFS_S_IRUSR | DFS_S_IRGRP | DFS_S_IROTH |
	DFS_S_IWUSR | DFS_S_IWGRP | DFS_S_IWOTH;
207

B
bernard.xiong 已提交
208
	if (dirent->type == ROMFS_DIRENT_DIR)
B
bernard.xiong@gmail.com 已提交
209
	{
210 211
		st->st_mode &= ~DFS_S_IFREG;
		st->st_mode |= DFS_S_IFDIR | DFS_S_IXUSR | DFS_S_IXGRP | DFS_S_IXOTH;
B
bernard.xiong 已提交
212 213 214 215 216 217 218 219 220
	}

	st->st_size = dirent->size;
	st->st_mtime = 0;
	st->st_blksize = 512;

	return DFS_STATUS_OK;
}

221
int dfs_romfs_getdents(struct dfs_fd *file, struct dirent *dirp, rt_uint32_t count)
B
bernard.xiong 已提交
222 223 224
{
	rt_size_t index;
	const char *name;
225
	struct dirent *d;
B
bernard.xiong 已提交
226 227
	struct romfs_dirent *dirent, *sub_dirent;

228
	dirent = (struct romfs_dirent *)file->data;
229
	RT_ASSERT(dirent->type == ROMFS_DIRENT_DIR);
B
bernard.xiong 已提交
230

231
	/* enter directory */
232
	dirent = (struct romfs_dirent *)dirent->data;
233
	
B
bernard.xiong 已提交
234
	/* make integer count */
235
	count = (count / sizeof(struct dirent));
236 237
	if (count == 0)
		return -DFS_STATUS_EINVAL;
B
bernard.xiong 已提交
238 239
	
	index = 0;
240
	for (index = 0; index < count && file->pos < file->size; index ++)
B
bernard.xiong 已提交
241 242
	{
		d = dirp + index;
B
bernard.xiong@gmail.com 已提交
243

B
bernard.xiong 已提交
244 245 246 247
		sub_dirent = &dirent[file->pos];
		name = sub_dirent->name;

		/* fill dirent */
248 249 250 251 252
		if (sub_dirent->type == ROMFS_DIRENT_DIR)
			d->d_type = DFS_DT_DIR;
		else
			d->d_type = DFS_DT_REG;

B
bernard.xiong@gmail.com 已提交
253
		d->d_namlen = rt_strlen(name);
254 255
		d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
		rt_strncpy(d->d_name, name, rt_strlen(name) + 1);
B
bernard.xiong 已提交
256 257 258 259

		/* move to next position */
		++ file->pos; 
	}
260 261

	return index * sizeof(struct dirent);
B
bernard.xiong 已提交
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
}

static const struct dfs_filesystem_operation _romfs = 
{
	"rom",
	dfs_romfs_mount,
	dfs_romfs_unmount,
	RT_NULL,
	RT_NULL,

	dfs_romfs_open,
	dfs_romfs_close,
	dfs_romfs_ioctl,
	dfs_romfs_read,
	RT_NULL,
	RT_NULL,
	dfs_romfs_lseek,
	dfs_romfs_getdents,
	RT_NULL,
	dfs_romfs_stat,
	RT_NULL,
};

int dfs_romfs_init(void)
{
    /* register rom file system */
    dfs_register(&_romfs);
	return 0;
}