1 /*
2 * Copyright (c) 2006-2021, 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_file * file,int cmd,void * args)57 int dfs_ramfs_ioctl(struct dfs_file *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_file * file,void * buf,size_t count)95 ssize_t dfs_ramfs_read(struct dfs_file *file, void *buf, size_t count)
96 {
97 rt_size_t length;
98 struct ramfs_dirent *dirent;
99
100 dirent = (struct ramfs_dirent *)file->vnode->data;
101 RT_ASSERT(dirent != NULL);
102
103 if (count < file->vnode->size - file->pos)
104 length = count;
105 else
106 length = file->vnode->size - file->pos;
107
108 if (length > 0)
109 rt_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_file * fd,const void * buf,size_t count)117 ssize_t dfs_ramfs_write(struct dfs_file *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->vnode->data;
123 RT_ASSERT(dirent != NULL);
124
125 ramfs = dirent->fs;
126 RT_ASSERT(ramfs != NULL);
127
128 if (count + fd->pos > fd->vnode->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->vnode->size = dirent->size;
143 }
144
145 if (count > 0)
146 rt_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_file * file,off_t offset)154 off_t dfs_ramfs_lseek(struct dfs_file *file, off_t offset)
155 {
156 if (offset <= (off_t)file->vnode->size)
157 {
158 file->pos = offset;
159
160 return file->pos;
161 }
162
163 return -EIO;
164 }
165
dfs_ramfs_close(struct dfs_file * file)166 int dfs_ramfs_close(struct dfs_file *file)
167 {
168 RT_ASSERT(file->vnode->ref_count > 0);
169 if (file->vnode->ref_count > 1)
170 {
171 return 0;
172 }
173
174 file->vnode->data = NULL;
175
176 return RT_EOK;
177 }
178
dfs_ramfs_open(struct dfs_file * file)179 int dfs_ramfs_open(struct dfs_file *file)
180 {
181 rt_size_t size;
182 struct dfs_ramfs *ramfs;
183 struct ramfs_dirent *dirent;
184 struct dfs_filesystem *fs;
185
186 RT_ASSERT(file->vnode->ref_count > 0);
187 if (file->vnode->ref_count > 1)
188 {
189 if (file->vnode->type == FT_DIRECTORY
190 && !(file->flags & O_DIRECTORY))
191 {
192 return -ENOENT;
193 }
194 file->pos = 0;
195 return 0;
196 }
197
198 fs = file->vnode->fs;
199
200 ramfs = (struct dfs_ramfs *)fs->data;
201 RT_ASSERT(ramfs != NULL);
202
203 if (file->flags & O_DIRECTORY)
204 {
205 if (file->flags & O_CREAT)
206 {
207 return -ENOSPC;
208 }
209
210 /* open directory */
211 dirent = dfs_ramfs_lookup(ramfs, file->vnode->path, &size);
212 if (dirent == NULL)
213 return -ENOENT;
214 if (dirent == &(ramfs->root)) /* it's root directory */
215 {
216 if (!(file->flags & O_DIRECTORY))
217 {
218 return -ENOENT;
219 }
220 }
221 file->vnode->type = FT_DIRECTORY;
222 }
223 else
224 {
225 dirent = dfs_ramfs_lookup(ramfs, file->vnode->path, &size);
226 if (dirent == &(ramfs->root)) /* it's root directory */
227 {
228 return -ENOENT;
229 }
230
231 if (dirent == NULL)
232 {
233 if (file->flags & O_CREAT || file->flags & O_WRONLY)
234 {
235 char *name_ptr;
236
237 /* create a file entry */
238 dirent = (struct ramfs_dirent *)
239 rt_memheap_alloc(&(ramfs->memheap),
240 sizeof(struct ramfs_dirent));
241 if (dirent == NULL)
242 {
243 return -ENOMEM;
244 }
245
246 /* remove '/' separator */
247 name_ptr = file->vnode->path;
248 while (*name_ptr == '/' && *name_ptr)
249 {
250 name_ptr++;
251 }
252 strncpy(dirent->name, name_ptr, RAMFS_NAME_MAX);
253
254 rt_list_init(&(dirent->list));
255 dirent->data = NULL;
256 dirent->size = 0;
257 dirent->fs = ramfs;
258 file->vnode->type = FT_DIRECTORY;
259
260 /* add to the root directory */
261 rt_list_insert_after(&(ramfs->root.list), &(dirent->list));
262 }
263 else
264 return -ENOENT;
265 }
266
267 /* Creates a new file.
268 * If the file is existing, it is truncated and overwritten.
269 */
270 if (file->flags & O_TRUNC)
271 {
272 dirent->size = 0;
273 if (dirent->data != NULL)
274 {
275 rt_memheap_free(dirent->data);
276 dirent->data = NULL;
277 }
278 }
279 }
280
281 file->vnode->data = dirent;
282 file->vnode->size = dirent->size;
283 if (file->flags & O_APPEND)
284 {
285 file->pos = file->vnode->size;
286 }
287 else
288 {
289 file->pos = 0;
290 }
291
292 return 0;
293 }
294
dfs_ramfs_stat(struct dfs_filesystem * fs,const char * path,struct stat * st)295 int dfs_ramfs_stat(struct dfs_filesystem *fs,
296 const char *path,
297 struct stat *st)
298 {
299 rt_size_t size;
300 struct ramfs_dirent *dirent;
301 struct dfs_ramfs *ramfs;
302
303 ramfs = (struct dfs_ramfs *)fs->data;
304 dirent = dfs_ramfs_lookup(ramfs, path, &size);
305
306 if (dirent == NULL)
307 return -ENOENT;
308
309 st->st_dev = 0;
310 st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
311 S_IWUSR | S_IWGRP | S_IWOTH;
312
313 st->st_size = dirent->size;
314 st->st_mtime = 0;
315
316 return RT_EOK;
317 }
318
dfs_ramfs_getdents(struct dfs_file * file,struct dirent * dirp,uint32_t count)319 int dfs_ramfs_getdents(struct dfs_file *file,
320 struct dirent *dirp,
321 uint32_t count)
322 {
323 rt_size_t index, end;
324 struct dirent *d;
325 struct ramfs_dirent *dirent;
326 struct dfs_ramfs *ramfs;
327
328 dirent = (struct ramfs_dirent *)file->vnode->data;
329
330 ramfs = dirent->fs;
331 RT_ASSERT(ramfs != RT_NULL);
332
333 if (dirent != &(ramfs->root))
334 return -EINVAL;
335
336 /* make integer count */
337 count = (count / sizeof(struct dirent));
338 if (count == 0)
339 return -EINVAL;
340
341 end = file->pos + count;
342 index = 0;
343 count = 0;
344 for (dirent = rt_list_entry(dirent->list.next, struct ramfs_dirent, list);
345 dirent != &(ramfs->root) && index < end;
346 dirent = rt_list_entry(dirent->list.next, struct ramfs_dirent, list))
347 {
348 if (index >= (rt_size_t)file->pos)
349 {
350 d = dirp + count;
351 d->d_type = DT_REG;
352 d->d_namlen = RT_NAME_MAX;
353 d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
354 rt_strncpy(d->d_name, dirent->name, RAMFS_NAME_MAX);
355
356 count += 1;
357 file->pos += 1;
358 }
359 index += 1;
360 }
361
362 return count * sizeof(struct dirent);
363 }
364
dfs_ramfs_unlink(struct dfs_filesystem * fs,const char * path)365 int dfs_ramfs_unlink(struct dfs_filesystem *fs, const char *path)
366 {
367 rt_size_t size;
368 struct dfs_ramfs *ramfs;
369 struct ramfs_dirent *dirent;
370
371 ramfs = (struct dfs_ramfs *)fs->data;
372 RT_ASSERT(ramfs != NULL);
373
374 dirent = dfs_ramfs_lookup(ramfs, path, &size);
375 if (dirent == NULL)
376 return -ENOENT;
377
378 rt_list_remove(&(dirent->list));
379 if (dirent->data != NULL)
380 rt_memheap_free(dirent->data);
381 rt_memheap_free(dirent);
382
383 return RT_EOK;
384 }
385
dfs_ramfs_rename(struct dfs_filesystem * fs,const char * oldpath,const char * newpath)386 int dfs_ramfs_rename(struct dfs_filesystem *fs,
387 const char *oldpath,
388 const char *newpath)
389 {
390 struct ramfs_dirent *dirent;
391 struct dfs_ramfs *ramfs;
392 rt_size_t size;
393
394 ramfs = (struct dfs_ramfs *)fs->data;
395 RT_ASSERT(ramfs != NULL);
396
397 dirent = dfs_ramfs_lookup(ramfs, newpath, &size);
398 if (dirent != NULL)
399 return -EEXIST;
400
401 dirent = dfs_ramfs_lookup(ramfs, oldpath, &size);
402 if (dirent == NULL)
403 return -ENOENT;
404
405 strncpy(dirent->name, newpath, RAMFS_NAME_MAX);
406
407 return RT_EOK;
408 }
409
410 static const struct dfs_file_ops _ram_fops =
411 {
412 dfs_ramfs_open,
413 dfs_ramfs_close,
414 dfs_ramfs_ioctl,
415 dfs_ramfs_read,
416 dfs_ramfs_write,
417 NULL, /* flush */
418 dfs_ramfs_lseek,
419 dfs_ramfs_getdents,
420 };
421
422 static const struct dfs_filesystem_ops _ramfs =
423 {
424 "ram",
425 DFS_FS_FLAG_DEFAULT,
426 &_ram_fops,
427
428 dfs_ramfs_mount,
429 dfs_ramfs_unmount,
430 NULL, /* mkfs */
431 dfs_ramfs_statfs,
432
433 dfs_ramfs_unlink,
434 dfs_ramfs_stat,
435 dfs_ramfs_rename,
436 };
437
dfs_ramfs_init(void)438 int dfs_ramfs_init(void)
439 {
440 /* register ram file system */
441 dfs_register(&_ramfs);
442
443 return 0;
444 }
445 INIT_COMPONENT_EXPORT(dfs_ramfs_init);
446
dfs_ramfs_create(rt_uint8_t * pool,rt_size_t size)447 struct dfs_ramfs *dfs_ramfs_create(rt_uint8_t *pool, rt_size_t size)
448 {
449 struct dfs_ramfs *ramfs;
450 rt_uint8_t *data_ptr;
451 rt_err_t result;
452
453 size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
454 ramfs = (struct dfs_ramfs *)pool;
455
456 data_ptr = (rt_uint8_t *)(ramfs + 1);
457 size = size - sizeof(struct dfs_ramfs);
458 size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
459
460 result = rt_memheap_init(&ramfs->memheap, "ramfs", data_ptr, size);
461 if (result != RT_EOK)
462 return NULL;
463 /* detach this memheap object from the system */
464 rt_object_detach((rt_object_t) & (ramfs->memheap));
465
466 /* initialize ramfs object */
467 ramfs->magic = RAMFS_MAGIC;
468 ramfs->memheap.parent.type = RT_Object_Class_MemHeap | RT_Object_Class_Static;
469
470 /* initialize root directory */
471 rt_memset(&(ramfs->root), 0x00, sizeof(ramfs->root));
472 rt_list_init(&(ramfs->root.list));
473 ramfs->root.size = 0;
474 strcpy(ramfs->root.name, ".");
475 ramfs->root.fs = ramfs;
476
477 return ramfs;
478 }
479
480