dfs_ramfs.c 10.4 KB
Newer Older
B
Bernard Xiong 已提交
1
/*
2
 * Copyright (c) 2006-2021, RT-Thread Development Team
B
Bernard Xiong 已提交
3
 *
4
 * SPDX-License-Identifier: Apache-2.0
B
Bernard Xiong 已提交
5 6 7 8 9
 *
 * Change Logs:
 * Date           Author       Notes
 * 2013-04-15     Bernard      the first version
 * 2013-05-05     Bernard      remove CRC for ramfs persistence
B
Bernard Xiong 已提交
10
 * 2013-05-22     Bernard      fix the no entry issue.
B
Bernard Xiong 已提交
11 12 13 14 15
 */

#include <rtthread.h>
#include <dfs.h>
#include <dfs_fs.h>
B
bernard 已提交
16 17
#include <dfs_file.h>

B
Bernard Xiong 已提交
18 19
#include "dfs_ramfs.h"

Y
yiyue.fang 已提交
20 21 22
int dfs_ramfs_mount(struct dfs_filesystem *fs,
                    unsigned long          rwflag,
                    const void            *data)
B
Bernard Xiong 已提交
23
{
24
    struct dfs_ramfs *ramfs;
B
Bernard Xiong 已提交
25

B
bernard 已提交
26 27
    if (data == NULL)
        return -EIO;
B
Bernard Xiong 已提交
28

29
    ramfs = (struct dfs_ramfs *)data;
B
Bernard Xiong 已提交
30
    fs->data = ramfs;
31

B
bernard 已提交
32
    return RT_EOK;
B
Bernard Xiong 已提交
33 34 35 36
}

int dfs_ramfs_unmount(struct dfs_filesystem *fs)
{
B
bernard 已提交
37
    fs->data = NULL;
38

B
bernard 已提交
39
    return RT_EOK;
B
Bernard Xiong 已提交
40 41 42 43 44 45 46
}

int dfs_ramfs_statfs(struct dfs_filesystem *fs, struct statfs *buf)
{
    struct dfs_ramfs *ramfs;

    ramfs = (struct dfs_ramfs *)fs->data;
B
bernard 已提交
47 48
    RT_ASSERT(ramfs != NULL);
    RT_ASSERT(buf != NULL);
B
Bernard Xiong 已提交
49

50
    buf->f_bsize  = 512;
51 52
    buf->f_blocks = ramfs->memheap.pool_size / 512;
    buf->f_bfree  = ramfs->memheap.available_size / 512;
B
Bernard Xiong 已提交
53

B
bernard 已提交
54
    return RT_EOK;
B
Bernard Xiong 已提交
55 56 57 58
}

int dfs_ramfs_ioctl(struct dfs_fd *file, int cmd, void *args)
{
B
bernard 已提交
59
    return -EIO;
B
Bernard Xiong 已提交
60 61
}

Y
yiyue.fang 已提交
62 63 64
struct ramfs_dirent *dfs_ramfs_lookup(struct dfs_ramfs *ramfs,
                                      const char       *path,
                                      rt_size_t        *size)
B
Bernard Xiong 已提交
65 66 67 68 69
{
    const char *subpath;
    struct ramfs_dirent *dirent;

    subpath = path;
70 71
    while (*subpath == '/' && *subpath)
        subpath ++;
B
Bernard Xiong 已提交
72 73 74
    if (! *subpath) /* is root directory */
    {
        *size = 0;
Y
yiyue.fang 已提交
75

B
Bernard Xiong 已提交
76 77 78 79
        return &(ramfs->root);
    }

    for (dirent = rt_list_entry(ramfs->root.list.next, struct ramfs_dirent, list);
Y
yiyue.fang 已提交
80 81
         dirent != &(ramfs->root);
         dirent = rt_list_entry(dirent->list.next, struct ramfs_dirent, list))
B
Bernard Xiong 已提交
82 83 84 85
    {
        if (rt_strcmp(dirent->name, subpath) == 0)
        {
            *size = dirent->size;
Y
yiyue.fang 已提交
86

B
Bernard Xiong 已提交
87 88 89 90 91
            return dirent;
        }
    }

    /* not found */
B
bernard 已提交
92
    return NULL;
B
Bernard Xiong 已提交
93 94
}

