dfs_romfs.c 8.3 KB
Newer Older
1
/*
2
 * Copyright (c) 2006-2018, RT-Thread Development Team
3
 *
4
 * SPDX-License-Identifier: Apache-2.0
5 6 7 8 9 10 11 12
 *
 * Change Logs:
 * Date           Author       Notes
 */

#include <rtthread.h>
#include <dfs.h>
#include <dfs_fs.h>
B
bernard 已提交
13 14
#include <dfs_file.h>

15 16 17 18
#include "dfs_romfs.h"

int dfs_romfs_mount(struct dfs_filesystem *fs, unsigned long rwflag, const void *data)
{
19
    struct root_data *root_data;
20

B
bernard 已提交
21 22
    if (data == NULL)
        return -EIO;
23

24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
    root_data = (struct root_data *)rt_malloc(sizeof(struct root_data));
    if (root_data)
    {
        int size = sizeof(struct romfs_dirent);
        root_data->dirent = (struct romfs_dirent *)data;
        if ((const char *)root_data->dirent->data - root_data->dirent->name != 0x04)
            root_data->offset = 0;
        else
            root_data->offset = (int)root_data->dirent->name != size ? ((long long)data - (long long)root_data->dirent->name + size) : (long long)data;
        fs->data = root_data;
    }
    else
    {
        return -RT_ENOMEM;
    }
39

B
bernard 已提交
40
    return RT_EOK;
41 42 43 44
}

int dfs_romfs_unmount(struct dfs_filesystem *fs)
{
45 46 47 48 49
    if (fs->data)
    {
        rt_free(fs->data);
    }

B
bernard 已提交
50
    return RT_EOK;
51 52 53 54
}

int dfs_romfs_ioctl(struct dfs_fd *file, int cmd, void *args)
{
B
bernard 已提交
55
    return -EIO;
56 57
}

G
Grissiom 已提交
58 59
rt_inline int check_dirent(struct romfs_dirent *dirent)
{
60 61
    if ((dirent->type != ROMFS_DIRENT_FILE && dirent->type != ROMFS_DIRENT_DIR)
        || dirent->size == ~0)
G
Grissiom 已提交
62 63 64 65
        return -1;
    return 0;
}

66
struct romfs_dirent *dfs_romfs_lookup(struct root_data *root_data, const char *path, rt_size_t *size)
67
{
B
bernard 已提交
68 69 70 71
    rt_size_t index, found;
    const char *subpath, *subpath_end;
    struct romfs_dirent *dirent;
    rt_size_t dirent_size;
72

G
Grissiom 已提交
73
    /* Check the root_dirent. */
74
    if (check_dirent(root_data->dirent) != 0)
B
bernard 已提交
75 76 77 78
        return NULL;

    if (path[0] == '/' && path[1] == '\0')
    {
79 80
        *size = root_data->dirent->size;
        return root_data->dirent;
B
bernard 已提交
81 82 83
    }

    /* goto root directy entries */
84 85
    dirent = (struct romfs_dirent *)(root_data->dirent->data + root_data->offset);
    dirent_size = root_data->dirent->size;
B
bernard 已提交
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102

    /* get the end position of this subpath */
    subpath_end = path;
    /* skip /// */
    while (*subpath_end && *subpath_end == '/')
        subpath_end ++;
    subpath = subpath_end;
    while ((*subpath_end != '/') && *subpath_end)
        subpath_end ++;

    while (dirent != NULL)
    {
        found = 0;

        /* search in folder */
        for (index = 0; index < dirent_size; index ++)
        {
G
Grissiom 已提交
103
            if (check_dirent(&dirent[index]) != 0)
B
bernard 已提交
104
                return NULL;
105 106
            if (rt_strlen(dirent[index].name + root_data->offset) == (subpath_end - subpath) &&
                    rt_strncmp(dirent[index].name + root_data->offset, subpath, (subpath_end - subpath)) == 0)
B
bernard 已提交
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
            {
                dirent_size = dirent[index].size;

                /* skip /// */
                while (*subpath_end && *subpath_end == '/')
                    subpath_end ++;
                subpath = subpath_end;
                while ((*subpath_end != '/') && *subpath_end)
                    subpath_end ++;

                if (!(*subpath))
                {
                    *size = dirent_size;
                    return &dirent[index];
                }

                if (dirent[index].type == ROMFS_DIRENT_DIR)
                {
                    /* enter directory */
126
                    dirent = (struct romfs_dirent *)(dirent[index].data + root_data->offset);
B
bernard 已提交
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
                    found = 1;
                    break;
                }
                else
                {
                    /* return file dirent */
                    if (subpath != NULL)
                        break; /* not the end of path */

                    return &dirent[index];
                }
            }
        }

        if (!found)
            break; /* not found */
    }

    /* not found */
    return NULL;
147 148
}

