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