B
bernard 已提交
95
int dfs_ramfs_read(struct dfs_fd *file, void *buf, size_t count)
B
Bernard Xiong 已提交
96 97 98 99 100
{
    rt_size_t length;
    struct ramfs_dirent *dirent;

    dirent = (struct ramfs_dirent *)file->data;
B
bernard 已提交
101
    RT_ASSERT(dirent != NULL);
B
Bernard Xiong 已提交
102 103 104 105 106 107 108

    if (count < file->size - file->pos)
        length = count;
    else
        length = file->size - file->pos;

    if (length > 0)
109
        rt_memcpy(buf, &(dirent->data[file->pos]), length);
B
Bernard Xiong 已提交
110 111 112 113 114 115 116

    /* update file current position */
    file->pos += length;

    return length;
}

B
bernard 已提交
117
int dfs_ramfs_write(struct dfs_fd *fd, const void *buf, size_t count)
B
Bernard Xiong 已提交
118 119 120 121
{
    struct ramfs_dirent *dirent;
    struct dfs_ramfs *ramfs;

122
    dirent = (struct ramfs_dirent *)fd->data;
B
bernard 已提交
123
    RT_ASSERT(dirent != NULL);
B
Bernard Xiong 已提交
124

B
bernard 已提交
125 126 127
    ramfs = dirent->fs;
    RT_ASSERT(ramfs != NULL);

B
Bernard Xiong 已提交
128 129 130 131
    if (count + fd->pos > fd->size)
    {
        rt_uint8_t *ptr;
        ptr = rt_memheap_realloc(&(ramfs->memheap), dirent->data, fd->pos + count);
B
bernard 已提交
132
        if (ptr == NULL)
B
Bernard Xiong 已提交
133
        {
B
bernard 已提交
134
            rt_set_errno(-ENOMEM);
Y
yiyue.fang 已提交
135

B
Bernard Xiong 已提交
136 137 138 139 140 141 142 143 144 145
            return 0;
        }

        /* update dirent and file size */
        dirent->data = ptr;
        dirent->size = fd->pos + count;
        fd->size = dirent->size;
    }

    if (count > 0)
146
        rt_memcpy(dirent->data + fd->pos, buf, count);
B
Bernard Xiong 已提交
147 148 149 150 151 152 153

    /* update file current position */
    fd->pos += count;

    return count;
}

B
bernard 已提交
154
int dfs_ramfs_lseek(struct dfs_fd *file, off_t offset)
B
Bernard Xiong 已提交
155
{
B
bernard 已提交
156
    if (offset <= (off_t)file->size)
B
Bernard Xiong 已提交
157 158
    {
        file->pos = offset;
Y
yiyue.fang 已提交
159

B
Bernard Xiong 已提交
160 161 162
        return file->pos;
    }

B
bernard 已提交
163
    return -EIO;
B
Bernard Xiong 已提交
164 165 166 167
}

int dfs_ramfs_close(struct dfs_fd *file)
{
B
bernard 已提交
168
    file->data = NULL;
Y
yiyue.fang 已提交
169

B
bernard 已提交
170
    return RT_EOK;
B
Bernard Xiong 已提交
171 172 173 174 175 176 177
}

