diff options
| author | Xavier Del Campo Romero <xavi92@disroot.org> | 2025-07-07 13:22:53 +0200 |
|---|---|---|
| committer | Xavier Del Campo Romero <xavi92@disroot.org> | 2025-11-11 00:08:15 +0100 |
| commit | 7861a52adf92a083bb2aed4c35f98d8035dce032 (patch) | |
| tree | 28cd3c40e4c878f730f5df3c1d93bdf91af490c3 /src/fs/iso9660 | |
| parent | 7fc48e9216ff809da5f8055a50b0be17628ef1df (diff) | |
| download | wnix-7861a52adf92a083bb2aed4c35f98d8035dce032.tar.gz | |
Setup project skeleton
Diffstat (limited to 'src/fs/iso9660')
| -rw-r--r-- | src/fs/iso9660/CMakeLists.txt | 20 | ||||
| -rw-r--r-- | src/fs/iso9660/include/iso9660.h | 24 | ||||
| -rw-r--r-- | src/fs/iso9660/private_include/iso9660/ops.h | 39 | ||||
| -rw-r--r-- | src/fs/iso9660/private_include/iso9660/routines.h | 35 | ||||
| -rw-r--r-- | src/fs/iso9660/private_include/iso9660/types.h | 148 | ||||
| -rw-r--r-- | src/fs/iso9660/src/CMakeLists.txt | 35 | ||||
| -rw-r--r-- | src/fs/iso9660/src/check_header.c | 39 | ||||
| -rw-r--r-- | src/fs/iso9660/src/close.c | 26 | ||||
| -rw-r--r-- | src/fs/iso9660/src/eof.c | 33 | ||||
| -rw-r--r-- | src/fs/iso9660/src/etotimespec.c | 40 | ||||
| -rw-r--r-- | src/fs/iso9660/src/gmtime.c | 35 | ||||
| -rw-r--r-- | src/fs/iso9660/src/lmsb16.c | 31 | ||||
| -rw-r--r-- | src/fs/iso9660/src/lmsb32.c | 31 | ||||
| -rw-r--r-- | src/fs/iso9660/src/mkdir.c | 28 | ||||
| -rw-r--r-- | src/fs/iso9660/src/mount.c | 180 | ||||
| -rw-r--r-- | src/fs/iso9660/src/open.c | 107 | ||||
| -rw-r--r-- | src/fs/iso9660/src/read.c | 27 | ||||
| -rw-r--r-- | src/fs/iso9660/src/register.c | 44 | ||||
| -rw-r--r-- | src/fs/iso9660/src/search.c | 557 | ||||
| -rw-r--r-- | src/fs/iso9660/src/stat.c | 28 | ||||
| -rw-r--r-- | src/fs/iso9660/src/totimespec.c | 54 | ||||
| -rw-r--r-- | src/fs/iso9660/src/totm.c | 72 | ||||
| -rw-r--r-- | src/fs/iso9660/src/write.c | 28 |
23 files changed, 1661 insertions, 0 deletions
diff --git a/src/fs/iso9660/CMakeLists.txt b/src/fs/iso9660/CMakeLists.txt new file mode 100644 index 0000000..736fc4e --- /dev/null +++ b/src/fs/iso9660/CMakeLists.txt @@ -0,0 +1,20 @@ +# wnix, a Unix-like operating system for WebAssembly applications. +# Copyright (C) 2025 Xavier Del Campo Romero +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +add_library(iso9660) +add_subdirectory(src) +target_include_directories(iso9660 PUBLIC include PRIVATE private_include) +target_link_libraries(iso9660 PUBLIC c PRIVATE fs kprintf state) diff --git a/src/fs/iso9660/include/iso9660.h b/src/fs/iso9660/include/iso9660.h new file mode 100644 index 0000000..e7d1864 --- /dev/null +++ b/src/fs/iso9660/include/iso9660.h @@ -0,0 +1,24 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef ISO9660_H +#define ISO9660_H + +int iso9660_register(void); + +#endif diff --git a/src/fs/iso9660/private_include/iso9660/ops.h b/src/fs/iso9660/private_include/iso9660/ops.h new file mode 100644 index 0000000..b85d025 --- /dev/null +++ b/src/fs/iso9660/private_include/iso9660/ops.h @@ -0,0 +1,39 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef ISO9660_OPS_H +#define ISO9660_OPS_H + +#include <fs/fs.h> +#include <fs/inode.h> + +int iso9660_mount(const struct fs_mount *m, struct fs_ret *r); +int iso9660_mkdir(const struct fs_mkdir *m, const struct fs_mp *mp, + const union inode_result *i, struct fs_ret *r); +int iso9660_open(const struct fs_open *o, const struct fs_mp *mp, + const union inode_result *i, struct fs_ret *r); +int iso9660_read(const struct fs_read *r, struct fs_ret *ret); +int iso9660_write(const struct fs_write *w, struct fs_ret *r); +int iso9660_stat(const struct fs_stat *s, const struct fs_mp *mp, + const union inode_result *inode, struct fs_ret *r); +int iso9660_close(struct fs_fd *fd); +int iso9660_eof(const struct fs_fd *fd); +int iso9660_search(const char *path, const struct fs_mp *prv, + union inode_result *inode, struct fs_ret *r); + +#endif diff --git a/src/fs/iso9660/private_include/iso9660/routines.h b/src/fs/iso9660/private_include/iso9660/routines.h new file mode 100644 index 0000000..467cce2 --- /dev/null +++ b/src/fs/iso9660/private_include/iso9660/routines.h @@ -0,0 +1,35 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef ISO9660_ROUTINES_H +#define ISO9660_ROUTINES_H + +#include <iso9660/types.h> +#include <stddef.h> +#include <stdint.h> +#include <time.h> + +int iso9660_check_header(const struct iso9660_magic *m); +uint16_t iso9660_lmsb16(const struct iso9660_lmsb16 *p); +uint32_t iso9660_lmsb32(const struct iso9660_lmsb32 *p); +int iso9660_totm(const struct iso9660_dt *dt, struct tm *tm); +int iso9660_totimespec(const struct iso9660_dt *dt, struct timespec *ts); +int iso9660_etotimespec(const struct iso9660_entry_dt *dt, struct timespec *ts); +struct tm iso9660_gmtime(const struct iso9660_entry_dt *dt); + +#endif diff --git a/src/fs/iso9660/private_include/iso9660/types.h b/src/fs/iso9660/private_include/iso9660/types.h new file mode 100644 index 0000000..55544fb --- /dev/null +++ b/src/fs/iso9660/private_include/iso9660/types.h @@ -0,0 +1,148 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef ISO9660_TYPES_H +#define ISO9660_TYPES_H + +#include <fs/fs.h> +#include <fs/inode.h> +#include <stdint.h> + +#define ISO9660_LE ((const union {int a; char c;}){.a = 1}.c) + +struct fs_mp_prv +{ + int dummy; +}; + +enum +{ + ISO9660_TYPE_BOOT_RECORD, + ISO9660_TYPE_PRIMARY_VD, + ISO9660_TYPE_SUPPLEMENTARY_VD, + ISO9660_TYPE_VOLUME_PARTITION, + ISO9660_TYPE_TERMINATOR = 0xff, +}; + +struct inode_prv +{ + long offset; +}; + +struct iso9660_magic +{ + uint8_t id[sizeof "CD001" - 1]; +}; + +struct iso9660_header +{ + uint8_t type; + struct iso9660_magic magic; + uint8_t version; +}; + +struct iso9660_lmsb16 +{ + uint8_t le[sizeof (uint16_t)], be[sizeof (uint16_t)]; +}; + +struct iso9660_lmsb32 +{ + uint8_t le[sizeof (uint32_t)], be[sizeof (uint32_t)]; +}; + +struct iso9660_dt +{ + char year[sizeof "9999" - 1], + month[sizeof "12" - 1], + day[sizeof "31" - 1], + hour[sizeof "23" - 1], + min[sizeof "59" - 1], + sec[sizeof "59" - 1], + hsec[sizeof "99" - 1]; + int8_t zone; +}; + +struct iso9660_lsb32 +{ + uint8_t data[sizeof (uint32_t)]; +}; + +struct iso9660_msb32 +{ + uint8_t data[sizeof (uint32_t)]; +}; + +struct iso9660_entry_dt +{ + uint8_t year, month, day, hour, min, sec, offset; +}; + +enum +{ + ISO9660_FLAGS_HIDDEN = 1, + ISO9660_FLAGS_DIR = 1 << 1, + ISO9660_FLAGS_ASSOC = 1 << 2, + ISO9660_FLAGS_HAS_FORMAT = 1 << 3, + ISO9660_FLAGS_HAS_UID_GID = 1 << 4, + ISO9660_FLAGS_NOT_FINAL = 1 << 7 +}; + +struct iso9660_entry +{ + uint8_t len, attr; + struct iso9660_lmsb32 extent_loc, data_len; + struct iso9660_entry_dt dt; + uint8_t flags; + uint8_t funit_sz, interleave_sz; + struct iso9660_lmsb16 seq_num; + uint8_t id_len; +}; + +struct iso9660_pvd +{ + uint8_t :8, sysid[32], vid[32], unused[8]; + struct iso9660_lmsb32 space_size; + uint8_t unused_2[32]; + struct iso9660_lmsb16 set_size, seq_num, block_size; + struct iso9660_lmsb32 pathtable_size; + struct iso9660_lsb32 lpath_loc, optlpath_loc; + struct iso9660_msb32 mpath_loc, optmpath_loc; + struct iso9660_entry root_dir; + uint8_t padding, set_id[128], pub_id[128], dprep_id[128], app_id[128], + copyright_id[37], abstract_id[37], bibl_id[37]; + struct iso9660_dt creat, mod, exp, eff; + uint8_t fs_version, :8, reserved[512 + 653]; +}; + + +struct iso9660_vd +{ + struct iso9660_header header; + + union + { + struct iso9660_pvd pvd; + } u; +}; + +enum {ISO9660_SECTOR_SZ = 2048}; + +extern const struct fs iso9660; + +#endif diff --git a/src/fs/iso9660/src/CMakeLists.txt b/src/fs/iso9660/src/CMakeLists.txt new file mode 100644 index 0000000..740e404 --- /dev/null +++ b/src/fs/iso9660/src/CMakeLists.txt @@ -0,0 +1,35 @@ +# wnix, a Unix-like operating system for WebAssembly applications. +# Copyright (C) 2025 Xavier Del Campo Romero +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +target_sources(iso9660 PRIVATE + check_header.c + close.c + eof.c + etotimespec.c + gmtime.c + lmsb16.c + lmsb32.c + mount.c + mkdir.c + open.c + stat.c + read.c + register.c + search.c + totimespec.c + totm.c + write.c +) diff --git a/src/fs/iso9660/src/check_header.c b/src/fs/iso9660/src/check_header.c new file mode 100644 index 0000000..f504187 --- /dev/null +++ b/src/fs/iso9660/src/check_header.c @@ -0,0 +1,39 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <iso9660.h> +#include <iso9660/routines.h> +#include <kprintf.h> +#include <stdint.h> +#include <string.h> + +int iso9660_check_header(const struct iso9660_magic *const m) +{ + static const struct iso9660_magic em = {{'C', 'D', '0', '0', '1'}}; + + if (memcmp(m, &em, sizeof *m)) + { + const uint8_t *const b = m->id; + + kprintf("Invalid ISO9660 header: " + "{%hhx, %hhx, %hhx, %hhx, %hhx}\n", b[0], b[1], b[2], b[3], b[4]); + return -1; + } + + return 0; +} diff --git a/src/fs/iso9660/src/close.c b/src/fs/iso9660/src/close.c new file mode 100644 index 0000000..d43da29 --- /dev/null +++ b/src/fs/iso9660/src/close.c @@ -0,0 +1,26 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <iso9660.h> +#include <iso9660/ops.h> +#include <fs/fs.h> + +int iso9660_close(struct fs_fd *const fd) +{ + return -1; +} diff --git a/src/fs/iso9660/src/eof.c b/src/fs/iso9660/src/eof.c new file mode 100644 index 0000000..1c36b63 --- /dev/null +++ b/src/fs/iso9660/src/eof.c @@ -0,0 +1,33 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <iso9660.h> +#include <iso9660/ops.h> +#include <iso9660/types.h> +#include <fs/inode.h> + +int iso9660_eof(const struct fs_fd *const fd) +{ + const union inode_result *const i = &fd->tgt_inode; + const off_t sz = i->cachei.size; + + if (!sz) + return 1; + + return fd->offset >= sz - 1; +} diff --git a/src/fs/iso9660/src/etotimespec.c b/src/fs/iso9660/src/etotimespec.c new file mode 100644 index 0000000..21debf7 --- /dev/null +++ b/src/fs/iso9660/src/etotimespec.c @@ -0,0 +1,40 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <iso9660.h> +#include <iso9660/routines.h> +#include <iso9660/types.h> +#include <time.h> + +int iso9660_etotimespec(const struct iso9660_entry_dt *const dt, + struct timespec *const ts) +{ + struct tm tm = iso9660_gmtime(dt); + const time_t t = mktime(&tm); + + if (t == (time_t)-1) + return -1; + + *ts = (const struct timespec) + { + .tv_sec = t, + .tv_nsec = 0 + }; + + return 0; +} diff --git a/src/fs/iso9660/src/gmtime.c b/src/fs/iso9660/src/gmtime.c new file mode 100644 index 0000000..2649688 --- /dev/null +++ b/src/fs/iso9660/src/gmtime.c @@ -0,0 +1,35 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <iso9660.h> +#include <iso9660/routines.h> +#include <iso9660/types.h> +#include <time.h> + +struct tm iso9660_gmtime(const struct iso9660_entry_dt *const dt) +{ + return (const struct tm) + { + .tm_year = dt->year + 1900, + .tm_mon = dt->month, + .tm_mday = dt->day, + .tm_hour = dt->hour, + .tm_min = dt->min, + .tm_sec = dt->sec + }; +} diff --git a/src/fs/iso9660/src/lmsb16.c b/src/fs/iso9660/src/lmsb16.c new file mode 100644 index 0000000..d404b2c --- /dev/null +++ b/src/fs/iso9660/src/lmsb16.c @@ -0,0 +1,31 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <iso9660/routines.h> +#include <iso9660/types.h> +#include <stdint.h> +#include <string.h> + +uint16_t iso9660_lmsb16(const struct iso9660_lmsb16 *const p) +{ + const uint16_t *const d = (const void *)(ISO9660_LE ? p->le : p->be); + uint16_t ret; + + memcpy(&ret, d, sizeof ret); + return ret; +} diff --git a/src/fs/iso9660/src/lmsb32.c b/src/fs/iso9660/src/lmsb32.c new file mode 100644 index 0000000..2811226 --- /dev/null +++ b/src/fs/iso9660/src/lmsb32.c @@ -0,0 +1,31 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <iso9660/routines.h> +#include <iso9660/types.h> +#include <stdint.h> +#include <string.h> + +uint32_t iso9660_lmsb32(const struct iso9660_lmsb32 *const p) +{ + const uint32_t *const d = (const void *)(ISO9660_LE ? p->le : p->be); + uint32_t ret; + + memcpy(&ret, d, sizeof ret); + return ret; +} diff --git a/src/fs/iso9660/src/mkdir.c b/src/fs/iso9660/src/mkdir.c new file mode 100644 index 0000000..9d30659 --- /dev/null +++ b/src/fs/iso9660/src/mkdir.c @@ -0,0 +1,28 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <iso9660.h> +#include <iso9660/ops.h> +#include <fs/fs.h> +#include <fs/inode.h> + +int iso9660_mkdir(const struct fs_mkdir *const m, const struct fs_mp *const mp, + const union inode_result *const inode, struct fs_ret *const r) +{ + return -1; +} diff --git a/src/fs/iso9660/src/mount.c b/src/fs/iso9660/src/mount.c new file mode 100644 index 0000000..83e7a6d --- /dev/null +++ b/src/fs/iso9660/src/mount.c @@ -0,0 +1,180 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <iso9660.h> +#include <iso9660/ops.h> +#include <iso9660/routines.h> +#include <iso9660/types.h> +#include <fs/fs.h> +#include <kprintf.h> +#include <state.h> +#include <errno.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +struct mount +{ + char *src, *tgt; + struct fs_fd fd; + struct fs_ret *r; + struct fs_mount mount; + struct iso9660_header header; + const struct fs_mp *mp; +}; + +static void free_mount(struct mount *const m) +{ + if (!m) + return; + + m->mp->fs->close(&m->fd); + free(m->src); + free(m->tgt); + free(m); +} + +static enum state check_header(void *const args) +{ + enum state ret = STATE_OK; + struct mount *const m = args; + + if (iso9660_check_header(&m->header.magic)) + ret = STATE_FATAL; + else if (fs_mountpoint(m->src, m->tgt, &iso9660, NULL, NULL)) + { + kprintf("Failed to allocate mountpoint {source=%s, target=%s}\n", + m->src, m->tgt); + ret = STATE_FATAL; + } + + free_mount(m); + return ret; +} + +static enum state read_header(void *const args) +{ + struct mount *const m = args; + struct fs_fd *const fd = &m->fd; + const struct fs *const fs = m->mp->fs; + const struct fs_read r = + { + .buf = &m->header, + .n = sizeof m->header, + .fd = fd + }; + + if (fd->error) + { + errno = fd->error; + goto failure; + } + + *m->r = (const struct fs_ret) + { + .f = check_header, + .args = m + }; + + fd->offset = 16 * ISO9660_SECTOR_SZ; + + if (fs->read(&r, m->r)) + goto failure; + + return STATE_AGAIN; + +failure: + free_mount(m); + return STATE_FATAL; +} + +static int search_done(const enum state state, const char *const relpath, + const struct fs_mp *const mp, const union inode_result *const inode, + void *const args) +{ + struct mount *const m = args; + const struct fs_mount *const fm = &m->mount; + + if (!inode) + { + errno = ENOENT; + goto failure; + } + + const struct fs_open o = + { + .fd = &m->fd, + .gid = fm->gid, + .uid = fm->uid, + .mode = fm->mode, + .path = relpath + }; + + *m->r = (const struct fs_ret) + { + .f = read_header, + .args = m + }; + + if (mp->fs->open(&o, mp, inode, m->r)) + goto failure; + + m->mp = mp; + return 0; + +failure: + free_mount(m); + return -1; +} + +int iso9660_mount(const struct fs_mount *const fm, struct fs_ret *const r) +{ + char *srcdup = NULL, *tgtdup = NULL; + struct mount *const m = malloc(sizeof *m); + + if (!m + || !(srcdup = strdup(fm->src)) + || !(tgtdup = strdup(fm->tgt))) + goto failure; + + *m = (const struct mount) + { + .src = srcdup, + .tgt = tgtdup, + .mount = *fm, + .r = r + }; + + const struct inode_search s = + { + .args = m, + .path = fm->src, + .done = search_done + }; + + if (inode_search(&s, r)) + goto failure; + + return 0; + +failure: + free(srcdup); + free(tgtdup); + free(m); + return -1; +} diff --git a/src/fs/iso9660/src/open.c b/src/fs/iso9660/src/open.c new file mode 100644 index 0000000..1ea6ad7 --- /dev/null +++ b/src/fs/iso9660/src/open.c @@ -0,0 +1,107 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <iso9660.h> +#include <iso9660/ops.h> +#include <iso9660/routines.h> +#include <iso9660/types.h> +#include <fs/fs.h> +#include <fs/inode.h> +#include <errno.h> +#include <stdlib.h> + +struct open +{ + struct inode inode; + struct fs_fd *fd; + struct fs_ret *pr, r; + const struct fs_mp *mp; +}; + +static int search_done(const enum state state, const char *const relpath, + const struct fs_mp *const mp, const union inode_result *const inode, + void *const args) +{ + int ret = 0; + struct open *const op = args; + const struct inode *const mpinode = &op->inode; + struct fs_fd *const fd = op->fd; + + if (mpinode->flags & INODE_DIR) + { + fd->error = EISDIR; + ret = -1; + } + else if (state) + { + fd->error = ENODEV; + ret = -1; + } + else + { + *fd = (const struct fs_fd) + { + .start = mpinode->prv->offset, + .tgt_inode.cachei = op->inode, + .size = mpinode->size, + .tgt_mp = op->mp, + .inode = *inode, + .mp = mp + }; + + *op->pr = op->r; + } + + free(op); + return ret; +} + +int iso9660_open(const struct fs_open *const o, const struct fs_mp *const mp, + const union inode_result *const inode, struct fs_ret *const r) +{ + const struct inode *const i = &inode->cachei; + struct open *const op = malloc(sizeof *op); + + if (!op) + return -1; + + const struct inode_search s = + { + .args = op, + .path = mp->src, + .done = search_done + }; + + *op = (const struct open) + { + .fd = o->fd, + .inode = *i, + .mp = mp, + .pr = r, + .r = *r + }; + + if (inode_search(&s, r)) + goto failure; + + return 0; + +failure: + free(op); + return -1; +} diff --git a/src/fs/iso9660/src/read.c b/src/fs/iso9660/src/read.c new file mode 100644 index 0000000..6e14845 --- /dev/null +++ b/src/fs/iso9660/src/read.c @@ -0,0 +1,27 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <iso9660.h> +#include <iso9660/ops.h> +#include <fs/fs.h> +#include <stddef.h> + +int iso9660_read(const struct fs_read *const fr, struct fs_ret *const ret) +{ + return -1; +} diff --git a/src/fs/iso9660/src/register.c b/src/fs/iso9660/src/register.c new file mode 100644 index 0000000..70a33f9 --- /dev/null +++ b/src/fs/iso9660/src/register.c @@ -0,0 +1,44 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <iso9660.h> +#include <iso9660/ops.h> +#include <fs/fs.h> + +const struct fs iso9660 = +{ + .type = "iso9660", + .flags = FS_DEV_REQUIRED, + .mount = iso9660_mount, + .stat = iso9660_stat, + .mkdir = iso9660_mkdir, + .open = iso9660_open, + .read = iso9660_read, + .write = iso9660_write, + .close = iso9660_close, + .eof = iso9660_eof, + .iops = + { + .search = iso9660_search + } +}; + +int iso9660_register(void) +{ + return fs_register(&iso9660); +} diff --git a/src/fs/iso9660/src/search.c b/src/fs/iso9660/src/search.c new file mode 100644 index 0000000..a7a5150 --- /dev/null +++ b/src/fs/iso9660/src/search.c @@ -0,0 +1,557 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <iso9660.h> +#include <iso9660/ops.h> +#include <iso9660/routines.h> +#include <iso9660/types.h> +#include <fs/fs.h> +#include <kprintf.h> +#include <fcntl.h> +#include <ctype.h> +#include <errno.h> +#include <inttypes.h> +#include <limits.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +struct id +{ + char buf[UCHAR_MAX]; +}; + +struct search +{ + union inode_result *inode; + const struct fs_mp *src_mp; + struct iso9660_entry entry; + const char *src, *path; + struct fs_ret r, *pr; + struct fs_fd fd; + off_t offset; + size_t token_i; + char *token; + void *buf; + struct id id; +}; + +static int prepare_entry(struct search *); +static int next_entry(struct search *); + +static void free_search(struct search *const s) +{ + if (!s) + return; + else if (s->src_mp) + s->src_mp->fs->close(&s->fd); + + free(s->buf); + free(s->token); + free(s); +} + +static int set_inode(struct search *const s, + const struct iso9660_entry *const e, const struct id *const id) +{ + struct inode *const inode = &s->inode->cachei; + struct inode_prv *p = NULL; + char *namedup = NULL; + struct timespec ts, atim; + + if (clock_gettime(CLOCK_REALTIME, &atim)) + goto failure; + else if (iso9660_etotimespec(&e->dt, &ts)) + { + kprintf("Invalid datetime, path=%s\n", s->path); + goto failure; + } + else if (!(namedup = strdup(id->buf)) || !(p = malloc(sizeof *p))) + goto failure; + + *p = (const struct inode_prv) + { + .offset = iso9660_lmsb32(&e->extent_loc) * ISO9660_SECTOR_SZ + }; + + *inode = (const struct inode) + { + .size = iso9660_lmsb32(&e->data_len), + .flags = INODE_REGFILE, + .name = namedup, + .mode = 0555, + .atim = atim, + .free = free, + .ctim = ts, + .mtim = ts, + .prv = p + }; + + return 0; + +failure: + free(p); + free(namedup); + return -1; +} + +static int next_token(struct search *const s) +{ + free(s->token); + s->token = NULL; + + if (fs_next(s->path, &s->token, &s->token_i)) + { + kprintf("Failed to extract next token, path=%s, i=%zu\n", s->path, + s->token_i); + return -1; + } + + return 0; +} + +static int check_version(const char *const version) +{ + char *end; + + errno = 0; + strtoul(version, &end, 10); + + return errno || *end; +} + +static void extract_id(const char *id, struct id *const out, + const char *const ext, const char *const version) +{ + char *p = out->buf; + + if (ext) + { + const ptrdiff_t n = ext - id; + const char *const e = ext + 1; + + memcpy(p, id, n); + p += n; + id += n; + + if (*e) + { + const ptrdiff_t n = version ? version - e : strlen(e); + + memcpy(p, id, n); + p += n; + } + } + else if (version) + { + memcpy(p, id, version - id); + p += version - id; + } + else + { + const ptrdiff_t n = strlen(id); + + memcpy(p, id, n); + p += n; + } + + *p = '\0'; + p = out->buf; + + while (*p) + { + *p = tolower(*p); + p++; + } +} + +static int parse_id(const char *const id, struct id *const out) +{ + static const char accept[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; + const char *const ext = strchr(id, '.'), *const version = strchr(id, ';'); + const size_t n = strspn(id, accept), len = strlen(id); + + /* Ensure only valid characters are met if no version or extension. */ + if (!version && !ext && n != len) + return -1; + /* Ensure file version appears only after file extension, + * if both are present. */ + else if (version && ext && ext > version) + return -1; + /* Ensure one and only one file version and/or extension appear. */ + else if ((version && strchr(version + 1, ';')) + || (ext && strchr(ext + 1, '.'))) + return -1; + else if (version && check_version(version + 1)) + return -1; + /* When present, ensure valid characters only until the file extension + * is found. */ + else if (ext && n != ext - id) + return -1; + + extract_id(id, out, ext, version); + return 0; +} + +static enum state id_read(void *const args) +{ + struct search *volatile const s = args; + const struct iso9660_entry *const e = &s->entry; + const char *const id = s->id.buf; + struct id outid; + + if (!*id || !strcmp(id, "\1")) + { + if (next_entry(s)) + goto failure; + } + else if (parse_id(id, &outid)) + { + kprintf("Invalid file or directory identifier=%s\n", id); + goto failure; + } + else if (!strcmp(outid.buf, s->token)) + { + char *token; + + if (fs_next(s->path, &token, &s->token_i)) + { + kprintf("Failed to extract next token, path=%s, i=%zu\n", + s->path, s->token_i); + goto failure; + } + else if (!token) + { + if (set_inode(s, e, &outid)) + goto failure; + + *s->pr = s->r; + free_search(s); + return STATE_AGAIN; + } + else if (!(e->flags & ISO9660_FLAGS_DIR)) + { + kprintf("Intermediate node %s not a directory, path=%s\n", + id, s->path); + goto failure; + } + else + { + s->fd.offset = iso9660_lmsb32(&e->extent_loc) * ISO9660_SECTOR_SZ; + + if (prepare_entry(s)) + goto failure; + } + + free(s->token); + free(s->buf); + s->token = token; + s->buf = NULL; + } + else if (next_entry(s)) + goto failure; + + return STATE_AGAIN; + +failure: + free_search(s); + return STATE_FATAL; +} + +static enum state entry_read(void *const args) +{ + struct search *const s = args; + const struct iso9660_entry *const e = &s->entry; + + if (e->len < sizeof *e) + { + kprintf("Unexpected entry length %hhu, expected %zu\n", e->len, + sizeof *e); + goto failure; + } + + char *const buf = s->id.buf; + const struct fs_mp *const mp = s->fd.mp; + const struct fs_read r = + { + .buf = buf, + .n = e->id_len, + .fd = &s->fd + }; + + *(buf + e->id_len) = '\0'; + *s->pr = (const struct fs_ret) + { + .f = id_read, + .args = s + }; + + if (mp->fs->read(&r, s->pr)) + goto failure; + + return STATE_AGAIN; + +failure: + free_search(s); + return STATE_FATAL; +} + +static int prepare_entry(struct search *const s) +{ + const struct fs_read r = + { + .buf = &s->entry, + .fd = &s->fd, + .n = sizeof s->entry + }; + + *s->pr = (const struct fs_ret) + { + .f = entry_read, + .args = s + }; + + s->offset = s->fd.offset; + return s->src_mp->fs->read(&r, s->pr); +} + +static int next_entry(struct search *const s) +{ + const struct iso9660_entry *const e = &s->entry; + struct fs_fd *const fd = &s->fd; + + fd->offset = s->offset + e->len; + return prepare_entry(s); +} + +static int set_root_inode(const struct iso9660_pvd *const pvd, + struct search *const s) +{ + struct inode *const inode = &s->inode->cachei; + struct inode_prv *p = NULL; + char *namedup = NULL; + + if (clock_gettime(CLOCK_REALTIME, &inode->atim)) + goto failure; + else if (iso9660_totimespec(&pvd->creat, &inode->ctim)) + { + kprintf("Invalid volume creation time\n"); + goto failure; + } + else if (iso9660_totimespec(&pvd->mod, &inode->mtim)) + { + kprintf("Invalid volume modification time\n"); + goto failure; + } + else if (!(namedup = strdup("/")) || !(p = malloc(sizeof *p))) + goto failure; + + *p = (const struct inode_prv) + { + .offset = offsetof(struct iso9660_pvd, root_dir) + }; + + inode->flags = INODE_DIR; + inode->mode = 0555; + inode->name = namedup; + inode->prv = p; + *s->pr = s->r; + free_search(s); + return 0; + +failure: + free(p); + free(namedup); + return -1; +} + +static int check_pvd(const struct iso9660_vd *const vd) +{ + const struct iso9660_pvd *const pvd = &vd->u.pvd; + const struct iso9660_entry *const e = &pvd->root_dir; + const struct iso9660_header *const h = &vd->header; + const uint16_t block_size = iso9660_lmsb16(&pvd->block_size); + const size_t exp_sz = sizeof (struct iso9660_entry) + sizeof pvd->padding; + + if (iso9660_check_header(&h->magic)) + return -1; + else if (h->version != 1) + { + kprintf("Unsupported ISO9660 version %#hhx, expected 1\n", h->version); + return -1; + } + else if (h->type != ISO9660_TYPE_PRIMARY_VD) + { + kprintf("Unexpected volume descriptor type %#hhx, expected=%#x\n", + h->type, ISO9660_TYPE_PRIMARY_VD); + return -1; + } + else if (pvd->fs_version != 1) + { + kprintf("Unexpected file structure version %#hhx, expected 1\n", + pvd->fs_version); + return -1; + } + else if (block_size != ISO9660_SECTOR_SZ) + { + kprintf("Unsupported block size %" PRIu16 ", expected %d\n", + block_size, ISO9660_SECTOR_SZ); + return -1; + } + else if (e->len != exp_sz) + { + kprintf("Unexpected root directory length %hhd, expected %zu\n", + e->len, exp_sz); + return -1; + } + else if (!(e->flags & ISO9660_FLAGS_DIR)) + { + kprintf("Directory flag (%#hx) not found in file flags (%#hhx)\n", + ISO9660_FLAGS_DIR, e->flags); + return -1; + } + + return 0; +} + +static enum state read_pvd_done(void *const args) +{ + struct search *const s = args; + struct fs_fd *const fd = &s->fd; + const struct iso9660_vd *const vd = s->buf; + const struct iso9660_pvd *const pvd = &vd->u.pvd; + const struct iso9660_entry *const e = &pvd->root_dir; + const uint32_t lba = iso9660_lmsb32(&e->extent_loc); + + fd->offset = lba * ISO9660_SECTOR_SZ; + + if (check_pvd(vd)) + goto failure; + else if (!strcmp(s->src, "/")) + { + if (set_root_inode(pvd, s)) + goto failure; + + return STATE_AGAIN; + } + else if (next_token(s) || prepare_entry(s)) + goto failure; + + return STATE_AGAIN; + +failure: + free_search(s); + return STATE_FATAL; +} + +static enum state read_pvd(void *const args) +{ + struct search *const s = args; + struct fs_fd *const fd = &s->fd; + + if (!(s->buf = malloc(ISO9660_SECTOR_SZ)) || next_token(s)) + goto failure; + + const struct fs_read r = + { + .buf = s->buf, + .fd = fd, + .n = ISO9660_SECTOR_SZ + }; + + *s->pr = (const struct fs_ret) + { + .f = read_pvd_done, + .args = s + }; + + fd->offset = 16 * ISO9660_SECTOR_SZ; + + if (s->src_mp->fs->read(&r, s->pr)) + goto failure; + + return STATE_AGAIN; + +failure: + free_search(s); + return STATE_FATAL; +} + +static int src_done(const enum state state, const char *const relpath, + const struct fs_mp *const mp, const union inode_result *const inode, + void *const args) +{ + struct search *const s = args; + + if (state) + { + kprintf("Failed to find source inode for %s\n", s->src); + return -1; + } + + s->src_mp = mp; + *s->pr = (const struct fs_ret) + { + .f = read_pvd, + .args = s + }; + + const struct fs_open o = + { + .fd = &s->fd, + .path = mp->src, + .flags = O_RDONLY + }; + + return mp->fs->open(&o, mp, inode, s->pr); +} + +int iso9660_search(const char *const path, const struct fs_mp *const mp, + union inode_result *const inode, struct fs_ret *const r) +{ + struct search *const s = malloc(sizeof *s); + + if (!s) + goto failure; + + *s = (const struct search) + { + .inode = inode, + .src = mp->src, + .path = path, + .r = *r, + .pr = r + }; + + const struct inode_search is = + { + .path = mp->src, + .done = src_done, + .args = s, + }; + + if (inode_search(&is, r)) + goto failure; + + return 0; + +failure: + free(s); + return -1; +} diff --git a/src/fs/iso9660/src/stat.c b/src/fs/iso9660/src/stat.c new file mode 100644 index 0000000..53732fe --- /dev/null +++ b/src/fs/iso9660/src/stat.c @@ -0,0 +1,28 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <iso9660.h> +#include <iso9660/ops.h> +#include <fs/fs.h> +#include <sys/stat.h> + +int iso9660_stat(const struct fs_stat *const s, const struct fs_mp *const mp, + const union inode_result *const inode, struct fs_ret *const r) +{ + return -1; +} diff --git a/src/fs/iso9660/src/totimespec.c b/src/fs/iso9660/src/totimespec.c new file mode 100644 index 0000000..735deb7 --- /dev/null +++ b/src/fs/iso9660/src/totimespec.c @@ -0,0 +1,54 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <iso9660.h> +#include <iso9660/routines.h> +#include <iso9660/types.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +int iso9660_totimespec(const struct iso9660_dt *const dt, + struct timespec *const ts) +{ + char hsec[sizeof dt->hsec + 1], *end; + unsigned long v; + struct tm tm; + time_t t; + + if (iso9660_totm(dt, &tm) + || ((t = mktime(&tm)) == (time_t)-1)) + return -1; + + errno = 0; + memcpy(hsec, dt->hsec, sizeof dt->hsec); + hsec[sizeof dt->hsec] = '\0'; + v = strtoul(hsec, &end, 10); + + if (errno || *end || v >= 100) + return -1; + + *ts = (const struct timespec) + { + .tv_sec = t, + .tv_nsec = v * 100000ul + }; + + return 0; +} diff --git a/src/fs/iso9660/src/totm.c b/src/fs/iso9660/src/totm.c new file mode 100644 index 0000000..1e94359 --- /dev/null +++ b/src/fs/iso9660/src/totm.c @@ -0,0 +1,72 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <iso9660.h> +#include <iso9660/routines.h> +#include <iso9660/types.h> +#include <errno.h> +#include <limits.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +int iso9660_totm(const struct iso9660_dt *const dt, struct tm *const tm) +{ + char year[sizeof dt->year + 1], + month[sizeof dt->month + 1], + day[sizeof dt->day + 1], + hour[sizeof dt->hour + 1], + min[sizeof dt->min + 1], + sec[sizeof dt->sec + 1]; + + struct buf + { + const char *src; + char *s; + int *v; + size_t n; + } bufs[] = + { + {.src = dt->year, .s = year, .n = sizeof dt->year, .v = &tm->tm_year}, + {.src = dt->month, .s = month, .n = sizeof dt->month, .v = &tm->tm_mon}, + {.src = dt->day, .s = day, .n = sizeof dt->day, .v = &tm->tm_yday}, + {.src = dt->hour, .s = hour, .n = sizeof dt->hour, .v = &tm->tm_hour}, + {.src = dt->min, .s = min, .n = sizeof dt->min, .v = &tm->tm_min}, + {.src = dt->sec, .s = sec, .n = sizeof dt->sec, .v = &tm->tm_sec} + }; + + for (size_t i = 0; i < sizeof bufs / sizeof *bufs; i++) + { + struct buf *const b = &bufs[i]; + unsigned long v; + char *end; + + memcpy(b->s, b->src, b->n - 1); + b->s[b->n] = '\0'; + errno = 0; + v = strtoul(b->s, &end, 10); + + if (errno || *end || v > INT_MAX) + return -1; + + *b->v = v; + } + + return 0; +} diff --git a/src/fs/iso9660/src/write.c b/src/fs/iso9660/src/write.c new file mode 100644 index 0000000..2ce3823 --- /dev/null +++ b/src/fs/iso9660/src/write.c @@ -0,0 +1,28 @@ +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <iso9660.h> +#include <iso9660/ops.h> +#include <fs/fs.h> +#include <errno.h> + +int iso9660_write(const struct fs_write *const w, struct fs_ret *const r) +{ + errno = EROFS; + return -1; +} |