B
bernard 已提交
149
int dfs_romfs_read(struct dfs_fd *file, void *buf, size_t count)
150
{
B
bernard 已提交
151 152
    rt_size_t length;
    struct romfs_dirent *dirent;
153
    struct root_data *root_data;
154

155
    root_data = (struct root_data *)file->fs->data;
B
bernard 已提交
156 157
    dirent = (struct romfs_dirent *)file->data;
    RT_ASSERT(dirent != NULL);
158

G
Grissiom 已提交
159 160
    if (check_dirent(dirent) != 0)
    {
B
bernard 已提交
161
        return -EIO;
G
Grissiom 已提交
162 163
    }

B
bernard 已提交
164 165 166 167
    if (count < file->size - file->pos)
        length = count;
    else
        length = file->size - file->pos;
168

B
bernard 已提交
169
    if (length > 0)
170
        memcpy(buf, &(dirent->data[file->pos]) + root_data->offset, length);
171

B
bernard 已提交
172 173
    /* update file current position */
    file->pos += length;
174

B
bernard 已提交
175
    return length;
176 177
}

B
bernard 已提交
178
int dfs_romfs_lseek(struct dfs_fd *file, off_t offset)
179
{
B
bernard 已提交
180 181 182 183 184
    if (offset <= file->size)
    {
        file->pos = offset;
        return file->pos;
    }
185

B
bernard 已提交
186
    return -EIO;
187 188 189 190
}

int dfs_romfs_close(struct dfs_fd *file)
{
B
bernard 已提交
191 192
    file->data = NULL;
    return RT_EOK;
193 194 195 196
}

int dfs_romfs_open(struct dfs_fd *file)
{
B
bernard 已提交
197 198
    rt_size_t size;
    struct romfs_dirent *dirent;
199
    struct root_data *root_data;
200

201
    root_data = (struct root_data *)file->fs->data;
202

203
    if (check_dirent(root_data->dirent) != 0)
B
bernard 已提交
204 205 206 207 208
        return -EIO;

    if (file->flags & (O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_RDWR))
        return -EINVAL;

209
    dirent = dfs_romfs_lookup(root_data, file->path, &size);
B
bernard 已提交
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
    if (dirent == NULL)
        return -ENOENT;

    /* entry is a directory file type */
    if (dirent->type == ROMFS_DIRENT_DIR)
    {
        if (!(file->flags & O_DIRECTORY))
            return -ENOENT;
    }
    else
    {
        /* entry is a file, but open it as a directory */
        if (file->flags & O_DIRECTORY)
            return -ENOENT;
    }

    file->data = dirent;
    file->size = size;
    file->pos = 0;

    return RT_EOK;
231 232 233 234
}