int dfs_ramfs_open(struct dfs_fd *file)
{
    rt_size_t size;
    struct dfs_ramfs *ramfs;
    struct ramfs_dirent *dirent;
lymzzyh's avatar
lymzzyh 已提交
178 179 180
    struct dfs_filesystem *fs;

    fs = (struct dfs_filesystem *)file->data;
B
Bernard Xiong 已提交
181

lymzzyh's avatar
lymzzyh 已提交
182
    ramfs = (struct dfs_ramfs *)fs->data;
B
bernard 已提交
183
    RT_ASSERT(ramfs != NULL);
B
Bernard Xiong 已提交
184

B
bernard 已提交
185
    if (file->flags & O_DIRECTORY)
B
Bernard Xiong 已提交
186
    {
B
bernard 已提交
187
        if (file->flags & O_CREAT)
B
Bernard Xiong 已提交
188
        {
B
bernard 已提交
189
            return -ENOSPC;
B
Bernard Xiong 已提交
190 191 192 193
        }

        /* open directory */
        dirent = dfs_ramfs_lookup(ramfs, file->path, &size);
B
bernard 已提交
194 195
        if (dirent == NULL)
            return -ENOENT;
B
Bernard Xiong 已提交
196 197
        if (dirent == &(ramfs->root)) /* it's root directory */
        {
B
bernard 已提交
198
            if (!(file->flags & O_DIRECTORY))
B
Bernard Xiong 已提交
199
            {
B
bernard 已提交
200
                return -ENOENT;
B
Bernard Xiong 已提交
201 202 203 204 205 206 207 208
            }
        }
    }
    else
    {
        dirent = dfs_ramfs_lookup(ramfs, file->path, &size);
        if (dirent == &(ramfs->root)) /* it's root directory */
        {
B
bernard 已提交
209
            return -ENOENT;
B
Bernard Xiong 已提交
210 211
        }

B
bernard 已提交
212
        if (dirent == NULL)
B
Bernard Xiong 已提交
213
        {
B
bernard 已提交
214
            if (file->flags & O_CREAT || file->flags & O_WRONLY)
B
Bernard Xiong 已提交
215 216 217 218
            {
                char *name_ptr;

                /* create a file entry */
219 220 221
                dirent = (struct ramfs_dirent *)
                         rt_memheap_alloc(&(ramfs->memheap),
                                          sizeof(struct ramfs_dirent));
B
bernard 已提交
222
                if (dirent == NULL)
B
Bernard Xiong 已提交
223
                {
B
bernard 已提交
224
                    return -ENOMEM;
B
Bernard Xiong 已提交
225 226 227 228
                }

                /* remove '/' separator */
                name_ptr = file->path;
Y
yiyue.fang 已提交
229 230
                while (*name_ptr == '/' && *name_ptr)
                    name_ptr ++;
B
Bernard Xiong 已提交
231 232 233
                strncpy(dirent->name, name_ptr, RAMFS_NAME_MAX);

                rt_list_init(&(dirent->list));
B
bernard 已提交
234
                dirent->data = NULL;
B
Bernard Xiong 已提交
235
                dirent->size = 0;
B
bernard 已提交
236 237
                dirent->fs = ramfs;

B
Bernard Xiong 已提交
238 239 240
                /* add to the root directory */
                rt_list_insert_after(&(ramfs->root.list), &(dirent->list));
            }
Y
yiyue.fang 已提交
241
            else
B
bernard 已提交
242
                return -ENOENT;
B
Bernard Xiong 已提交
243 244
        }

245 246 247
        /* Creates a new file.
         * If the file is existing, it is truncated and overwritten.
         */
B
bernard 已提交
248
        if (file->flags & O_TRUNC)
B
Bernard Xiong 已提交
249 250
        {
            dirent->size = 0;
B
bernard 已提交
251
            if (dirent->data != NULL)
B
Bernard Xiong 已提交
252 253
            {
                rt_memheap_free(dirent->data);
B
bernard 已提交
254
                dirent->data = NULL;
B
Bernard Xiong 已提交
255 256 257 258 259 260
            }
        }
    }

    file->data = dirent;
    file->size = dirent->size;
B
bernard 已提交
261 262
    if (file->flags & O_APPEND)
        file->pos = file->size;
263
    else
B
bernard 已提交
264
        file->pos = 0;
B
Bernard Xiong 已提交
265

B
bernard 已提交
266
    return 0;
B
Bernard Xiong 已提交
267 268
}

269 270 271
int dfs_ramfs_stat(struct dfs_filesystem *fs,
                   const char            *path,
                   struct stat           *st)
