Move filesystem drivers into their separate directories
This commit is contained in:
1
kernel/fs/fatfs/.gitignore
vendored
Normal file
1
kernel/fs/fatfs/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.o
|
||||
@@ -1,8 +1,8 @@
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-parameter"
|
||||
#pragma clang diagnostic ignored "-Wmacro-redefined"
|
||||
#include <fs/fat1.h>
|
||||
#include <fs/fatfs_ctx.h>
|
||||
#include <fs/fatfs/fat1.h>
|
||||
#include <fs/fatfs/fatfs_ctx.h>
|
||||
#include <proc/proc.h>
|
||||
#include <proc/reschedule.h>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include <desc.h>
|
||||
#include <devices.h>
|
||||
#include <fs/fat1.h>
|
||||
#include <fs/fatfs.h>
|
||||
#include <fs/fatfs_ctx.h>
|
||||
#include <fs/fatfs/fat1.h>
|
||||
#include <fs/fatfs/fatfs.h>
|
||||
#include <fs/fatfs/fatfs_ctx.h>
|
||||
#include <fs/path.h>
|
||||
#include <fs/vfs.h>
|
||||
#include <libk/align.h>
|
||||
5
kernel/fs/fatfs/src.mk
Normal file
5
kernel/fs/fatfs/src.mk
Normal file
@@ -0,0 +1,5 @@
|
||||
c += fs/fatfs/fat1.c \
|
||||
fs/fatfs/fatfs.c
|
||||
|
||||
o += fs/fatfs/fat1.o \
|
||||
fs/fatfs/fatfs.o
|
||||
1
kernel/fs/iso9660fs/.gitignore
vendored
Normal file
1
kernel/fs/iso9660fs/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.o
|
||||
@@ -3,8 +3,8 @@
|
||||
#include <devices.h>
|
||||
#include <dir_entry.h>
|
||||
#include <fs/def_vfs_op.h>
|
||||
#include <fs/iso9660fs.h>
|
||||
#include <fs/lib9660.h>
|
||||
#include <fs/iso9660fs/iso9660fs.h>
|
||||
#include <fs/iso9660fs/lib9660.h>
|
||||
#include <fs/vfs.h>
|
||||
#include <libk/std.h>
|
||||
#include <libk/string.h>
|
||||
359
kernel/fs/iso9660fs/lib9660.c
Normal file
359
kernel/fs/iso9660fs/lib9660.c
Normal file
@@ -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 <fs/iso9660fs/lib9660.h>
|
||||
#include <libk/string.h>
|
||||
#include <sys/debug.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
210
kernel/fs/iso9660fs/lib9660.h
Normal file
210
kernel/fs/iso9660fs/lib9660.h
Normal file
@@ -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 <aux/compiler.h>
|
||||
#include <libk/std.h>
|
||||
|
||||
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
|
||||
5
kernel/fs/iso9660fs/src.mk
Normal file
5
kernel/fs/iso9660fs/src.mk
Normal file
@@ -0,0 +1,5 @@
|
||||
c += fs/iso9660fs/iso9660fs.c \
|
||||
fs/iso9660fs/lib9660.c
|
||||
|
||||
o += fs/iso9660fs/iso9660fs.o \
|
||||
fs/iso9660fs/lib9660.o
|
||||
@@ -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 <fs/lib9660.h>
|
||||
#include <libk/string.h>
|
||||
#include <sys/debug.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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 <libk/std.h>
|
||||
#include <aux/compiler.h>
|
||||
|
||||
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
|
||||
@@ -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
|
||||
|
||||
1
kernel/fs/tarfs/.gitignore
vendored
Normal file
1
kernel/fs/tarfs/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.o
|
||||
3
kernel/fs/tarfs/src.mk
Normal file
3
kernel/fs/tarfs/src.mk
Normal file
@@ -0,0 +1,3 @@
|
||||
c += fs/tarfs/tarfs.c
|
||||
|
||||
o += fs/tarfs/tarfs.o
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <desc.h>
|
||||
#include <devices.h>
|
||||
#include <fs/path.h>
|
||||
#include <fs/tarfs.h>
|
||||
#include <fs/tarfs/tarfs.h>
|
||||
#include <fs/vfs.h>
|
||||
#include <libk/align.h>
|
||||
#include <libk/minmax.h>
|
||||
@@ -1,8 +1,8 @@
|
||||
#include <device/device.h>
|
||||
#include <fs/fat1.h>
|
||||
#include <fs/fatfs.h>
|
||||
#include <fs/iso9660fs.h>
|
||||
#include <fs/tarfs.h>
|
||||
#include <fs/fatfs/fat1.h>
|
||||
#include <fs/fatfs/fatfs.h>
|
||||
#include <fs/iso9660fs/iso9660fs.h>
|
||||
#include <fs/tarfs/tarfs.h>
|
||||
#include <fs/vfs.h>
|
||||
#include <fs_types.h>
|
||||
#include <id/id_alloc.h>
|
||||
|
||||
Reference in New Issue
Block a user