int dfs_romfs_stat(struct dfs_filesystem *fs, const char *path, struct stat *st)
{
B
bernard 已提交
235 236
    rt_size_t size;
    struct romfs_dirent *dirent;
237
    struct root_data *root_data;
238

239 240
    root_data = (struct root_data *)fs->data;
    dirent = dfs_romfs_lookup(root_data, path, &size);
241

B
bernard 已提交
242 243
    if (dirent == NULL)
        return -ENOENT;
244

B
bernard 已提交
245 246
    st->st_dev = 0;
    st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
247
                  S_IWUSR | S_IWGRP | S_IWOTH;
248

B
bernard 已提交
249 250 251 252 253
    if (dirent->type == ROMFS_DIRENT_DIR)
    {
        st->st_mode &= ~S_IFREG;
        st->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
    }
254

B
bernard 已提交
255 256
    st->st_size = dirent->size;
    st->st_mtime = 0;
257

B
bernard 已提交
258
    return RT_EOK;
259 260
}

B
bernard 已提交
261
int dfs_romfs_getdents(struct dfs_fd *file, struct dirent *dirp, uint32_t count)
262
{
B
bernard 已提交
263 264 265 266
    rt_size_t index;
    const char *name;
    struct dirent *d;
    struct romfs_dirent *dirent, *sub_dirent;
267
    struct root_data *root_data;
268

269
    root_data = (struct root_data *)file->fs->data;
B
bernard 已提交
270
    dirent = (struct romfs_dirent *)file->data;
G
Grissiom 已提交
271
    if (check_dirent(dirent) != 0)
B
bernard 已提交
272 273
        return -EIO;
    RT_ASSERT(dirent->type == ROMFS_DIRENT_DIR);
274

B
bernard 已提交
275
    /* enter directory */
276
    dirent = (struct romfs_dirent *)(dirent->data + root_data->offset);
G
Grissiom 已提交
277

B
bernard 已提交
278 279 280 281
    /* make integer count */
    count = (count / sizeof(struct dirent));
    if (count == 0)
        return -EINVAL;
G
Grissiom 已提交
282

B
bernard 已提交
283 284 285 286
    index = 0;
    for (index = 0; index < count && file->pos < file->size; index ++)
    {
        d = dirp + index;
287

B
bernard 已提交
288
        sub_dirent = &dirent[file->pos];
289
        name = sub_dirent->name + root_data->offset;
290

B
bernard 已提交
291 292 293 294 295
        /* fill dirent */
        if (sub_dirent->type == ROMFS_DIRENT_DIR)
            d->d_type = DT_DIR;
        else
            d->d_type = DT_REG;
296

B
bernard 已提交
297 298 299
        d->d_namlen = rt_strlen(name);
        d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
        rt_strncpy(d->d_name, name, rt_strlen(name) + 1);
300

B
bernard 已提交
301 302 303
        /* move to next position */
        ++ file->pos;
    }
304

B
bernard 已提交
305
    return index * sizeof(struct dirent);
306 307
}

308 309 310 311 312 313 314 315 316 317 318 319
void *dfs_romfs_get(struct dfs_fd *file)
{
    struct root_data *root_data = (struct root_data *)file->fs->data;
    struct romfs_dirent *dirent = (struct romfs_dirent *)file->data;
    if (dirent)
    {
        return (void *)(&dirent->data[file->pos] + root_data->offset);
    }

    return RT_NULL;
}

B
bernard 已提交
320
static const struct dfs_file_ops _rom_fops =
321
{
B
bernard 已提交
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
    dfs_romfs_open,
    dfs_romfs_close,
    dfs_romfs_ioctl,
    dfs_romfs_read,
    NULL,
    NULL,
    dfs_romfs_lseek,
    dfs_romfs_getdents,
};
static const struct dfs_filesystem_ops _romfs =
{
    "rom",
    DFS_FS_FLAG_DEFAULT,
    &_rom_fops,

    dfs_romfs_mount,
    dfs_romfs_unmount,
    NULL,
    NULL,

    NULL,
    dfs_romfs_stat,
    NULL,
345 346 347 348 349 350
};

int dfs_romfs_init(void)
{
    /* register rom file system */
    dfs_register(&_romfs);
B
bernard 已提交
351
    return 0;
352
}
353
INIT_COMPONENT_EXPORT(dfs_romfs_init);
354