B
Bernard Xiong 已提交
272 273 274 275 276 277 278 279
{
    rt_size_t size;
    struct ramfs_dirent *dirent;
    struct dfs_ramfs *ramfs;

    ramfs = (struct dfs_ramfs *)fs->data;
    dirent = dfs_ramfs_lookup(ramfs, path, &size);

B
bernard 已提交
280 281
    if (dirent == NULL)
        return -ENOENT;
B
Bernard Xiong 已提交
282 283

    st->st_dev = 0;
B
bernard 已提交
284 285
    st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
                  S_IWUSR | S_IWGRP | S_IWOTH;
B
Bernard Xiong 已提交
286 287 288 289

    st->st_size = dirent->size;
    st->st_mtime = 0;

B
bernard 已提交
290
    return RT_EOK;
B
Bernard Xiong 已提交
291 292
}

293 294
int dfs_ramfs_getdents(struct dfs_fd *file,
                       struct dirent *dirp,
B
bernard 已提交
295
                       uint32_t    count)
B
Bernard Xiong 已提交
296 297 298 299
{
    rt_size_t index, end;
    struct dirent *d;
    struct ramfs_dirent *dirent;
300
    struct dfs_ramfs *ramfs;
B
Bernard Xiong 已提交
301 302 303

    dirent = (struct ramfs_dirent *)file->data;

B
bernard 已提交
304 305 306
    ramfs  = dirent->fs;
    RT_ASSERT(ramfs != RT_NULL);

B
bernard 已提交
307 308 309
    if (dirent != &(ramfs->root))
        return -EINVAL;

B
Bernard Xiong 已提交
310 311
    /* make integer count */
    count = (count / sizeof(struct dirent));
312
    if (count == 0)
B
bernard 已提交
313
        return -EINVAL;
B
Bernard Xiong 已提交
314 315 316 317 318

    end = file->pos + count;
    index = 0;
    count = 0;
    for (dirent = rt_list_entry(dirent->list.next, struct ramfs_dirent, list);
Y
yiyue.fang 已提交
319 320
         dirent != &(ramfs->root) && index < end;
         dirent = rt_list_entry(dirent->list.next, struct ramfs_dirent, list))
B
Bernard Xiong 已提交
321 322 323 324
    {
        if (index >= (rt_size_t)file->pos)
        {
            d = dirp + count;
B
bernard 已提交
325
            d->d_type = DT_REG;
B
Bernard Xiong 已提交
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
            d->d_namlen = RT_NAME_MAX;
            d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
            rt_strncpy(d->d_name, dirent->name, RAMFS_NAME_MAX);

            count += 1;
            file->pos += 1;
        }
        index += 1;
    }

    return count * sizeof(struct dirent);
}

int dfs_ramfs_unlink(struct dfs_filesystem *fs, const char *path)
{
    rt_size_t size;
    struct dfs_ramfs *ramfs;
    struct ramfs_dirent *dirent;

    ramfs = (struct dfs_ramfs *)fs->data;
B
bernard 已提交
346
    RT_ASSERT(ramfs != NULL);
B
Bernard Xiong 已提交
347 348

    dirent = dfs_ramfs_lookup(ramfs, path, &size);
B
bernard 已提交
349 350
    if (dirent == NULL)
        return -ENOENT;
B
Bernard Xiong 已提交
351 352

    rt_list_remove(&(dirent->list));
B
bernard 已提交
353
    if (dirent->data != NULL)
B
Bernard Xiong 已提交
354 355 356
        rt_memheap_free(dirent->data);
    rt_memheap_free(dirent);

B
bernard 已提交
357
    return RT_EOK;
B
Bernard Xiong 已提交
358 359
}

Y
yiyue.fang 已提交
360 361 362
int dfs_ramfs_rename(struct dfs_filesystem *fs,
                     const char            *oldpath,
                     const char            *newpath)
