220 lines
7.1 KiB
C
220 lines
7.1 KiB
C
/* lib9660: a simple ISO9660 reader library especially suited to embedded
|
|
* systems
|
|
*
|
|
* Copyright © 2014, Owen 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
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <stdbool.h>
|
|
|
|
#ifdef L9660_HAVE_STDIO
|
|
#include <stdio.h>
|
|
#define L9660_SEEK_END SEEK_END
|
|
#define L9660_SEEK_SET SEEK_SET
|
|
#define L9660_SEEK_CUR SEEK_CUR
|
|
#else
|
|
#define L9660_SEEK_END -1
|
|
#define L9660_SEEK_SET 0
|
|
#define L9660_SEEK_CUR +1
|
|
#endif
|
|
|
|
#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)
|
|
|
|
/* 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]; } l9660_luint16;
|
|
typedef struct { uint8_t be[2]; } l9660_buint16;
|
|
typedef struct { uint8_t le[2], be[2]; } l9660_duint16;
|
|
typedef struct { uint8_t le[4]; } l9660_luint32;
|
|
typedef struct { uint8_t be[4]; } l9660_buint32;
|
|
typedef struct { uint8_t le[4], be[4]; } l9660_duint32;
|
|
|
|
/* Descriptor time format */
|
|
typedef struct {
|
|
char d[17];
|
|
} l9660_desctime;
|
|
|
|
/* File time format */
|
|
typedef struct {
|
|
char d[7];
|
|
} 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*/];
|
|
} l9660_dirent;
|
|
|
|
/* Volume descriptor header */
|
|
typedef struct {
|
|
uint8_t type;
|
|
char magic[5];
|
|
uint8_t version;
|
|
} 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];
|
|
};
|
|
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];
|
|
} l9660_vdesc_primary;
|
|
|
|
/* A generic volume descriptor (i.e. 2048 bytes) */
|
|
typedef union {
|
|
l9660_vdesc_header hdr;
|
|
char _bits[2048];
|
|
} l9660_vdesc;
|
|
|
|
/* File system structure.
|
|
* Stick this inside your own structure and cast/offset as appropriate to store
|
|
* private data
|
|
*/
|
|
typedef struct l9660_fs {
|
|
#ifdef L9660_SINGLEBUFFER
|
|
union {
|
|
l9660_dirent root_dir_ent;
|
|
char root_dir_pad[34];
|
|
};
|
|
#else
|
|
/* Sector buffer to hold the PVD */
|
|
l9660_vdesc pvd;
|
|
#endif
|
|
|
|
/* read_sector func */
|
|
bool (*read_sector)(struct l9660_fs* fs, void* buf, uint32_t sector);
|
|
} l9660_fs;
|
|
|
|
typedef struct {
|
|
#ifndef L9660_SINGLEBUFFER
|
|
/* single sector buffer */
|
|
char buf[2048];
|
|
#endif
|
|
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);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|