1 /*
2 * Copyright (c) 2006-2018, 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_fd * file,int cmd,void * args)35 int dfs_romfs_ioctl(struct dfs_fd *file, int cmd, void *args)
36 {
37 return -EIO;
38 }
39
check_dirent(struct romfs_dirent * dirent)40 rt_inline int check_dirent(struct romfs_dirent *dirent)
41 {
42 if ((dirent->type != ROMFS_DIRENT_FILE && dirent->type != ROMFS_DIRENT_DIR)
43 || dirent->size == ~0)
44 return -1;
45 return 0;
46 }
47
dfs_romfs_lookup(struct romfs_dirent * root_dirent,const char * path,rt_size_t * size)48 struct romfs_dirent *dfs_romfs_lookup(struct romfs_dirent *root_dirent, const char *path, rt_size_t *size)
49 {
50 rt_size_t index, found;
51 const char *subpath, *subpath_end;
52 struct romfs_dirent *dirent;
53 rt_size_t dirent_size;
54
55 /* Check the root_dirent. */
56 if (check_dirent(root_dirent) != 0)
57 return NULL;
58
59 if (path[0] == '/' && path[1] == '\0')
60 {
61 *size = root_dirent->size;
62 return root_dirent;
63 }
64
65 /* goto root directy entries */
66 dirent = (struct romfs_dirent *)root_dirent->data;
67 dirent_size = root_dirent->size;
68
69 /* get the end position of this subpath */
70 subpath_end = path;
71 /* skip /// */
72 while (*subpath_end && *subpath_end == '/')
73 subpath_end ++;
74 subpath = subpath_end;
75 while ((*subpath_end != '/') && *subpath_end)
76 subpath_end ++;
77
78 while (dirent != NULL)
79 {
80 found = 0;
81
82 /* search in folder */
83 for (index = 0; index < dirent_size; index ++)
84 {
85 if (check_dirent(&dirent[index]) != 0)
86 return NULL;
87 if (rt_strlen(dirent[index].name) == (subpath_end - subpath) &&
88 rt_strncmp(dirent[index].name, subpath, (subpath_end - subpath)) == 0)
89 {
90 dirent_size = dirent[index].size;
91
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 if (!(*subpath))
100 {
101 *size = dirent_size;
102 return &dirent[index];
103 }
104
105 if (dirent[index].type == ROMFS_DIRENT_DIR)
106 {
107 /* enter directory */
108 dirent = (struct romfs_dirent*)dirent[index].data;
109 found = 1;
110 break;
111 }
112 else
113 {
114 /* return file dirent */
115 if (subpath != NULL)
116 break; /* not the end of path */
117
118 return &dirent[index];
119 }
120 }
121 }
122
123 if (!found)
124 break; /* not found */
125 }
126
127 /* not found */
128 return NULL;
129 }
130
dfs_romfs_read(struct dfs_fd * file,void * buf,size_t count)131 int dfs_romfs_read(struct dfs_fd *file, void *buf, size_t count)
132 {
133 rt_size_t length;
134 struct romfs_dirent *dirent;
135
136 dirent = (struct romfs_dirent *)file->data;
137 RT_ASSERT(dirent != NULL);
138
139 if (check_dirent(dirent) != 0)
140 {
141 return -EIO;
142 }
143
144 if (count < file->size - file->pos)
145 length = count;
146 else
147 length = file->size - file->pos;
148
149 if (length > 0)
150 memcpy(buf, &(dirent->data[file->pos]), length);
151
152 /* update file current position */
153 file->pos += length;
154
155 return length;
156 }
157
dfs_romfs_lseek(struct dfs_fd * file,off_t offset)158 int dfs_romfs_lseek(struct dfs_fd *file, off_t offset)
159 {
160 if (offset <= file->size)
161 {
162 file->pos = offset;
163 return file->pos;
164 }
165
166 return -EIO;
167 }
168
dfs_romfs_close(struct dfs_fd * file)169 int dfs_romfs_close(struct dfs_fd *file)
170 {
171 file->data = NULL;
172 return RT_EOK;
173 }
174
dfs_romfs_open(struct dfs_fd * file)175 int dfs_romfs_open(struct dfs_fd *file)
176 {
177 rt_size_t size;
178 struct romfs_dirent *dirent;
179 struct romfs_dirent *root_dirent;
180 struct dfs_filesystem *fs;
181
182 fs = (struct dfs_filesystem *)file->data;
183 root_dirent = (struct romfs_dirent *)fs->data;
184
185 if (check_dirent(root_dirent) != 0)
186 return -EIO;
187
188 if (file->flags & (O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_RDWR))
189 return -EINVAL;
190
191 dirent = dfs_romfs_lookup(root_dirent, file->path, &size);
192 if (dirent == NULL)
193 return -ENOENT;
194
195 /* entry is a directory file type */
196 if (dirent->type == ROMFS_DIRENT_DIR)
197 {
198 if (!(file->flags & O_DIRECTORY))
199 return -ENOENT;
200 }
201 else
202 {
203 /* entry is a file, but open it as a directory */
204 if (file->flags & O_DIRECTORY)
205 return -ENOENT;
206 }
207
208 file->data = dirent;
209 file->size = size;
210 file->pos = 0;
211
212 return RT_EOK;
213 }
214
dfs_romfs_stat(struct dfs_filesystem * fs,const char * path,struct stat * st)215 int dfs_romfs_stat(struct dfs_filesystem *fs, const char *path, struct stat *st)
216 {
217 rt_size_t size;
218 struct romfs_dirent *dirent;
219 struct romfs_dirent *root_dirent;
220
221 root_dirent = (struct romfs_dirent *)fs->data;
222 dirent = dfs_romfs_lookup(root_dirent, path, &size);
223
224 if (dirent == NULL)
225 return -ENOENT;
226
227 st->st_dev = 0;
228 st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
229 S_IWUSR | S_IWGRP | S_IWOTH;
230
231 if (dirent->type == ROMFS_DIRENT_DIR)
232 {
233 st->st_mode &= ~S_IFREG;
234 st->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
235 }
236
237 st->st_size = dirent->size;
238 st->st_mtime = 0;
239
240 return RT_EOK;
241 }
242
dfs_romfs_getdents(struct dfs_fd * file,struct dirent * dirp,uint32_t count)243 int dfs_romfs_getdents(struct dfs_fd *file, struct dirent *dirp, uint32_t count)
244 {
245 rt_size_t index;
246 const char *name;
247 struct dirent *d;
248 struct romfs_dirent *dirent, *sub_dirent;
249
250 dirent = (struct romfs_dirent *)file->data;
251 if (check_dirent(dirent) != 0)
252 return -EIO;
253 RT_ASSERT(dirent->type == ROMFS_DIRENT_DIR);
254
255 /* enter directory */
256 dirent = (struct romfs_dirent *)dirent->data;
257
258 /* make integer count */
259 count = (count / sizeof(struct dirent));
260 if (count == 0)
261 return -EINVAL;
262
263 index = 0;
264 for (index = 0; index < count && file->pos < file->size; index ++)
265 {
266 d = dirp + index;
267
268 sub_dirent = &dirent[file->pos];
269 name = sub_dirent->name;
270
271 /* fill dirent */
272 if (sub_dirent->type == ROMFS_DIRENT_DIR)
273 d->d_type = DT_DIR;
274 else
275 d->d_type = DT_REG;
276
277 d->d_namlen = rt_strlen(name);
278 d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
279 rt_strncpy(d->d_name, name, rt_strlen(name) + 1);
280
281 /* move to next position */
282 ++ file->pos;
283 }
284
285 return index * sizeof(struct dirent);
286 }
287
288 static const struct dfs_file_ops _rom_fops =
289 {
290 dfs_romfs_open,
291 dfs_romfs_close,
292 dfs_romfs_ioctl,
293 dfs_romfs_read,
294 NULL,
295 NULL,
296 dfs_romfs_lseek,
297 dfs_romfs_getdents,
298 };
299 static const struct dfs_filesystem_ops _romfs =
300 {
301 "rom",
302 DFS_FS_FLAG_DEFAULT,
303 &_rom_fops,
304
305 dfs_romfs_mount,
306 dfs_romfs_unmount,
307 NULL,
308 NULL,
309
310 NULL,
311 dfs_romfs_stat,
312 NULL,
313 };
314
dfs_romfs_init(void)315 int dfs_romfs_init(void)
316 {
317 /* register rom file system */
318 dfs_register(&_romfs);
319 return 0;
320 }
321 INIT_COMPONENT_EXPORT(dfs_romfs_init);
322
323