B
Bernard Xiong 已提交
363 364 365 366 367 368
{
    struct ramfs_dirent *dirent;
    struct dfs_ramfs *ramfs;
    rt_size_t size;

    ramfs = (struct dfs_ramfs *)fs->data;
B
bernard 已提交
369
    RT_ASSERT(ramfs != NULL);
B
Bernard Xiong 已提交
370 371

    dirent = dfs_ramfs_lookup(ramfs, newpath, &size);
B
bernard 已提交
372 373
    if (dirent != NULL)
        return -EEXIST;
B
Bernard Xiong 已提交
374 375

    dirent = dfs_ramfs_lookup(ramfs, oldpath, &size);
B
bernard 已提交
376 377
    if (dirent == NULL)
        return -ENOENT;
B
Bernard Xiong 已提交
378 379 380

    strncpy(dirent->name, newpath, RAMFS_NAME_MAX);

B
bernard 已提交
381
    return RT_EOK;
B
Bernard Xiong 已提交
382 383
}

384
static const struct dfs_file_ops _ram_fops =
B
Bernard Xiong 已提交
385 386 387 388 389 390
{
    dfs_ramfs_open,
    dfs_ramfs_close,
    dfs_ramfs_ioctl,
    dfs_ramfs_read,
    dfs_ramfs_write,
B
bernard 已提交
391
    NULL, /* flush */
B
Bernard Xiong 已提交
392 393
    dfs_ramfs_lseek,
    dfs_ramfs_getdents,
B
bernard 已提交
394 395 396 397 398 399 400 401 402 403 404 405 406
};

static const struct dfs_filesystem_ops _ramfs =
{
    "ram",
    DFS_FS_FLAG_DEFAULT,
    &_ram_fops,

    dfs_ramfs_mount,
    dfs_ramfs_unmount,
    NULL, /* mkfs */
    dfs_ramfs_statfs,

B
Bernard Xiong 已提交
407 408 409 410 411 412 413 414 415
    dfs_ramfs_unlink,
    dfs_ramfs_stat,
    dfs_ramfs_rename,
};

int dfs_ramfs_init(void)
{
    /* register ram file system */
    dfs_register(&_ramfs);
Y
yiyue.fang 已提交
416

B
Bernard Xiong 已提交
417 418
    return 0;
}
419
INIT_COMPONENT_EXPORT(dfs_ramfs_init);
B
Bernard Xiong 已提交
420

421
struct dfs_ramfs *dfs_ramfs_create(rt_uint8_t *pool, rt_size_t size)
B
Bernard Xiong 已提交
422 423 424 425 426
{
    struct dfs_ramfs *ramfs;
    rt_uint8_t *data_ptr;
    rt_err_t result;

427 428
    size  = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
    ramfs = (struct dfs_ramfs *)pool;
B
Bernard Xiong 已提交
429 430 431 432 433 434

    data_ptr = (rt_uint8_t *)(ramfs + 1);
    size = size - sizeof(struct dfs_ramfs);
    size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);

    result = rt_memheap_init(&ramfs->memheap, "ramfs", data_ptr, size);
Y
yiyue.fang 已提交
435
    if (result != RT_EOK)
B
bernard 已提交
436
        return NULL;
Y
yiyue.fang 已提交
437
    /* detach this memheap object from the system */
438
    rt_object_detach((rt_object_t) & (ramfs->memheap));
B
Bernard Xiong 已提交
439 440 441

    /* initialize ramfs object */
    ramfs->magic = RAMFS_MAGIC;
442
    ramfs->memheap.parent.type = RT_Object_Class_MemHeap | RT_Object_Class_Static;
B
Bernard Xiong 已提交
443 444

    /* initialize root directory */
445
    rt_memset(&(ramfs->root), 0x00, sizeof(ramfs->root));
B
Bernard Xiong 已提交
446 447 448
    rt_list_init(&(ramfs->root.list));
    ramfs->root.size = 0;
    strcpy(ramfs->root.name, ".");
lymzzyh's avatar
lymzzyh 已提交
449
    ramfs->root.fs = ramfs;
B
Bernard Xiong 已提交
450 451 452

    return ramfs;
}
B
bernard 已提交
453