xref: /nrf52832-nimble/rt-thread/components/dfs/filesystems/romfs/dfs_romfs.c (revision 104654410c56c573564690304ae786df310c91fc)
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