1 /*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 */
9
10 #include <rtthread.h>
11 #include <dfs.h>
12 #include <dfs_fs.h>
13 #include <dfs_file.h>
14
15 #include "dfs_romfs.h"
16
dfs_romfs_mount(struct dfs_filesystem * fs,unsigned long rwflag,const void * data)17 int dfs_romfs_mount(struct dfs_filesystem *fs, unsigned long rwflag, const void *data)
18 {
19 struct romfs_dirent *root_dirent;
20
21 if (data == NULL)
22 return -EIO;
23
24 root_dirent = (struct romfs_dirent *)data;
25 fs->data = root_dirent;
26
27 return RT_EOK;
28 }
29
dfs_romfs_unmount(struct dfs_filesystem * fs)30 int dfs_romfs_unmount(struct dfs_filesystem *fs)
31 {
32 return RT_EOK;
33 }
34
dfs_romfs_ioctl(struct dfs_file * file,int cmd,void * args)35 int dfs_romfs_ioctl(struct dfs_file *file, int cmd, void *args)
36 {
37 int ret = RT_EOK;
38 struct romfs_dirent *dirent;
39
40 dirent = (struct romfs_dirent *)file->vnode->data;
41 RT_ASSERT(dirent != NULL);
42
43 switch (cmd)
44 {
45 case RT_FIOGETADDR:
46 {
47 *(rt_ubase_t*)args = (rt_ubase_t)dirent->data;
48 break;
49 }
50 case RT_FIOFTRUNCATE:
51 {
52 break;
53 }
54 default:
55 ret = -RT_EINVAL;
56 break;
57 }
58 return ret;
59 }
60
check_dirent(struct romfs_dirent * dirent)61 rt_inline int check_dirent(struct romfs_dirent *dirent)
62 {
63 if ((dirent->type != ROMFS_DIRENT_FILE && dirent->type != ROMFS_DIRENT_DIR)
64 || dirent->size == ~0U)
65 return -1;
66 return 0;
67 }
68
dfs_romfs_lookup(struct romfs_dirent * root_dirent,const char * path,rt_size_t * size)69 struct romfs_dirent *dfs_romfs_lookup(struct romfs_dirent *root_dirent, const char *path, rt_size_t *size)
70 {
71 rt_size_t index, found;
72 const char *subpath, *subpath_end;
73 struct romfs_dirent *dirent;
74 rt_size_t dirent_size;
75
76 /* Check the root_dirent. */
77 if (check_dirent(root_dirent) != 0)
78 return NULL;
79
80 if (path[0] == '/' && path[1] == '\0')
81 {
82 *size = root_dirent->size;
83 return root_dirent;
84 }
85
86 /* goto root directory entries */
87 dirent = (struct romfs_dirent *)root_dirent->data;
88 dirent_size = root_dirent->size;
89
90 /* get the end position of this subpath */
91 subpath_end = path;
92 /* skip /// */
93 while (*subpath_end && *subpath_end == '/')
94 subpath_end ++;
95 subpath = subpath_end;
96 while ((*subpath_end != '/') && *subpath_end)
97 subpath_end ++;
98
99 while (dirent != NULL)
100 {
101 found = 0;
102
103 /* search in folder */
104 for (index = 0; index < dirent_size; index ++)
105 {
106 if (check_dirent(&dirent[index]) != 0)
107 return NULL;
108 if (rt_strlen(dirent[index].name) == (rt_size_t)(subpath_end - subpath) &&
109 rt_strncmp(dirent[index].name, subpath, (subpath_end - subpath)) == 0)
110 {
111 dirent_size = dirent[index].size;
112
113 /* skip /// */
114 while (*subpath_end && *subpath_end == '/')
115 subpath_end ++;
116 subpath = subpath_end;
117 while ((*subpath_end != '/') && *subpath_end)
118 subpath_end ++;
119
120 if (!(*subpath))
121 {
122 *size = dirent_size;
123 return &dirent[index];
124 }
125
126 if (dirent[index].type == ROMFS_DIRENT_DIR)
127 {
128 /* enter directory */
129 dirent = (struct romfs_dirent *)dirent[index].data;
130 found = 1;
131 break;
132 }
133 else
134 {
135 /* return file dirent */
136 return &dirent[index];
137 }
138 }
139 }
140
141 if (!found)
142 break; /* not found */
143 }
144
145 /* not found */
146 return NULL;
147 }
148
dfs_romfs_read(struct dfs_file * file,void * buf,size_t count)149 ssize_t dfs_romfs_read(struct dfs_file *file, void *buf, size_t count)
150 {
151 rt_size_t length;
152 struct romfs_dirent *dirent;
153
154 dirent = (struct romfs_dirent *)file->vnode->data;
155 RT_ASSERT(dirent != NULL);
156
157 if (check_dirent(dirent) != 0)
158 {
159 return -EIO;
160 }
161
162 if (count < file->vnode->size - file->pos)
163 length = count;
164 else
165 length = file->vnode->size - file->pos;
166
167 if (length > 0)
168 rt_memcpy(buf, &(dirent->data[file->pos]), length);
169
170 /* update file current position */
171 file->pos += length;
172
173 return length;
174 }
175
dfs_romfs_lseek(struct dfs_file * file,off_t offset)176 off_t dfs_romfs_lseek(struct dfs_file *file, off_t offset)
177 {
178 if (offset <= file->vnode->size)
179 {
180 file->pos = offset;
181 return file->pos;
182 }
183
184 return -EIO;
185 }
186
dfs_romfs_close(struct dfs_file * file)187 int dfs_romfs_close(struct dfs_file *file)
188 {
189 RT_ASSERT(file->vnode->ref_count > 0);
190 if (file->vnode->ref_count > 1)
191 {
192 return RT_EOK;
193 }
194 file->vnode->data = NULL;
195 return RT_EOK;
196 }
197
dfs_romfs_open(struct dfs_file * file)198 int dfs_romfs_open(struct dfs_file *file)
199 {
200 rt_size_t size;
201 struct romfs_dirent *dirent;
202 struct romfs_dirent *root_dirent;
203 struct dfs_filesystem *fs;
204
205 if (file->flags & (O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_RDWR))
206 {
207 return -EINVAL;
208 }
209
210 RT_ASSERT(file->vnode->ref_count > 0);
211 if (file->vnode->ref_count > 1)
212 {
213 if (file->vnode->type == FT_DIRECTORY
214 && !(file->flags & O_DIRECTORY))
215 {
216 return -ENOENT;
217 }
218 file->pos = 0;
219 return 0;
220 }
221
222 fs = file->vnode->fs;
223 root_dirent = (struct romfs_dirent *)fs->data;
224
225 if (check_dirent(root_dirent) != 0)
226 {
227 return -EIO;
228 }
229
230 if (file->flags & (O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_RDWR))
231 {
232 return -EINVAL;
233 }
234
235 dirent = dfs_romfs_lookup(root_dirent, file->vnode->path, &size);
236 if (dirent == NULL)
237 {
238 return -ENOENT;
239 }
240
241 /* entry is a directory file type */
242 if (dirent->type == ROMFS_DIRENT_DIR)
243 {
244 if (!(file->flags & O_DIRECTORY))
245 {
246 return -ENOENT;
247 }
248 file->vnode->type = FT_DIRECTORY;
249 }
250 else
251 {
252 /* entry is a file, but open it as a directory */
253 if (file->flags & O_DIRECTORY)
254 {
255 return -ENOENT;
256 }
257 file->vnode->type = FT_REGULAR;
258 }
259
260 file->vnode->data = dirent;
261 file->vnode->size = size;
262 file->pos = 0;
263
264 return RT_EOK;
265 }
266
dfs_romfs_stat(struct dfs_filesystem * fs,const char * path,struct stat * st)267 int dfs_romfs_stat(struct dfs_filesystem *fs, const char *path, struct stat *st)
268 {
269 rt_size_t size;
270 struct romfs_dirent *dirent;
271 struct romfs_dirent *root_dirent;
272
273 root_dirent = (struct romfs_dirent *)fs->data;
274 dirent = dfs_romfs_lookup(root_dirent, path, &size);
275
276 if (dirent == NULL)
277 {
278 return -ENOENT;
279 }
280
281 st->st_dev = 0;
282 st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
283 S_IWUSR | S_IWGRP | S_IWOTH;
284
285 if (dirent->type == ROMFS_DIRENT_DIR)
286 {
287 st->st_mode &= ~S_IFREG;
288 st->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
289 }
290
291 st->st_size = dirent->size;
292 st->st_mtime = 0;
293
294 return RT_EOK;
295 }
296
dfs_romfs_getdents(struct dfs_file * file,struct dirent * dirp,uint32_t count)297 int dfs_romfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
298 {
299 rt_size_t index;
300 rt_size_t len;
301 const char *name;
302 struct dirent *d;
303 struct romfs_dirent *dirent, *sub_dirent;
304
305 dirent = (struct romfs_dirent *)file->vnode->data;
306 if (check_dirent(dirent) != 0)
307 {
308 return -EIO;
309 }
310 RT_ASSERT(dirent->type == ROMFS_DIRENT_DIR);
311
312 /* enter directory */
313 dirent = (struct romfs_dirent *)dirent->data;
314
315 /* make integer count */
316 count = (count / sizeof(struct dirent));
317 if (count == 0)
318 {
319 return -EINVAL;
320 }
321
322 index = 0;
323 for (index = 0; index < count && file->pos < file->vnode->size; index++)
324 {
325 d = dirp + index;
326
327 sub_dirent = &dirent[file->pos];
328 name = sub_dirent->name;
329
330 /* fill dirent */
331 if (sub_dirent->type == ROMFS_DIRENT_DIR)
332 d->d_type = DT_DIR;
333 else
334 d->d_type = DT_REG;
335
336 len = rt_strlen(name);
337 RT_ASSERT(len <= RT_UINT8_MAX);
338 d->d_namlen = (rt_uint8_t)len;
339 d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
340 rt_strncpy(d->d_name, name, DIRENT_NAME_MAX);
341
342 /* move to next position */
343 ++ file->pos;
344 }
345
346 return index * sizeof(struct dirent);
347 }
348
349 static const struct dfs_file_ops _rom_fops =
350 {
351 dfs_romfs_open,
352 dfs_romfs_close,
353 dfs_romfs_ioctl,
354 dfs_romfs_read,
355 NULL,
356 NULL,
357 dfs_romfs_lseek,
358 dfs_romfs_getdents,
359 NULL,
360 };
361 static const struct dfs_filesystem_ops _romfs =
362 {
363 "rom",
364 DFS_FS_FLAG_DEFAULT,
365 &_rom_fops,
366
367 dfs_romfs_mount,
368 dfs_romfs_unmount,
369 NULL,
370 NULL,
371
372 NULL,
373 dfs_romfs_stat,
374 NULL,
375 };
376
dfs_romfs_init(void)377 int dfs_romfs_init(void)
378 {
379 /* register rom file system */
380 dfs_register(&_romfs);
381 return 0;
382 }
383 INIT_COMPONENT_EXPORT(dfs_romfs_init);
384
385 #ifndef RT_USING_DFS_ROMFS_USER_ROOT
386 static const unsigned char _dummy_dummy_txt[] =
387 {
388 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x21, 0x0d, 0x0a,
389 };
390
391 static const struct romfs_dirent _dummy[] =
392 {
393 {ROMFS_DIRENT_FILE, "dummy.txt", _dummy_dummy_txt, sizeof(_dummy_dummy_txt)},
394 };
395
396 static const unsigned char _dummy_txt[] =
397 {
398 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x21, 0x0d, 0x0a,
399 };
400
401 rt_weak const struct romfs_dirent _root_dirent[] =
402 {
403 {ROMFS_DIRENT_DIR, "dummy", (rt_uint8_t *)_dummy, sizeof(_dummy) / sizeof(_dummy[0])},
404 {ROMFS_DIRENT_FILE, "dummy.txt", _dummy_txt, sizeof(_dummy_txt)},
405 };
406
407 rt_weak const struct romfs_dirent romfs_root =
408 {
409 ROMFS_DIRENT_DIR, "/", (rt_uint8_t *)_root_dirent, sizeof(_root_dirent) / sizeof(_root_dirent[0])
410 };
411 #endif
412