From 24332da96793e8601ad6b78d3a1c10bb4d5581da Mon Sep 17 00:00:00 2001 From: kamkow1 Date: Sat, 18 Apr 2026 18:49:13 +0200 Subject: [PATCH] Move filesystem drivers into their separate directories --- kernel/fs/fatfs/.gitignore | 1 + kernel/fs/{ => fatfs}/fat1.c | 4 +- kernel/fs/{ => fatfs}/fat1.h | 0 kernel/fs/{ => fatfs}/fatfs.c | 6 +- kernel/fs/{ => fatfs}/fatfs.h | 0 kernel/fs/{ => fatfs}/fatfs_ctx.h | 0 kernel/fs/fatfs/src.mk | 5 + kernel/fs/iso9660fs/.gitignore | 1 + kernel/fs/{ => iso9660fs}/iso9660fs.c | 4 +- kernel/fs/{ => iso9660fs}/iso9660fs.h | 0 kernel/fs/iso9660fs/lib9660.c | 359 ++++++++++++++++++++++++ kernel/fs/iso9660fs/lib9660.h | 210 ++++++++++++++ kernel/fs/iso9660fs/src.mk | 5 + kernel/fs/lib9660.c | 382 -------------------------- kernel/fs/lib9660.h | 202 -------------- kernel/fs/src.mk | 18 +- kernel/fs/tarfs/.gitignore | 1 + kernel/fs/tarfs/src.mk | 3 + kernel/fs/{ => tarfs}/tarfs.c | 2 +- kernel/fs/{ => tarfs}/tarfs.h | 0 kernel/fs/vfs.c | 8 +- 21 files changed, 603 insertions(+), 608 deletions(-) create mode 100644 kernel/fs/fatfs/.gitignore rename kernel/fs/{ => fatfs}/fat1.c (99%) rename kernel/fs/{ => fatfs}/fat1.h (100%) rename kernel/fs/{ => fatfs}/fatfs.c (98%) rename kernel/fs/{ => fatfs}/fatfs.h (100%) rename kernel/fs/{ => fatfs}/fatfs_ctx.h (100%) create mode 100644 kernel/fs/fatfs/src.mk create mode 100644 kernel/fs/iso9660fs/.gitignore rename kernel/fs/{ => iso9660fs}/iso9660fs.c (98%) rename kernel/fs/{ => iso9660fs}/iso9660fs.h (100%) create mode 100644 kernel/fs/iso9660fs/lib9660.c create mode 100644 kernel/fs/iso9660fs/lib9660.h create mode 100644 kernel/fs/iso9660fs/src.mk delete mode 100644 kernel/fs/lib9660.c delete mode 100644 kernel/fs/lib9660.h create mode 100644 kernel/fs/tarfs/.gitignore create mode 100644 kernel/fs/tarfs/src.mk rename kernel/fs/{ => tarfs}/tarfs.c (99%) rename kernel/fs/{ => tarfs}/tarfs.h (100%) diff --git a/kernel/fs/fatfs/.gitignore b/kernel/fs/fatfs/.gitignore new file mode 100644 index 0000000..5761abc --- /dev/null +++ b/kernel/fs/fatfs/.gitignore @@ -0,0 +1 @@ +*.o diff --git a/kernel/fs/fat1.c b/kernel/fs/fatfs/fat1.c similarity index 99% rename from kernel/fs/fat1.c rename to kernel/fs/fatfs/fat1.c index e6bca50..da64451 100644 --- a/kernel/fs/fat1.c +++ b/kernel/fs/fatfs/fat1.c @@ -1,8 +1,8 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-parameter" #pragma clang diagnostic ignored "-Wmacro-redefined" -#include -#include +#include +#include #include #include diff --git a/kernel/fs/fat1.h b/kernel/fs/fatfs/fat1.h similarity index 100% rename from kernel/fs/fat1.h rename to kernel/fs/fatfs/fat1.h diff --git a/kernel/fs/fatfs.c b/kernel/fs/fatfs/fatfs.c similarity index 98% rename from kernel/fs/fatfs.c rename to kernel/fs/fatfs/fatfs.c index 86306b7..ca7a40f 100644 --- a/kernel/fs/fatfs.c +++ b/kernel/fs/fatfs/fatfs.c @@ -1,8 +1,8 @@ #include #include -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/kernel/fs/fatfs.h b/kernel/fs/fatfs/fatfs.h similarity index 100% rename from kernel/fs/fatfs.h rename to kernel/fs/fatfs/fatfs.h diff --git a/kernel/fs/fatfs_ctx.h b/kernel/fs/fatfs/fatfs_ctx.h similarity index 100% rename from kernel/fs/fatfs_ctx.h rename to kernel/fs/fatfs/fatfs_ctx.h diff --git a/kernel/fs/fatfs/src.mk b/kernel/fs/fatfs/src.mk new file mode 100644 index 0000000..faed37b --- /dev/null +++ b/kernel/fs/fatfs/src.mk @@ -0,0 +1,5 @@ +c += fs/fatfs/fat1.c \ + fs/fatfs/fatfs.c + +o += fs/fatfs/fat1.o \ + fs/fatfs/fatfs.o diff --git a/kernel/fs/iso9660fs/.gitignore b/kernel/fs/iso9660fs/.gitignore new file mode 100644 index 0000000..5761abc --- /dev/null +++ b/kernel/fs/iso9660fs/.gitignore @@ -0,0 +1 @@ +*.o diff --git a/kernel/fs/iso9660fs.c b/kernel/fs/iso9660fs/iso9660fs.c similarity index 98% rename from kernel/fs/iso9660fs.c rename to kernel/fs/iso9660fs/iso9660fs.c index 83e4f53..78e16a3 100644 --- a/kernel/fs/iso9660fs.c +++ b/kernel/fs/iso9660fs/iso9660fs.c @@ -3,8 +3,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/kernel/fs/iso9660fs.h b/kernel/fs/iso9660fs/iso9660fs.h similarity index 100% rename from kernel/fs/iso9660fs.h rename to kernel/fs/iso9660fs/iso9660fs.h diff --git a/kernel/fs/iso9660fs/lib9660.c b/kernel/fs/iso9660fs/lib9660.c new file mode 100644 index 0000000..3da962f --- /dev/null +++ b/kernel/fs/iso9660fs/lib9660.c @@ -0,0 +1,359 @@ +/* lib9660: a simple ISO9660 reader library especially suited to embedded + * systems + * + * SPDX-License-Identifier: LicenseRef-ISC1 + * SPDX-FileCopyrightText: © 2014 Erin Shepherd + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice appears in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#define SEEK_END L9660_SEEK_END +#define SEEK_SET L9660_SEEK_SET +#define SEEK_CUR L9660_SEEK_CUR + +#define DENT_EXISTS (1 << 0) +#define DENT_ISDIR (1 << 1) +#define DENT_ASSOCIATED (1 << 2) +#define DENT_RECORD (1 << 3) +#define DENT_PROTECTION (1 << 4) +#define DENT_MULTIEXTENT (1 << 5) + +#define PVD(vdesc) ((l9660_vdesc_primary*)(vdesc)) + +#ifdef L9660_BIG_ENDIAN +#define READ16(v) (((v).be[1]) | ((v).be[0] << 8)) +#define READ32(v) (((v).be[3]) | ((v).be[2] << 8) | ((v).be[1]) << 16 | ((v).be[0] << 24)) +#else +#define READ16(v) (((v).le[0]) | ((v).le[1] << 8)) +#define READ32(v) (((v).le[0]) | ((v).le[1] << 8) | ((v).le[2]) << 16 | ((v).le[3] << 24)) +#endif + +#define HAVEBUFFER(f) (true) +#define BUF(f) ((f)->buf) + +#define ROCKRIDGE_FILENAME_MAX 0xFF + +#define NM_CONTINUE 0x01 +#define NM_CURRENT 0x02 +#define NM_PARENT 0x04 + +static char* strchrnul (const char* s, int c) { + while (*s && *s != c) + s++; + return (char*)s; +} + +static inline uint16_t fsectoff (l9660_file* f) { return f->position % 2048; } + +static inline uint32_t fsector (l9660_file* f) { return f->position / 2048; } + +static inline uint32_t fnextsectpos (l9660_file* f) { return (f->position + 2047) & ~2047; } + +const char* l9660_get_rockridge_name (l9660_dirent* dirent, char* out, size_t* out_len) { + uint8_t* ptr = (uint8_t*)dirent + sizeof (*dirent) + dirent->name_len; + + if (!(dirent->name_len & 1)) + ptr++; + + uint8_t* end = (uint8_t*)dirent + dirent->length; + + size_t total = 0; + bool found = false; + + while (ptr + sizeof (l9660_su_field) <= end) { + l9660_su_field* sufield = (l9660_su_field*)ptr; + + if (sufield->len < 5 || ptr + sufield->len > end) + break; + + if (sufield->sign[0] == 'N' && sufield->sign[1] == 'M') { + uint8_t flags = sufield->data[0]; + + if ((flags & NM_CURRENT)) { + out[0] = '.'; + *out_len = 1; + return out; + } + + if ((flags & NM_PARENT)) { + out[0] = '.'; + out[1] = '.'; + *out_len = 2; + return out; + } + + size_t part_len = sufield->len - 5; + if (total + part_len > ROCKRIDGE_FILENAME_MAX) + part_len = ROCKRIDGE_FILENAME_MAX - total; + + memcpy (out + total, &sufield->data[1], part_len); + total += part_len; + found = true; + + if (total < ROCKRIDGE_FILENAME_MAX) + out[total] = '\0'; + else + out[ROCKRIDGE_FILENAME_MAX - 1] = '\0'; + + if (!(flags & NM_CONTINUE)) + break; + } + + ptr += sufield->len; + } + + if (!found) + return NULL; + + *out_len = total; + + return out; +} + +l9660_status l9660_openfs (l9660_fs* fs, + bool (*read_sector) (l9660_fs* fs, void* buf, uint32_t sector)) { + fs->read_sector = read_sector; + +#ifndef L9660_SINGLEBUFFER + l9660_vdesc_primary* pvd = PVD (&fs->pvd); +#else + last_file = NULL; + l9660_vdesc_primary* pvd = PVD (gbuf); +#endif + uint32_t idx = 0x10; + for (;;) { + // Read next sector + if (!read_sector (fs, pvd, idx)) + return L9660_EIO; + + // Validate magic + if (memcmp (pvd->hdr.magic, "CD001", 5) != 0) + return L9660_EBADFS; + + if (pvd->hdr.type == 1) + break; // Found PVD + else if (pvd->hdr.type == 255) + return L9660_EBADFS; + } + +#ifdef L9660_SINGLEBUFFER + memcpy (&fs->root_dir_ent, &pvd->root_dir_ent, pvd->root_dir_ent.length); +#endif + + return L9660_OK; +} + +l9660_status l9660_fs_open_root (l9660_dir* dir, l9660_fs* fs) { + l9660_file* f = &dir->file; +#ifndef L9660_SINGLEBUFFER + l9660_dirent* dirent = &PVD (&fs->pvd)->rde.root_dir_ent; +#else + l9660_dirent* dirent = &fs->root_dir_ent; +#endif + + f->fs = fs; + f->first_sector = READ32 (dirent->sector); + f->length = READ32 (dirent->size); + f->position = 0; + + return L9660_OK; +} + +static l9660_status buffer (l9660_file* f) { +#ifdef L9660_SINGLEBUFFER + last_file = f; +#endif + if (!f->fs->read_sector (f->fs, BUF (f), f->first_sector + f->position / 2048)) + return L9660_EIO; + else + return L9660_OK; +} + +static l9660_status prebuffer (l9660_file* f) { + if (!HAVEBUFFER (f) || (f->position % 2048) == 0) + return buffer (f); + else + return L9660_OK; +} + +static l9660_status openat_raw (l9660_file* child, l9660_dir* parent, const char* name, + bool isdir) { + char rr_namebuf[ROCKRIDGE_FILENAME_MAX]; + l9660_status rv; + l9660_dirent* dent = NULL; + size_t dent_rr_name_len = 0; + if ((rv = l9660_seekdir (parent, 0))) + return rv; + + do { + const char* seg = name; + name = strchrnul (name, '/'); + size_t seglen = name - seg; + + /* ISO9660 stores '.' as '\0' */ + if (seglen == 1 && *seg == '.') + seg = "\0"; + + /* ISO9660 stores ".." as '\1' */ + if (seglen == 2 && seg[0] == '.' && seg[1] == '.') { + seg = "\1"; + seglen = 1; + } + + for (;;) { + if ((rv = l9660_readdir (parent, &dent))) + return rv; + + /* EOD */ + if (!dent) + return L9660_ENOENT; + + const char* rockridge_name = l9660_get_rockridge_name (dent, rr_namebuf, &dent_rr_name_len); + + if (rockridge_name == NULL) { + /* wrong length */ + if (seglen != dent->name_len) + continue; + + /* check name */ + if (memcmp (seg, dent->name, seglen) != 0) + continue; + + /* check for a revision tag */ + if (dent->name_len > seglen && dent->name[seglen] != ';') + continue; + + /* all tests pass */ + break; + } else { + if (seglen == dent_rr_name_len && memcmp (seg, rockridge_name, seglen) == 0) + break; + + continue; + } + } + + child->fs = parent->file.fs; + child->first_sector = READ32 (dent->sector); + child->length = READ32 (dent->size); + child->position = 0; + + if (*name && (dent->flags & DENT_ISDIR) == 0) + return L9660_ENOTDIR; + + parent = (l9660_dir*)child; + + if (*name == '/') + name++; + } while (*name); + + if (isdir) { + if ((dent->flags & DENT_ISDIR) == 0) + return L9660_ENOTDIR; + } else { + if ((dent->flags & DENT_ISDIR) != 0) + return L9660_ENOTFILE; + } + + return L9660_OK; +} + +l9660_status l9660_opendirat (l9660_dir* dir, l9660_dir* parent, const char* path) { + return openat_raw (&dir->file, parent, path, true); +} + +static inline unsigned aligneven (unsigned v) { return v + (v & 1); } + +l9660_status l9660_readdir (l9660_dir* dir, l9660_dirent** pdirent) { + l9660_status rv; + l9660_file* f = &dir->file; + +rebuffer: + if (f->position >= f->length) { + *pdirent = NULL; + return L9660_OK; + } + + if ((rv = prebuffer (f))) + return rv; + + char* off = BUF (f) + fsectoff (f); + if (*off == 0) { + // Padded end of sector + f->position = fnextsectpos (f); + goto rebuffer; + } + + l9660_dirent* dirent = (l9660_dirent*)off; + f->position += aligneven (dirent->length); + + *pdirent = dirent; + return L9660_OK; +} + +l9660_status l9660_openat (l9660_file* child, l9660_dir* parent, const char* name) { + return openat_raw (child, parent, name, false); +} + +/*! Seek the file to \p offset from \p whence */ +l9660_status l9660_seek (l9660_file* f, int whence, int32_t offset) { + l9660_status rv; + uint32_t cursect = fsector (f); + + switch (whence) { + case SEEK_SET: + f->position = offset; + break; + + case SEEK_CUR: + f->position = f->position + offset; + break; + + case SEEK_END: + f->position = f->length - offset; + break; + } + + if (fsector (f) != cursect && fsectoff (f) != 0) { + if ((rv = buffer (f))) + return rv; + } + + return L9660_OK; +} + +uint32_t l9660_tell (l9660_file* f) { return f->position; } + +l9660_status l9660_read (l9660_file* f, void* buf, size_t size, size_t* read) { + l9660_status rv; + + if ((rv = prebuffer (f))) + return rv; + + uint16_t rem = 2048 - fsectoff (f); + if (rem > f->length - f->position) + rem = f->length - f->position; + if (rem < size) + size = rem; + + memcpy (buf, BUF (f) + fsectoff (f), size); + + *read = size; + f->position += size; + + return L9660_OK; +} diff --git a/kernel/fs/iso9660fs/lib9660.h b/kernel/fs/iso9660fs/lib9660.h new file mode 100644 index 0000000..04fc1d9 --- /dev/null +++ b/kernel/fs/iso9660fs/lib9660.h @@ -0,0 +1,210 @@ +/* lib9660: a simple ISO9660 reader library especially suited to embedded + * systems + * + * SPDX-License-Identifier: LicenseRef-ISC1 + * SPDX-FileCopyrightText: © 2014 Erin Shepherd + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice appears in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef LIB9660_H +#define LIB9660_H + +#include +#include + +struct proc; +struct reschedule_ctx; + +#define L9660_SEEK_END -1 +#define L9660_SEEK_SET 0 +#define L9660_SEEK_CUR +1 + +/* Our error return format */ +typedef enum { + /*! Success! */ + L9660_OK = 0, + /*! read_sector callback returned false */ + L9660_EIO, + /*! file system is bad */ + L9660_EBADFS, + /*! specified name does not exist */ + L9660_ENOENT, + /*! attempted to open a non-file (e.g. a directory) as a file */ + L9660_ENOTFILE, + /*! attempted to open a non-directory (e.g. a file) as a directory + * may be returned by l9660_openat if e.g. you pass path "a/b" and + * "a" is a file + */ + L9660_ENOTDIR, +} l9660_status; + +/* ISO9660 uses big/little/dual endian integers */ +typedef struct { + uint8_t le[2]; +} PACKED l9660_luint16; +typedef struct { + uint8_t be[2]; +} PACKED l9660_buint16; +typedef struct { + uint8_t le[2], be[2]; +} PACKED l9660_duint16; +typedef struct { + uint8_t le[4]; +} PACKED l9660_luint32; +typedef struct { + uint8_t be[4]; +} PACKED l9660_buint32; +typedef struct { + uint8_t le[4], be[4]; +} PACKED l9660_duint32; + +/* Descriptor time format */ +typedef struct { + char d[17]; +} PACKED l9660_desctime; + +/* File time format */ +typedef struct { + char d[7]; +} PACKED l9660_filetime; + +/* Directory entry */ +typedef struct { + uint8_t length; + uint8_t xattr_length; + l9660_duint32 sector; + l9660_duint32 size; + l9660_filetime time; + uint8_t flags; + uint8_t unit_size; + uint8_t gap_size; + l9660_duint16 vol_seq_number; + uint8_t name_len; + char name[/*name_len*/]; +} PACKED l9660_dirent; + +typedef struct { + char sign[2]; + uint8_t len; + uint8_t version; + char data[]; +} PACKED l9660_su_field; + +/* Volume descriptor header */ +typedef struct { + uint8_t type; + char magic[5]; + uint8_t version; +} PACKED l9660_vdesc_header; + +/* Primary volume descriptor */ +typedef struct { + l9660_vdesc_header hdr; + char pad0[1]; + char system_id[32]; + char volume_id[32]; + char pad1[8]; + l9660_duint32 volume_space_size; + char pad2[32]; + l9660_duint16 volume_set_size; + l9660_duint16 volume_seq_number; + l9660_duint16 logical_block_size; + l9660_duint32 path_table_size; + l9660_luint32 path_table_le; + l9660_luint32 path_table_opt_le; + l9660_buint32 path_table_be; + l9660_buint32 path_table_opt_be; + union { + l9660_dirent root_dir_ent; + char pad3[34]; + } PACKED rde; + char volume_set_id[128]; + char data_preparer_id[128]; + char app_id[128]; + char copyright_file[38]; + char abstract_file[36]; + char bibliography_file[37]; + l9660_desctime volume_created, volume_modified, volume_expires, volume_effective; + uint8_t file_structure_version; + char pad4[1]; + char app_reserved[512]; + char reserved[653]; +} PACKED l9660_vdesc_primary; + +/* A generic volume descriptor (i.e. 2048 bytes) */ +typedef union { + l9660_vdesc_header hdr; + char _bits[2048]; +} PACKED l9660_vdesc; + +/* File system structure. + * Stick this inside your own structure and cast/offset as appropriate to store + * private data + */ +typedef struct l9660_fs { + void* udata; + struct proc* proc; + struct reschedule_ctx* rctx; + /* Sector buffer to hold the PVD */ + l9660_vdesc pvd; + /* read_sector func */ + bool (*read_sector) (struct l9660_fs* fs, void* buf, uint32_t sector); +} l9660_fs; + +typedef struct { + /* single sector buffer */ + char buf[2048]; + l9660_fs* fs; + uint32_t first_sector; + uint32_t position; + uint32_t length; +} l9660_file; + +typedef struct { + /* directories are mostly just files with special accessors, but we like type safetey */ + l9660_file file; +} l9660_dir; + +/* Open a file system, initialising *fs. */ +l9660_status l9660_openfs (l9660_fs* fs, + bool (*read_sector) (l9660_fs* fs, void* buf, uint32_t sector)); + +/*void l9660_closefs(l9660_fs *fs); (nop) */ + +/*! Open the root directory */ +l9660_status l9660_fs_open_root (l9660_dir* dir, l9660_fs* fs); + +/*! Open the subdirectory given by \p path */ +l9660_status l9660_opendirat (l9660_dir* dir, l9660_dir* parent, const char* path); +/*! Returns the next directory entry. If end-of-directory is reached, *dirent is + * set to NULL. */ +l9660_status l9660_readdir (l9660_dir* dir, l9660_dirent** dirent); + +#define l9660_seekdir(dir, pos) (l9660_seek (&(dir)->file, L9660_SEEK_SET, (pos))) +#define l9660_telldir(dir) (l9660_tell (&(dir)->file)) + +/*! Open the file given by \p path in \p parent */ +l9660_status l9660_openat (l9660_file* file, l9660_dir* parent, const char* path); + +/*! Read \p size bytes into \p buf. The number of bytes read will be returned in + * \p *read. May be less than \p size (but only 0 on EOF) + */ +l9660_status l9660_read (l9660_file* file, void* buf, size_t size, size_t* read); +/*! Seek the file to \p offset from \p whence */ +l9660_status l9660_seek (l9660_file* file, int whence, int32_t offset); +/*! Return the current position (suitable for passing to l9660_seek(file, SEEK_SET, ...)) */ +uint32_t l9660_tell (l9660_file* file); + +const char* l9660_get_rockridge_name (l9660_dirent* dirent, char* out, size_t* out_len); + +#endif diff --git a/kernel/fs/iso9660fs/src.mk b/kernel/fs/iso9660fs/src.mk new file mode 100644 index 0000000..f617ee8 --- /dev/null +++ b/kernel/fs/iso9660fs/src.mk @@ -0,0 +1,5 @@ +c += fs/iso9660fs/iso9660fs.c \ + fs/iso9660fs/lib9660.c + +o += fs/iso9660fs/iso9660fs.o \ + fs/iso9660fs/lib9660.o diff --git a/kernel/fs/lib9660.c b/kernel/fs/lib9660.c deleted file mode 100644 index 32e00fb..0000000 --- a/kernel/fs/lib9660.c +++ /dev/null @@ -1,382 +0,0 @@ -/* lib9660: a simple ISO9660 reader library especially suited to embedded - * systems - * - * SPDX-License-Identifier: LicenseRef-ISC1 - * SPDX-FileCopyrightText: © 2014 Erin Shepherd - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice appears in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include - -#define SEEK_END L9660_SEEK_END -#define SEEK_SET L9660_SEEK_SET -#define SEEK_CUR L9660_SEEK_CUR - -#define DENT_EXISTS (1 << 0) -#define DENT_ISDIR (1 << 1) -#define DENT_ASSOCIATED (1 << 2) -#define DENT_RECORD (1 << 3) -#define DENT_PROTECTION (1 << 4) -#define DENT_MULTIEXTENT (1 << 5) - -#define PVD(vdesc) ((l9660_vdesc_primary*)(vdesc)) - -#ifdef L9660_BIG_ENDIAN -#define READ16(v) (((v).be[1]) | ((v).be[0] << 8)) -#define READ32(v) (((v).be[3]) | ((v).be[2] << 8) | ((v).be[1]) << 16 | ((v).be[0] << 24)) -#else -#define READ16(v) (((v).le[0]) | ((v).le[1] << 8)) -#define READ32(v) (((v).le[0]) | ((v).le[1] << 8) | ((v).le[2]) << 16 | ((v).le[3] << 24)) -#endif - -#define HAVEBUFFER(f) (true) -#define BUF(f) ((f)->buf) - -#define ROCKRIDGE_FILENAME_MAX 0xFF - -#define NM_CONTINUE 0x01 -#define NM_CURRENT 0x02 -#define NM_PARENT 0x04 - -static char *strchrnul(const char *s, int c) -{ - while (*s && *s != c) - s++; - return (char *) s; -} - -static inline uint16_t fsectoff(l9660_file *f) -{ - return f->position % 2048; -} - -static inline uint32_t fsector(l9660_file *f) -{ - return f->position / 2048; -} - -static inline uint32_t fnextsectpos(l9660_file *f) -{ - return (f->position + 2047) & ~2047; -} - -const char* l9660_get_rockridge_name (l9660_dirent* dirent, char* out, size_t *out_len) { - uint8_t* ptr = (uint8_t*)dirent + sizeof (*dirent) + dirent->name_len; - - if (!(dirent->name_len & 1)) - ptr++; - - uint8_t* end = (uint8_t*)dirent + dirent->length; - - size_t total = 0; - bool found = false; - - while (ptr + sizeof (l9660_su_field) <= end) { - l9660_su_field* sufield = (l9660_su_field*)ptr; - - if (sufield->len < 5 || ptr + sufield->len > end) - break; - - if (sufield->sign[0] == 'N' && sufield->sign[1] == 'M') { - uint8_t flags = sufield->data[0]; - - if ((flags & NM_CURRENT)) { - out[0] = '.'; - *out_len = 1; - return out; - } - - if ((flags & NM_PARENT)) { - out[0] = '.'; - out[1] = '.'; - *out_len = 2; - return out; - } - - size_t part_len = sufield->len - 5; - if (total + part_len > ROCKRIDGE_FILENAME_MAX) - part_len = ROCKRIDGE_FILENAME_MAX - total; - - memcpy (out + total, &sufield->data[1], part_len); - total += part_len; - found = true; - - if (total < ROCKRIDGE_FILENAME_MAX) - out[total] = '\0'; - else - out[ROCKRIDGE_FILENAME_MAX - 1] = '\0'; - - if (!(flags & NM_CONTINUE)) - break; - } - - ptr += sufield->len; - } - - if (!found) - return NULL; - - *out_len = total; - - return out; -} - -l9660_status l9660_openfs( - l9660_fs *fs, - bool (*read_sector)(l9660_fs *fs, void *buf, uint32_t sector)) -{ - fs->read_sector = read_sector; - -#ifndef L9660_SINGLEBUFFER - l9660_vdesc_primary *pvd = PVD(&fs->pvd); -#else - last_file = NULL; - l9660_vdesc_primary *pvd = PVD(gbuf); -#endif - uint32_t idx = 0x10; - for (;;) { - // Read next sector - if (!read_sector(fs, pvd, idx)) - return L9660_EIO; - - // Validate magic - if (memcmp(pvd->hdr.magic, "CD001", 5) != 0) - return L9660_EBADFS; - - if (pvd->hdr.type == 1) - break; // Found PVD - else if(pvd->hdr.type == 255) - return L9660_EBADFS; - } - -#ifdef L9660_SINGLEBUFFER - memcpy(&fs->root_dir_ent, &pvd->root_dir_ent, pvd->root_dir_ent.length); -#endif - - return L9660_OK; -} - -l9660_status l9660_fs_open_root(l9660_dir *dir, l9660_fs *fs) -{ - l9660_file *f = &dir->file; -#ifndef L9660_SINGLEBUFFER - l9660_dirent *dirent = &PVD(&fs->pvd)->rde.root_dir_ent; -#else - l9660_dirent *dirent = &fs->root_dir_ent; -#endif - - f->fs = fs; - f->first_sector = READ32(dirent->sector); - f->length = READ32(dirent->size); - f->position = 0; - - return L9660_OK; -} - -static l9660_status buffer(l9660_file *f) -{ -#ifdef L9660_SINGLEBUFFER - last_file = f; -#endif - if (!f->fs->read_sector(f->fs, BUF(f), f->first_sector + f->position / 2048)) - return L9660_EIO; - else - return L9660_OK; -} - -static l9660_status prebuffer(l9660_file *f) -{ - if (!HAVEBUFFER(f) || (f->position % 2048) == 0) - return buffer(f); - else return L9660_OK; -} - -static l9660_status openat_raw(l9660_file *child, l9660_dir *parent, const char *name, bool isdir) -{ - char rr_namebuf[ROCKRIDGE_FILENAME_MAX]; - l9660_status rv; - l9660_dirent *dent = NULL; - size_t dent_rr_name_len = 0; - if ((rv = l9660_seekdir(parent, 0))) return rv; - - do { - const char *seg = name; - name = strchrnul(name, '/'); - size_t seglen = name - seg; - - /* ISO9660 stores '.' as '\0' */ - if (seglen == 1 && *seg == '.') - seg = "\0"; - - /* ISO9660 stores ".." as '\1' */ - if (seglen == 2 && seg[0] == '.' && seg[1] == '.') { - seg = "\1"; - seglen = 1; - } - - for(;;) { - if ((rv = l9660_readdir(parent, &dent))) - return rv; - - /* EOD */ - if (!dent) - return L9660_ENOENT; - - const char* rockridge_name = l9660_get_rockridge_name (dent, rr_namebuf, &dent_rr_name_len); - - if (rockridge_name == NULL) { - /* wrong length */ - if (seglen != dent->name_len) - continue; - - /* check name */ - if (memcmp(seg, dent->name, seglen) != 0) - continue; - - /* check for a revision tag */ - if (dent->name_len > seglen && dent->name[seglen] != ';') - continue; - - /* all tests pass */ - break; - } else { - if (seglen == dent_rr_name_len && memcmp (seg, rockridge_name, seglen) == 0) - break; - - continue; - } - } - - child->fs = parent->file.fs; - child->first_sector = READ32(dent->sector); - child->length = READ32(dent->size); - child->position = 0; - - if (*name && (dent->flags & DENT_ISDIR) == 0) - return L9660_ENOTDIR; - - parent = (l9660_dir*) child; - - if (*name == '/') - name++; - } while(*name); - - if (isdir) { - if ((dent->flags & DENT_ISDIR) == 0) - return L9660_ENOTDIR; - } else { - if ((dent->flags & DENT_ISDIR) != 0) - return L9660_ENOTFILE; - } - - return L9660_OK; -} - -l9660_status l9660_opendirat(l9660_dir *dir, l9660_dir *parent, const char *path) -{ - return openat_raw(&dir->file, parent, path, true); -} - -static inline unsigned aligneven(unsigned v) { - return v + (v & 1); -} - -l9660_status l9660_readdir(l9660_dir *dir, l9660_dirent **pdirent) -{ - l9660_status rv; - l9660_file *f = &dir->file; - -rebuffer: - if(f->position >= f->length) { - *pdirent = NULL; - return L9660_OK; - } - - if ((rv = prebuffer(f))) - return rv; - - char *off = BUF(f) + fsectoff(f); - if (*off == 0) { - // Padded end of sector - f->position = fnextsectpos(f); - goto rebuffer; - } - - l9660_dirent *dirent = (l9660_dirent*) off; - f->position += aligneven(dirent->length); - - *pdirent = dirent; - return L9660_OK; -} - -l9660_status l9660_openat(l9660_file *child, l9660_dir *parent, const char * name) -{ - return openat_raw(child, parent, name, false); -} - -/*! Seek the file to \p offset from \p whence */ -l9660_status l9660_seek(l9660_file *f, int whence, int32_t offset) -{ - l9660_status rv; - uint32_t cursect = fsector(f); - - switch (whence) { - case SEEK_SET: - f->position = offset; - break; - - case SEEK_CUR: - f->position = f->position + offset; - break; - - case SEEK_END: - f->position = f->length - offset; - break; - } - - if (fsector(f) != cursect && fsectoff(f) != 0) { - if ((rv = buffer(f))) - return rv; - } - - return L9660_OK; -} - -uint32_t l9660_tell(l9660_file *f) -{ - return f->position; -} - -l9660_status l9660_read(l9660_file *f, void* buf, size_t size, size_t *read) -{ - l9660_status rv; - - if ((rv = prebuffer(f))) - return rv; - - uint16_t rem = 2048 - fsectoff(f); - if (rem > f->length - f->position) - rem = f->length - f->position; - if (rem < size) - size = rem; - - memcpy(buf, BUF(f) + fsectoff(f), size); - - *read = size; - f->position += size; - - return L9660_OK; -} diff --git a/kernel/fs/lib9660.h b/kernel/fs/lib9660.h deleted file mode 100644 index d530b8f..0000000 --- a/kernel/fs/lib9660.h +++ /dev/null @@ -1,202 +0,0 @@ -/* lib9660: a simple ISO9660 reader library especially suited to embedded - * systems - * - * SPDX-License-Identifier: LicenseRef-ISC1 - * SPDX-FileCopyrightText: © 2014 Erin Shepherd - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice appears in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ -#ifndef LIB9660_H -#define LIB9660_H - -#include -#include - -struct proc; -struct reschedule_ctx; - -#define L9660_SEEK_END -1 -#define L9660_SEEK_SET 0 -#define L9660_SEEK_CUR +1 - -/* Our error return format */ -typedef enum { - /*! Success! */ - L9660_OK = 0, - /*! read_sector callback returned false */ - L9660_EIO, - /*! file system is bad */ - L9660_EBADFS, - /*! specified name does not exist */ - L9660_ENOENT, - /*! attempted to open a non-file (e.g. a directory) as a file */ - L9660_ENOTFILE, - /*! attempted to open a non-directory (e.g. a file) as a directory - * may be returned by l9660_openat if e.g. you pass path "a/b" and - * "a" is a file - */ - L9660_ENOTDIR, -} l9660_status; - -/* ISO9660 uses big/little/dual endian integers */ -typedef struct { uint8_t le[2]; } PACKED l9660_luint16; -typedef struct { uint8_t be[2]; } PACKED l9660_buint16; -typedef struct { uint8_t le[2], be[2]; } PACKED l9660_duint16; -typedef struct { uint8_t le[4]; } PACKED l9660_luint32; -typedef struct { uint8_t be[4]; } PACKED l9660_buint32; -typedef struct { uint8_t le[4], be[4]; } PACKED l9660_duint32; - -/* Descriptor time format */ -typedef struct { - char d[17]; -} PACKED l9660_desctime; - -/* File time format */ -typedef struct { - char d[7]; -} PACKED l9660_filetime; - -/* Directory entry */ -typedef struct { - uint8_t length; - uint8_t xattr_length; - l9660_duint32 sector; - l9660_duint32 size; - l9660_filetime time; - uint8_t flags; - uint8_t unit_size; - uint8_t gap_size; - l9660_duint16 vol_seq_number; - uint8_t name_len; - char name[/*name_len*/]; -} PACKED l9660_dirent; - -typedef struct { - char sign[2]; - uint8_t len; - uint8_t version; - char data[]; -} PACKED l9660_su_field; - -/* Volume descriptor header */ -typedef struct { - uint8_t type; - char magic[5]; - uint8_t version; -} PACKED l9660_vdesc_header; - -/* Primary volume descriptor */ -typedef struct { - l9660_vdesc_header hdr; - char pad0[1]; - char system_id[32]; - char volume_id[32]; - char pad1[8]; - l9660_duint32 volume_space_size; - char pad2[32]; - l9660_duint16 volume_set_size; - l9660_duint16 volume_seq_number; - l9660_duint16 logical_block_size; - l9660_duint32 path_table_size; - l9660_luint32 path_table_le; - l9660_luint32 path_table_opt_le; - l9660_buint32 path_table_be; - l9660_buint32 path_table_opt_be; - union { - l9660_dirent root_dir_ent; - char pad3[34]; - } PACKED rde; - char volume_set_id[128]; - char data_preparer_id[128]; - char app_id[128]; - char copyright_file[38]; - char abstract_file[36]; - char bibliography_file[37]; - l9660_desctime volume_created, - volume_modified, - volume_expires, - volume_effective; - uint8_t file_structure_version; - char pad4[1]; - char app_reserved[512]; - char reserved[653]; -} PACKED l9660_vdesc_primary; - -/* A generic volume descriptor (i.e. 2048 bytes) */ -typedef union { - l9660_vdesc_header hdr; - char _bits[2048]; -} PACKED l9660_vdesc; - -/* File system structure. - * Stick this inside your own structure and cast/offset as appropriate to store - * private data - */ -typedef struct l9660_fs { - void* udata; - struct proc* proc; - struct reschedule_ctx* rctx; - /* Sector buffer to hold the PVD */ - l9660_vdesc pvd; - /* read_sector func */ - bool (*read_sector)(struct l9660_fs *fs, void *buf, uint32_t sector); -} l9660_fs; - -typedef struct { - /* single sector buffer */ - char buf[2048]; - l9660_fs *fs; - uint32_t first_sector; - uint32_t position; - uint32_t length; -} l9660_file; - -typedef struct { - /* directories are mostly just files with special accessors, but we like type safetey */ - l9660_file file; -} l9660_dir; - -/* Open a file system, initialising *fs. */ -l9660_status l9660_openfs( - l9660_fs *fs, - bool (*read_sector)(l9660_fs *fs, void *buf, uint32_t sector)); - -/*void l9660_closefs(l9660_fs *fs); (nop) */ - -/*! Open the root directory */ -l9660_status l9660_fs_open_root(l9660_dir *dir, l9660_fs *fs); - -/*! Open the subdirectory given by \p path */ -l9660_status l9660_opendirat(l9660_dir *dir, l9660_dir *parent, const char *path); -/*! Returns the next directory entry. If end-of-directory is reached, *dirent is - * set to NULL. */ -l9660_status l9660_readdir(l9660_dir *dir, l9660_dirent **dirent); - -#define l9660_seekdir(dir, pos) (l9660_seek(&(dir)->file, L9660_SEEK_SET, (pos))) -#define l9660_telldir(dir) (l9660_tell(&(dir)->file)) - -/*! Open the file given by \p path in \p parent */ -l9660_status l9660_openat(l9660_file *file, l9660_dir *parent, const char *path); - -/*! Read \p size bytes into \p buf. The number of bytes read will be returned in - * \p *read. May be less than \p size (but only 0 on EOF) - */ -l9660_status l9660_read(l9660_file *file, void* buf, size_t size, size_t *read); -/*! Seek the file to \p offset from \p whence */ -l9660_status l9660_seek(l9660_file *file, int whence, int32_t offset); -/*! Return the current position (suitable for passing to l9660_seek(file, SEEK_SET, ...)) */ -uint32_t l9660_tell(l9660_file *file); - -const char* l9660_get_rockridge_name (l9660_dirent* dirent, char* out, size_t *out_len); - -#endif diff --git a/kernel/fs/src.mk b/kernel/fs/src.mk index 48a3d6a..210b625 100644 --- a/kernel/fs/src.mk +++ b/kernel/fs/src.mk @@ -1,15 +1,9 @@ +include fs/fatfs/src.mk +include fs/tarfs/src.mk +include fs/iso9660fs/src.mk + c += fs/vfs.c \ - fs/tarfs.c \ - fs/path.c \ - fs/fat1.c \ - fs/fatfs.c \ - fs/lib9660.c \ - fs/iso9660fs.c + fs/path.c o += fs/vfs.o \ - fs/tarfs.o \ - fs/path.o \ - fs/fat1.o \ - fs/fatfs.o \ - fs/lib9660.o \ - fs/iso9660fs.o + fs/path.o diff --git a/kernel/fs/tarfs/.gitignore b/kernel/fs/tarfs/.gitignore new file mode 100644 index 0000000..5761abc --- /dev/null +++ b/kernel/fs/tarfs/.gitignore @@ -0,0 +1 @@ +*.o diff --git a/kernel/fs/tarfs/src.mk b/kernel/fs/tarfs/src.mk new file mode 100644 index 0000000..5fb1c14 --- /dev/null +++ b/kernel/fs/tarfs/src.mk @@ -0,0 +1,3 @@ +c += fs/tarfs/tarfs.c + +o += fs/tarfs/tarfs.o diff --git a/kernel/fs/tarfs.c b/kernel/fs/tarfs/tarfs.c similarity index 99% rename from kernel/fs/tarfs.c rename to kernel/fs/tarfs/tarfs.c index 4fb073a..15525be 100644 --- a/kernel/fs/tarfs.c +++ b/kernel/fs/tarfs/tarfs.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/kernel/fs/tarfs.h b/kernel/fs/tarfs/tarfs.h similarity index 100% rename from kernel/fs/tarfs.h rename to kernel/fs/tarfs/tarfs.h diff --git a/kernel/fs/vfs.c b/kernel/fs/vfs.c index 949c43d..5fed1ac 100644 --- a/kernel/fs/vfs.c +++ b/kernel/fs/vfs.c @@ -1,8 +1,8 @@ #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include