xref: /nrf52832-nimble/rt-thread/components/dfs/filesystems/ramfs/dfs_ramfs.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  * 2013-04-15     Bernard      the first version
9  * 2013-05-05     Bernard      remove CRC for ramfs persistence
10  * 2013-05-22     Bernard      fix the no entry issue.
11  */
12 
13 #include <rtthread.h>
14 #include <dfs.h>
15 #include <dfs_fs.h>
16 #include <dfs_file.h>
17 
18 #include "dfs_ramfs.h"
19 
dfs_ramfs_mount(struct dfs_filesystem * fs,unsigned long rwflag,const void * data)20 int dfs_ramfs_mount(struct dfs_filesystem *fs,
21                     unsigned long          rwflag,
22                     const void            *data)
23 {
24     struct dfs_ramfs* ramfs;
25 
26     if (data == NULL)
27         return -EIO;
28 
29     ramfs = (struct dfs_ramfs *)data;
30     fs->data = ramfs;
31 
32     return RT_EOK;
33 }
34 
dfs_ramfs_unmount(struct dfs_filesystem * fs)35 int dfs_ramfs_unmount(struct dfs_filesystem *fs)
36 {
37     fs->data = NULL;
38 
39     return RT_EOK;
40 }
41 
dfs_ramfs_statfs(struct dfs_filesystem * fs,struct statfs * buf)42 int dfs_ramfs_statfs(struct dfs_filesystem *fs, struct statfs *buf)
43 {
44     struct dfs_ramfs *ramfs;
45 
46     ramfs = (struct dfs_ramfs *)fs->data;
47     RT_ASSERT(ramfs != NULL);
48     RT_ASSERT(buf != NULL);
49 
50     buf->f_bsize  = 512;
51     buf->f_blocks = ramfs->memheap.pool_size/512;
52     buf->f_bfree  = ramfs->memheap.available_size/512;
53 
54     return RT_EOK;
55 }
56 
dfs_ramfs_ioctl(struct dfs_fd * file,int cmd,void * args)57 int dfs_ramfs_ioctl(struct dfs_fd *file, int cmd, void *args)
58 {
59     return -EIO;
60 }
61 
dfs_ramfs_lookup(struct dfs_ramfs * ramfs,const char * path,rt_size_t * size)62 struct ramfs_dirent *dfs_ramfs_lookup(struct dfs_ramfs *ramfs,
63                                       const char       *path,
64                                       rt_size_t        *size)
65 {
66     const char *subpath;
67     struct ramfs_dirent *dirent;
68 
69     subpath = path;
70     while (*subpath == '/' && *subpath)
71         subpath ++;
72     if (! *subpath) /* is root directory */
73     {
74         *size = 0;
75 
76         return &(ramfs->root);
77     }
78 
79     for (dirent = rt_list_entry(ramfs->root.list.next, struct ramfs_dirent, list);
80          dirent != &(ramfs->root);
81          dirent = rt_list_entry(dirent->list.next, struct ramfs_dirent, list))
82     {
83         if (rt_strcmp(dirent->name, subpath) == 0)
84         {
85             *size = dirent->size;
86 
87             return dirent;
88         }
89     }
90 
91     /* not found */
92     return NULL;
93 }
94 
dfs_ramfs_read(struct dfs_fd * file,void * buf,size_t count)95 int dfs_ramfs_read(struct dfs_fd *file, void *buf, size_t count)
96 {
97     rt_size_t length;
98     struct ramfs_dirent *dirent;
99 
100     dirent = (struct ramfs_dirent *)file->data;
101     RT_ASSERT(dirent != NULL);
102 
103     if (count < file->size - file->pos)
104         length = count;
105     else
106         length = file->size - file->pos;
107 
108     if (length > 0)
109         memcpy(buf, &(dirent->data[file->pos]), length);
110 
111     /* update file current position */
112     file->pos += length;
113 
114     return length;
115 }
116 
dfs_ramfs_write(struct dfs_fd * fd,const void * buf,size_t count)117 int dfs_ramfs_write(struct dfs_fd *fd, const void *buf, size_t count)
118 {
119     struct ramfs_dirent *dirent;
120     struct dfs_ramfs *ramfs;
121 
122     dirent = (struct ramfs_dirent*)fd->data;
123     RT_ASSERT(dirent != NULL);
124 
125     ramfs = dirent->fs;
126     RT_ASSERT(ramfs != NULL);
127 
128     if (count + fd->pos > fd->size)
129     {
130         rt_uint8_t *ptr;
131         ptr = rt_memheap_realloc(&(ramfs->memheap), dirent->data, fd->pos + count);
132         if (ptr == NULL)
133         {
134             rt_set_errno(-ENOMEM);
135 
136             return 0;
137         }
138 
139         /* update dirent and file size */
140         dirent->data = ptr;
141         dirent->size = fd->pos + count;
142         fd->size = dirent->size;
143     }
144 
145     if (count > 0)
146         memcpy(dirent->data + fd->pos, buf, count);
147 
148     /* update file current position */
149     fd->pos += count;
150 
151     return count;
152 }
153 
dfs_ramfs_lseek(struct dfs_fd * file,off_t offset)154 int dfs_ramfs_lseek(struct dfs_fd *file, off_t offset)
155 {
156     if (offset <= (off_t)file->size)
157     {
158         file->pos = offset;
159 
160         return file->pos;
161     }
162 
163     return -EIO;
164 }
165 
dfs_ramfs_close(struct dfs_fd * file)166 int dfs_ramfs_close(struct dfs_fd *file)
167 {
168     file->data = NULL;
169 
170     return RT_EOK;
171 }
172 
dfs_ramfs_open(struct dfs_fd * file)173 int dfs_ramfs_open(struct dfs_fd *file)
174 {
175     rt_size_t size;
176     struct dfs_ramfs *ramfs;
177     struct ramfs_dirent *dirent;
178     struct dfs_filesystem *fs;
179 
180     fs = (struct dfs_filesystem *)file->data;
181 
182     ramfs = (struct dfs_ramfs *)fs->data;
183     RT_ASSERT(ramfs != NULL);
184 
185     if (file->flags & O_DIRECTORY)
186     {
187         if (file->flags & O_CREAT)
188         {
189             return -ENOSPC;
190         }
191 
192         /* open directory */
193         dirent = dfs_ramfs_lookup(ramfs, file->path, &size);
194         if (dirent == NULL)
195             return -ENOENT;
196         if (dirent == &(ramfs->root)) /* it's root directory */
197         {
198             if (!(file->flags & O_DIRECTORY))
199             {
200                 return -ENOENT;
201             }
202         }
203     }
204     else
205     {
206         dirent = dfs_ramfs_lookup(ramfs, file->path, &size);
207         if (dirent == &(ramfs->root)) /* it's root directory */
208         {
209             return -ENOENT;
210         }
211 
212         if (dirent == NULL)
213         {
214             if (file->flags & O_CREAT || file->flags & O_WRONLY)
215             {
216                 char *name_ptr;
217 
218                 /* create a file entry */
219                 dirent = (struct ramfs_dirent *)
220                          rt_memheap_alloc(&(ramfs->memheap),
221                                           sizeof(struct ramfs_dirent));
222                 if (dirent == NULL)
223                 {
224                     return -ENOMEM;
225                 }
226 
227                 /* remove '/' separator */
228                 name_ptr = file->path;
229                 while (*name_ptr == '/' && *name_ptr)
230                     name_ptr ++;
231                 strncpy(dirent->name, name_ptr, RAMFS_NAME_MAX);
232 
233                 rt_list_init(&(dirent->list));
234                 dirent->data = NULL;
235                 dirent->size = 0;
236                 dirent->fs = ramfs;
237 
238                 /* add to the root directory */
239                 rt_list_insert_after(&(ramfs->root.list), &(dirent->list));
240             }
241             else
242                 return -ENOENT;
243         }
244 
245         /* Creates a new file.
246          * If the file is existing, it is truncated and overwritten.
247          */
248         if (file->flags & O_TRUNC)
249         {
250             dirent->size = 0;
251             if (dirent->data != NULL)
252             {
253                 rt_memheap_free(dirent->data);
254                 dirent->data = NULL;
255             }
256         }
257     }
258 
259     file->data = dirent;
260     file->size = dirent->size;
261     if (file->flags & O_APPEND)
262         file->pos = file->size;
263     else
264         file->pos = 0;
265 
266     return 0;
267 }
268 
dfs_ramfs_stat(struct dfs_filesystem * fs,const char * path,struct stat * st)269 int dfs_ramfs_stat(struct dfs_filesystem *fs,
270                    const char            *path,
271                    struct stat           *st)
272 {
273     rt_size_t size;
274     struct ramfs_dirent *dirent;
275     struct dfs_ramfs *ramfs;
276 
277     ramfs = (struct dfs_ramfs *)fs->data;
278     dirent = dfs_ramfs_lookup(ramfs, path, &size);
279 
280     if (dirent == NULL)
281         return -ENOENT;
282 
283     st->st_dev = 0;
284     st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
285                   S_IWUSR | S_IWGRP | S_IWOTH;
286 
287     st->st_size = dirent->size;
288     st->st_mtime = 0;
289 
290     return RT_EOK;
291 }
292 
dfs_ramfs_getdents(struct dfs_fd * file,struct dirent * dirp,uint32_t count)293 int dfs_ramfs_getdents(struct dfs_fd *file,
294                        struct dirent *dirp,
295                        uint32_t    count)
296 {
297     rt_size_t index, end;
298     struct dirent *d;
299     struct ramfs_dirent *dirent;
300     struct dfs_ramfs *ramfs;
301 
302     dirent = (struct ramfs_dirent *)file->data;
303 
304     ramfs  = dirent->fs;
305     RT_ASSERT(ramfs != RT_NULL);
306 
307     if (dirent != &(ramfs->root))
308         return -EINVAL;
309 
310     /* make integer count */
311     count = (count / sizeof(struct dirent));
312     if (count == 0)
313         return -EINVAL;
314 
315     end = file->pos + count;
316     index = 0;
317     count = 0;
318     for (dirent = rt_list_entry(dirent->list.next, struct ramfs_dirent, list);
319          dirent != &(ramfs->root) && index < end;
320          dirent = rt_list_entry(dirent->list.next, struct ramfs_dirent, list))
321     {
322         if (index >= (rt_size_t)file->pos)
323         {
324             d = dirp + count;
325             d->d_type = DT_REG;
326             d->d_namlen = RT_NAME_MAX;
327             d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
328             rt_strncpy(d->d_name, dirent->name, RAMFS_NAME_MAX);
329 
330             count += 1;
331             file->pos += 1;
332         }
333         index += 1;
334     }
335 
336     return count * sizeof(struct dirent);
337 }
338 
dfs_ramfs_unlink(struct dfs_filesystem * fs,const char * path)339 int dfs_ramfs_unlink(struct dfs_filesystem *fs, const char *path)
340 {
341     rt_size_t size;
342     struct dfs_ramfs *ramfs;
343     struct ramfs_dirent *dirent;
344 
345     ramfs = (struct dfs_ramfs *)fs->data;
346     RT_ASSERT(ramfs != NULL);
347 
348     dirent = dfs_ramfs_lookup(ramfs, path, &size);
349     if (dirent == NULL)
350         return -ENOENT;
351 
352     rt_list_remove(&(dirent->list));
353     if (dirent->data != NULL)
354         rt_memheap_free(dirent->data);
355     rt_memheap_free(dirent);
356 
357     return RT_EOK;
358 }
359 
dfs_ramfs_rename(struct dfs_filesystem * fs,const char * oldpath,const char * newpath)360 int dfs_ramfs_rename(struct dfs_filesystem *fs,
361                      const char            *oldpath,
362                      const char            *newpath)
363 {
364     struct ramfs_dirent *dirent;
365     struct dfs_ramfs *ramfs;
366     rt_size_t size;
367 
368     ramfs = (struct dfs_ramfs *)fs->data;
369     RT_ASSERT(ramfs != NULL);
370 
371     dirent = dfs_ramfs_lookup(ramfs, newpath, &size);
372     if (dirent != NULL)
373         return -EEXIST;
374 
375     dirent = dfs_ramfs_lookup(ramfs, oldpath, &size);
376     if (dirent == NULL)
377         return -ENOENT;
378 
379     strncpy(dirent->name, newpath, RAMFS_NAME_MAX);
380 
381     return RT_EOK;
382 }
383 
384 static const struct dfs_file_ops _ram_fops =
385 {
386     dfs_ramfs_open,
387     dfs_ramfs_close,
388     dfs_ramfs_ioctl,
389     dfs_ramfs_read,
390     dfs_ramfs_write,
391     NULL, /* flush */
392     dfs_ramfs_lseek,
393     dfs_ramfs_getdents,
394 };
395 
396 static const struct dfs_filesystem_ops _ramfs =
397 {
398     "ram",
399     DFS_FS_FLAG_DEFAULT,
400     &_ram_fops,
401 
402     dfs_ramfs_mount,
403     dfs_ramfs_unmount,
404     NULL, /* mkfs */
405     dfs_ramfs_statfs,
406 
407     dfs_ramfs_unlink,
408     dfs_ramfs_stat,
409     dfs_ramfs_rename,
410 };
411 
dfs_ramfs_init(void)412 int dfs_ramfs_init(void)
413 {
414     /* register ram file system */
415     dfs_register(&_ramfs);
416 
417     return 0;
418 }
419 INIT_COMPONENT_EXPORT(dfs_ramfs_init);
420 
dfs_ramfs_create(rt_uint8_t * pool,rt_size_t size)421 struct dfs_ramfs* dfs_ramfs_create(rt_uint8_t *pool, rt_size_t size)
422 {
423     struct dfs_ramfs *ramfs;
424     rt_uint8_t *data_ptr;
425     rt_err_t result;
426 
427     size  = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
428     ramfs = (struct dfs_ramfs *)pool;
429 
430     data_ptr = (rt_uint8_t *)(ramfs + 1);
431     size = size - sizeof(struct dfs_ramfs);
432     size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
433 
434     result = rt_memheap_init(&ramfs->memheap, "ramfs", data_ptr, size);
435     if (result != RT_EOK)
436         return NULL;
437     /* detach this memheap object from the system */
438     rt_object_detach((rt_object_t)&(ramfs->memheap));
439 
440     /* initialize ramfs object */
441     ramfs->magic = RAMFS_MAGIC;
442     ramfs->memheap.parent.type = RT_Object_Class_MemHeap | RT_Object_Class_Static;
443 
444     /* initialize root directory */
445     memset(&(ramfs->root), 0x00, sizeof(ramfs->root));
446     rt_list_init(&(ramfs->root.list));
447     ramfs->root.size = 0;
448     strcpy(ramfs->root.name, ".");
449     ramfs->root.fs = ramfs;
450 
451     return ramfs;
452 }
453 
454