1 /*
2 * Copyright (c) 2006-2023, 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_dentry.h>
14 #include <dfs_file.h>
15 #include <dfs_mnt.h>
16
17 #include "dfs_romfs.h"
18 #include <errno.h>
19 #include <fcntl.h>
20
21 #include <rtdbg.h>
22
23 static const struct dfs_file_ops _rom_fops;
24
25 static const mode_t romfs_modemap[] =
26 {
27 S_IFREG | 0644, /* regular file */
28 S_IFDIR | 0644, /* directory */
29 0, /* hard link */
30 S_IFLNK | 0777, /* symlink */
31 S_IFBLK | 0600, /* blockdev */
32 S_IFCHR | 0600, /* chardev */
33 S_IFSOCK | 0644, /* socket */
34 S_IFIFO | 0644 /* FIFO */
35 };
36
dfs_romfs_mount(struct dfs_mnt * mnt,unsigned long rwflag,const void * data)37 static int dfs_romfs_mount(struct dfs_mnt *mnt, unsigned long rwflag, const void *data)
38 {
39 struct romfs_dirent *root_dirent;
40
41 if (data == NULL)
42 return -1;
43
44 root_dirent = (struct romfs_dirent *)data;
45 mnt->data = root_dirent;
46
47 return 0;
48 }
49
dfs_romfs_umount(struct dfs_mnt * fs)50 static int dfs_romfs_umount(struct dfs_mnt *fs)
51 {
52 return RT_EOK;
53 }
54
dfs_romfs_ioctl(struct dfs_file * file,int cmd,void * args)55 int dfs_romfs_ioctl(struct dfs_file *file, int cmd, void *args)
56 {
57 int ret = RT_EOK;
58 struct romfs_dirent *dirent;
59
60 dirent = (struct romfs_dirent *)file->data;
61 RT_ASSERT(dirent != NULL);
62
63 switch (cmd)
64 {
65 case RT_FIOGETADDR:
66 {
67 *(rt_ubase_t*)args = (rt_ubase_t)dirent->data;
68 break;
69 }
70 case RT_FIOFTRUNCATE:
71 {
72 break;
73 }
74 default:
75 ret = -RT_EINVAL;
76 break;
77 }
78 return ret;
79 }
80
check_dirent(struct romfs_dirent * dirent)81 rt_inline int check_dirent(struct romfs_dirent *dirent)
82 {
83 if (dirent == NULL
84 ||(dirent->type != ROMFS_DIRENT_FILE && dirent->type != ROMFS_DIRENT_DIR)
85 || dirent->size == ~0)
86 return -1;
87 return 0;
88 }
89
__dfs_romfs_lookup(struct romfs_dirent * root_dirent,const char * path,rt_size_t * size)90 struct romfs_dirent *__dfs_romfs_lookup(struct romfs_dirent *root_dirent, const char *path, rt_size_t *size)
91 {
92 rt_size_t index, found;
93 const char *subpath, *subpath_end;
94 struct romfs_dirent *dirent;
95 rt_size_t dirent_size;
96
97 /* Check the root_dirent. */
98 if (check_dirent(root_dirent) != 0)
99 return NULL;
100
101 if (path[0] == '/' && path[1] == '\0')
102 {
103 *size = root_dirent->size;
104 return root_dirent;
105 }
106
107 /* goto root directy entries */
108 dirent = (struct romfs_dirent *)root_dirent->data;
109 dirent_size = root_dirent->size;
110
111 /* get the end position of this subpath */
112 subpath_end = path;
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 while (dirent != NULL)
121 {
122 found = 0;
123
124 /* search in folder */
125 for (index = 0; index < dirent_size; index ++)
126 {
127 if (check_dirent(&dirent[index]) != 0)
128 return NULL;
129 if (rt_strlen(dirent[index].name) == (subpath_end - subpath) &&
130 rt_strncmp(dirent[index].name, subpath, (subpath_end - subpath)) == 0)
131 {
132 dirent_size = dirent[index].size;
133
134 /* skip /// */
135 while (*subpath_end && *subpath_end == '/')
136 subpath_end ++;
137 subpath = subpath_end;
138 while ((*subpath_end != '/') && *subpath_end)
139 subpath_end ++;
140
141 if (!(*subpath))
142 {
143 *size = dirent_size;
144 return &dirent[index];
145 }
146
147 if (dirent[index].type == ROMFS_DIRENT_DIR)
148 {
149 /* enter directory */
150 dirent = (struct romfs_dirent *)dirent[index].data;
151 found = 1;
152 break;
153 }
154 else
155 {
156 /* return file dirent */
157 return &dirent[index];
158 }
159 }
160 }
161
162 if (!found)
163 break; /* not found */
164 }
165
166 /* not found */
167 return NULL;
168 }
169
dfs_romfs_lookup(struct dfs_dentry * dentry)170 static struct dfs_vnode *dfs_romfs_lookup (struct dfs_dentry *dentry)
171 {
172 rt_size_t size;
173 struct dfs_vnode *vnode = RT_NULL;
174 struct romfs_dirent *root_dirent = RT_NULL, *dirent = RT_NULL;
175
176 RT_ASSERT(dentry != RT_NULL);
177 RT_ASSERT(dentry->mnt != RT_NULL);
178
179 root_dirent = (struct romfs_dirent *)dentry->mnt->data;
180 if (check_dirent(root_dirent) == 0)
181 {
182 /* create a vnode */
183 DLOG(msg, "rom", "vnode", DLOG_MSG, "dfs_vnode_create()");
184 vnode = dfs_vnode_create();
185 if (vnode)
186 {
187 dirent = __dfs_romfs_lookup(root_dirent, dentry->pathname, &size);
188 if (dirent)
189 {
190 vnode->nlink = 1;
191 vnode->size = dirent->size;
192 if (dirent->type == ROMFS_DIRENT_DIR)
193 {
194 vnode->mode = romfs_modemap[ROMFS_DIRENT_DIR] | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
195 vnode->type = FT_DIRECTORY;
196 }
197 else if (dirent->type == ROMFS_DIRENT_FILE)
198 {
199 vnode->mode = romfs_modemap[ROMFS_DIRENT_FILE] | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
200 vnode->type = FT_REGULAR;
201 }
202
203 DLOG(msg, "rom", "rom", DLOG_MSG, "vnode->data = dirent");
204 vnode->data = dirent;
205 vnode->mnt = dentry->mnt;
206 }
207 else
208 {
209 /* no-entry */
210 DLOG(msg, "rom", "vnode", DLOG_MSG, "dfs_vnode_destroy, no-dentry");
211 dfs_vnode_destroy(vnode);
212 vnode = RT_NULL;
213 }
214 }
215 }
216
217 return vnode;
218 }
219
dfs_romfs_free_vnode(struct dfs_vnode * vnode)220 static int dfs_romfs_free_vnode(struct dfs_vnode *vnode)
221 {
222 /* nothing to be freed */
223 if (vnode->ref_count <= 1)
224 {
225 vnode->data = NULL;
226 }
227
228 return 0;
229 }
230
dfs_romfs_read(struct dfs_file * file,void * buf,size_t count,off_t * pos)231 static ssize_t dfs_romfs_read(struct dfs_file *file, void *buf, size_t count, off_t *pos)
232 {
233 rt_size_t length;
234 struct romfs_dirent *dirent;
235
236 dirent = (struct romfs_dirent *)file->vnode->data;
237 RT_ASSERT(dirent != NULL);
238
239 if (check_dirent(dirent) != 0)
240 {
241 return -EIO;
242 }
243
244 if (count < file->vnode->size - *pos)
245 length = count;
246 else
247 length = file->vnode->size - *pos;
248
249 if (length > 0)
250 memcpy(buf, &(dirent->data[*pos]), length);
251
252 /* update file current position */
253 *pos += length;
254
255 return length;
256 }
257
dfs_romfs_close(struct dfs_file * file)258 static int dfs_romfs_close(struct dfs_file *file)
259 {
260 return RT_EOK;
261 }
262
dfs_romfs_open(struct dfs_file * file)263 int dfs_romfs_open(struct dfs_file *file)
264 {
265 rt_size_t size;
266 struct romfs_dirent *dirent;
267 struct romfs_dirent *root_dirent;
268 struct dfs_mnt *mnt;
269
270 if (file->flags & (O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_RDWR))
271 {
272 return -EINVAL;
273 }
274
275 mnt = file->dentry->mnt;
276 RT_ASSERT(mnt != RT_NULL);
277
278 root_dirent = (struct romfs_dirent *)mnt->data;
279 if (check_dirent(root_dirent) != 0)
280 {
281 return -EIO;
282 }
283
284 /* get rom dirent */
285 dirent = __dfs_romfs_lookup(root_dirent, file->dentry->pathname, &size);
286 if (dirent == NULL)
287 {
288 return -ENOENT;
289 }
290
291 file->data = dirent;
292 file->fops = &_rom_fops;
293 file->fpos = 0;
294
295 return RT_EOK;
296 }
297
dfs_romfs_stat(struct dfs_dentry * dentry,struct stat * st)298 static int dfs_romfs_stat(struct dfs_dentry *dentry, struct stat *st)
299 {
300 rt_err_t ret = dfs_file_lock();
301 if (ret == RT_EOK)
302 {
303 st->st_dev = 0;
304 st->st_mode = dentry->vnode->mode;
305 st->st_size = dentry->vnode->size;
306 st->st_nlink = dentry->vnode->nlink;
307 st->st_mtime = 0;
308
309 dfs_file_unlock();
310 }
311
312 return RT_EOK;
313 }
314
dfs_romfs_getdents(struct dfs_file * file,struct dirent * dirp,uint32_t count)315 static int dfs_romfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
316 {
317 rt_size_t index;
318 const char *name;
319 struct dirent *d;
320 struct romfs_dirent *dirent, *sub_dirent;
321
322 dirent = (struct romfs_dirent *)file->vnode->data;
323 if (check_dirent(dirent) != 0)
324 {
325 return -EIO;
326 }
327 RT_ASSERT(dirent->type == ROMFS_DIRENT_DIR);
328
329 /* enter directory */
330 dirent = (struct romfs_dirent *)dirent->data;
331
332 /* make integer count */
333 count = (count / sizeof(struct dirent));
334 if (count == 0)
335 {
336 return -EINVAL;
337 }
338
339 index = 0;
340 for (index = 0; index < count && file->fpos < file->vnode->size; index++)
341 {
342 d = dirp + index;
343
344 sub_dirent = &dirent[file->fpos];
345 name = sub_dirent->name;
346
347 /* fill dirent */
348 if (sub_dirent->type == ROMFS_DIRENT_DIR)
349 d->d_type = DT_DIR;
350 else
351 d->d_type = DT_REG;
352
353 d->d_namlen = rt_strlen(name);
354 d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
355 rt_strncpy(d->d_name, name, DIRENT_NAME_MAX);
356
357 /* move to next position */
358 ++ file->fpos;
359 }
360
361 return index * sizeof(struct dirent);
362 }
363
364 static const struct dfs_file_ops _rom_fops =
365 {
366 .open = dfs_romfs_open,
367 .close = dfs_romfs_close,
368 .ioctl = dfs_romfs_ioctl,
369 .lseek = generic_dfs_lseek,
370 .read = dfs_romfs_read,
371 .getdents = dfs_romfs_getdents,
372 };
373
374 static const struct dfs_filesystem_ops _romfs_ops =
375 {
376 .name ="rom",
377 .flags = 0,
378 .default_fops = &_rom_fops,
379 .mount = dfs_romfs_mount,
380 .umount = dfs_romfs_umount,
381 .stat = dfs_romfs_stat,
382 .lookup = dfs_romfs_lookup,
383 .free_vnode = dfs_romfs_free_vnode
384 };
385
386 static struct dfs_filesystem_type _romfs =
387 {
388 .fs_ops = &_romfs_ops,
389 };
390
dfs_romfs_init(void)391 int dfs_romfs_init(void)
392 {
393 /* register rom file system */
394 dfs_register(&_romfs);
395
396 return 0;
397 }
398 INIT_COMPONENT_EXPORT(dfs_romfs_init);
399