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 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 35 int dfs_ramfs_unmount(struct dfs_filesystem *fs) 36 { 37 fs->data = NULL; 38 39 return RT_EOK; 40 } 41 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 57 int dfs_ramfs_ioctl(struct dfs_fd *file, int cmd, void *args) 58 { 59 return -EIO; 60 } 61 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 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 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 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 166 int dfs_ramfs_close(struct dfs_fd *file) 167 { 168 file->data = NULL; 169 170 return RT_EOK; 171 } 172 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 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 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 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 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 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 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