diff --git a/src/add-ons/kernel/file_systems/iso9660/Jamfile b/src/add-ons/kernel/file_systems/iso9660/Jamfile index 8680b6564b..cf6d22354b 100644 --- a/src/add-ons/kernel/file_systems/iso9660/Jamfile +++ b/src/add-ons/kernel/file_systems/iso9660/Jamfile @@ -20,13 +20,20 @@ oldOPTIM = $(OPTIM) ; defines = [ FDefines $(defines) ] ; SubDirCcFlags $(defines) -Wall -Wno-multichar ; + SubDirC++Flags $(defines) -Wall -Wno-multichar -fno-rtti ; } KernelAddon iso9660 : kernel file_systems : iso.c - kernel_interface.c + iso9660.cpp + kernel_interface.cpp + kernel_cpp.cpp ; +SEARCH on [ FGristFiles + kernel_cpp.cpp + ] = [ FDirName $(HAIKU_TOP) src system kernel util ] ; + rule InstallISO9660 { Depends $(<) : $(>) ; diff --git a/src/add-ons/kernel/file_systems/iso9660/cache.h b/src/add-ons/kernel/file_systems/iso9660/cache.h deleted file mode 100644 index b491d141d7..0000000000 --- a/src/add-ons/kernel/file_systems/iso9660/cache.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef _CACHE_H_ -#define _CACHE_H_ - -#include - -typedef struct hash_ent { - int dev; - off_t bnum; - off_t hash_val; - void *data; - struct hash_ent *next; -} hash_ent; - - -typedef struct hash_table { - hash_ent **table; - int max; - int mask; /* == max - 1 */ - int num_elements; -} hash_table; - - -#define HT_DEFAULT_MAX 128 - - -typedef struct cache_ent { - int dev; - off_t block_num; - int bsize; - volatile int flags; - - void *data; - void *clone; /* copy of data by set_block_info() */ - int lock; - - void (*func)(off_t bnum, size_t num_blocks, void *arg); - off_t logged_bnum; - void *arg; - - struct cache_ent *next, /* points toward mru end of list */ - *prev; /* points toward lru end of list */ - -} cache_ent; - -#define CE_NORMAL 0x0000 /* a nice clean pristine page */ -#define CE_DIRTY 0x0002 /* needs to be written to disk */ -#define CE_BUSY 0x0004 /* this block has i/o happening, don't touch it */ - - -typedef struct cache_ent_list { - cache_ent *lru; /* tail of the list */ - cache_ent *mru; /* head of the list */ -} cache_ent_list; - - -typedef struct block_cache { - lock lock; - int flags; - int cur_blocks; - int max_blocks; - hash_table ht; - - cache_ent_list normal, /* list of "normal" blocks (clean & dirty) */ - locked; /* list of clean and locked blocks */ -} block_cache; - -#if 0 /* XXXdbg -- need to deal with write through caches */ -#define DC_WRITE_THROUGH 0x0001 /* cache is write-through (for floppies) */ -#endif - -#define ALLOW_WRITES 1 -#define NO_WRITES 0 - -extern _IMPEXP_KERNEL int init_block_cache(int max_blocks, int flags); -extern _IMPEXP_KERNEL void shutdown_block_cache(void); - -extern _IMPEXP_KERNEL void force_cache_flush(int dev, int prefer_log_blocks); -extern _IMPEXP_KERNEL int flush_blocks(int dev, off_t bnum, int nblocks); -extern _IMPEXP_KERNEL int flush_device(int dev, int warn_locked); - -extern _IMPEXP_KERNEL int init_cache_for_device(int fd, off_t max_blocks); -extern _IMPEXP_KERNEL int remove_cached_device_blocks(int dev, int allow_write); - -extern _IMPEXP_KERNEL void *get_block(int dev, off_t bnum, int bsize); -extern _IMPEXP_KERNEL void *get_empty_block(int dev, off_t bnum, int bsize); -extern _IMPEXP_KERNEL int release_block(int dev, off_t bnum); -extern _IMPEXP_KERNEL int mark_blocks_dirty(int dev, off_t bnum, int nblocks); - - -extern _IMPEXP_KERNEL int cached_read(int dev, off_t bnum, void *data, off_t num_blocks, int bsize); -extern _IMPEXP_KERNEL int cached_write(int dev, off_t bnum, const void *data, - off_t num_blocks, int bsize); -extern _IMPEXP_KERNEL int cached_write_locked(int dev, off_t bnum, const void *data, - off_t num_blocks, int bsize); -extern _IMPEXP_KERNEL int set_blocks_info(int dev, off_t *blocks, int nblocks, - void (*func)(off_t bnum, size_t nblocks, void *arg), - void *arg); - - -extern _IMPEXP_KERNEL size_t read_phys_blocks (int fd, off_t bnum, void *data, uint num_blocks, int bsize); -extern _IMPEXP_KERNEL size_t write_phys_blocks(int fd, off_t bnum, void *data, uint num_blocks, int bsize); - -#endif /* _CACHE_H_ */ diff --git a/src/add-ons/kernel/file_systems/iso9660/fsproto.h b/src/add-ons/kernel/file_systems/iso9660/fsproto.h deleted file mode 100644 index 000809c3bc..0000000000 --- a/src/add-ons/kernel/file_systems/iso9660/fsproto.h +++ /dev/null @@ -1,240 +0,0 @@ -#ifndef _FSPROTO_H -#define _FSPROTO_H - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -typedef dev_t nspace_id; -typedef ino_t vnode_id; - -/* - * PUBLIC PART OF THE FILE SYSTEM PROTOCOL - */ - -#define WSTAT_MODE 0x0001 -#define WSTAT_UID 0x0002 -#define WSTAT_GID 0x0004 -#define WSTAT_SIZE 0x0008 -#define WSTAT_ATIME 0x0010 -#define WSTAT_MTIME 0x0020 -#define WSTAT_CRTIME 0x0040 - -#define WFSSTAT_NAME 0x0001 - -#define B_ENTRY_CREATED 1 -#define B_ENTRY_REMOVED 2 -#define B_ENTRY_MOVED 3 -#define B_STAT_CHANGED 4 -#define B_ATTR_CHANGED 5 -#define B_DEVICE_MOUNTED 6 -#define B_DEVICE_UNMOUNTED 7 - -#define B_STOP_WATCHING 0x0000 -#define B_WATCH_NAME 0x0001 -#define B_WATCH_STAT 0x0002 -#define B_WATCH_ATTR 0x0004 -#define B_WATCH_DIRECTORY 0x0008 - -#define SELECT_READ 1 -#define SELECT_WRITE 2 -#define SELECT_EXCEPTION 3 - -#define B_CUR_FS_API_VERSION 2 - -struct attr_info; -struct index_info; - -typedef int op_read_vnode(void *ns, vnode_id vnid, char r, void **node); -typedef int op_write_vnode(void *ns, void *node, char r); -typedef int op_remove_vnode(void *ns, void *node, char r); -typedef int op_secure_vnode(void *ns, void *node); - -typedef int op_walk(void *ns, void *base, const char *file, char **newpath, - vnode_id *vnid); - -typedef int op_access(void *ns, void *node, int mode); - -typedef int op_create(void *ns, void *dir, const char *name, - int omode, int perms, vnode_id *vnid, void **cookie); -typedef int op_mkdir(void *ns, void *dir, const char *name, int perms); -typedef int op_symlink(void *ns, void *dir, const char *name, - const char *path); -typedef int op_link(void *ns, void *dir, const char *name, void *node); - -typedef int op_rename(void *ns, void *olddir, const char *oldname, - void *newdir, const char *newname); -typedef int op_unlink(void *ns, void *dir, const char *name); -typedef int op_rmdir(void *ns, void *dir, const char *name); - -typedef int op_readlink(void *ns, void *node, char *buf, size_t *bufsize); - -typedef int op_opendir(void *ns, void *node, void **cookie); -typedef int op_closedir(void *ns, void *node, void *cookie); -typedef int op_rewinddir(void *ns, void *node, void *cookie); -typedef int op_readdir(void *ns, void *node, void *cookie, long *num, - struct dirent *buf, size_t bufsize); - -typedef int op_open(void *ns, void *node, int omode, void **cookie); -typedef int op_close(void *ns, void *node, void *cookie); -typedef int op_free_cookie(void *ns, void *node, void *cookie); -typedef int op_read(void *ns, void *node, void *cookie, off_t pos, void *buf, - size_t *len); -typedef int op_write(void *ns, void *node, void *cookie, off_t pos, - const void *buf, size_t *len); -typedef int op_readv(void *ns, void *node, void *cookie, off_t pos, const iovec *vec, - size_t count, size_t *len); -typedef int op_writev(void *ns, void *node, void *cookie, off_t pos, const iovec *vec, - size_t count, size_t *len); -typedef int op_ioctl(void *ns, void *node, void *cookie, int cmd, void *buf, - size_t len); -typedef int op_setflags(void *ns, void *node, void *cookie, int flags); - -typedef int op_rstat(void *ns, void *node, struct stat *); -typedef int op_wstat(void *ns, void *node, struct stat *, long mask); -typedef int op_fsync(void *ns, void *node); - -typedef int op_select(void *ns, void *node, void *cookie, uint8 event, - uint32 ref, selectsync *sync); -typedef int op_deselect(void *ns, void *node, void *cookie, uint8 event, - selectsync *sync); - -typedef int op_initialize(const char *devname, void *parms, size_t len); -typedef int op_mount(nspace_id nsid, const char *devname, ulong flags, - void *parms, size_t len, void **data, vnode_id *vnid); -typedef int op_unmount(void *ns); -typedef int op_sync(void *ns); -typedef int op_rfsstat(void *ns, struct fs_info *); -typedef int op_wfsstat(void *ns, struct fs_info *, long mask); - - -typedef int op_open_attrdir(void *ns, void *node, void **cookie); -typedef int op_close_attrdir(void *ns, void *node, void *cookie); -typedef int op_rewind_attrdir(void *ns, void *node, void *cookie); -typedef int op_read_attrdir(void *ns, void *node, void *cookie, long *num, - struct dirent *buf, size_t bufsize); -typedef int op_remove_attr(void *ns, void *node, const char *name); -typedef int op_rename_attr(void *ns, void *node, const char *oldname, - const char *newname); -typedef int op_stat_attr(void *ns, void *node, const char *name, - struct attr_info *buf); - -typedef int op_write_attr(void *ns, void *node, const char *name, int type, - const void *buf, size_t *len, off_t pos); -typedef int op_read_attr(void *ns, void *node, const char *name, int type, - void *buf, size_t *len, off_t pos); - -typedef int op_open_indexdir(void *ns, void **cookie); -typedef int op_close_indexdir(void *ns, void *cookie); -typedef int op_rewind_indexdir(void *ns, void *cookie); -typedef int op_read_indexdir(void *ns, void *cookie, long *num, - struct dirent *buf, size_t bufsize); -typedef int op_create_index(void *ns, const char *name, int type, int flags); -typedef int op_remove_index(void *ns, const char *name); -typedef int op_rename_index(void *ns, const char *oldname, - const char *newname); -typedef int op_stat_index(void *ns, const char *name, struct index_info *buf); - -typedef int op_open_query(void *ns, const char *query, ulong flags, - port_id port, long token, void **cookie); -typedef int op_close_query(void *ns, void *cookie); -typedef int op_read_query(void *ns, void *cookie, long *num, - struct dirent *buf, size_t bufsize); - -typedef struct vnode_ops { - op_read_vnode (*read_vnode); - op_write_vnode (*write_vnode); - op_remove_vnode (*remove_vnode); - op_secure_vnode (*secure_vnode); - op_walk (*walk); - op_access (*access); - op_create (*create); - op_mkdir (*mkdir); - op_symlink (*symlink); - op_link (*link); - op_rename (*rename); - op_unlink (*unlink); - op_rmdir (*rmdir); - op_readlink (*readlink); - op_opendir (*opendir); - op_closedir (*closedir); - op_free_cookie (*free_dircookie); - op_rewinddir (*rewinddir); - op_readdir (*readdir); - op_open (*open); - op_close (*close); - op_free_cookie (*free_cookie); - op_read (*read); - op_write (*write); - op_readv (*readv); - op_writev (*writev); - op_ioctl (*ioctl); - op_setflags (*setflags); - op_rstat (*rstat); - op_wstat (*wstat); - op_fsync (*fsync); - op_initialize (*initialize); - op_mount (*mount); - op_unmount (*unmount); - op_sync (*sync); - op_rfsstat (*rfsstat); - op_wfsstat (*wfsstat); - op_select (*select); - op_deselect (*deselect); - op_open_indexdir (*open_indexdir); - op_close_indexdir (*close_indexdir); - op_free_cookie (*free_indexdircookie); - op_rewind_indexdir (*rewind_indexdir); - op_read_indexdir (*read_indexdir); - op_create_index (*create_index); - op_remove_index (*remove_index); - op_rename_index (*rename_index); - op_stat_index (*stat_index); - op_open_attrdir (*open_attrdir); - op_close_attrdir (*close_attrdir); - op_free_cookie (*free_attrdircookie); - op_rewind_attrdir (*rewind_attrdir); - op_read_attrdir (*read_attrdir); - op_write_attr (*write_attr); - op_read_attr (*read_attr); - op_remove_attr (*remove_attr); - op_rename_attr (*rename_attr); - op_stat_attr (*stat_attr); - op_open_query (*open_query); - op_close_query (*close_query); - op_free_cookie (*free_querycookie); - op_read_query (*read_query); -} vnode_ops; - -extern _IMPEXP_KERNEL int new_path(const char *path, char **copy); -extern _IMPEXP_KERNEL void free_path(char *p); - -extern _IMPEXP_KERNEL int notify_listener(int op, nspace_id nsid, - vnode_id vnida, vnode_id vnidb, - vnode_id vnidc, const char *name); -extern _IMPEXP_KERNEL int send_notification(port_id port, long token, - ulong what, long op, nspace_id nsida, - nspace_id nsidb, vnode_id vnida, - vnode_id vnidb, vnode_id vnidc, - const char *name); -extern _IMPEXP_KERNEL int get_vnode(nspace_id nsid, vnode_id vnid, void **data); -extern _IMPEXP_KERNEL int put_vnode(nspace_id nsid, vnode_id vnid); -extern _IMPEXP_KERNEL int new_vnode(nspace_id nsid, vnode_id vnid, void *data); -extern _IMPEXP_KERNEL int remove_vnode(nspace_id nsid, vnode_id vnid); -extern _IMPEXP_KERNEL int unremove_vnode(nspace_id nsid, vnode_id vnid); -extern _IMPEXP_KERNEL int is_vnode_removed(nspace_id nsid, vnode_id vnid); - - -extern _EXPORT vnode_ops fs_entry; -extern _EXPORT int32 api_version; - -#endif diff --git a/src/add-ons/kernel/file_systems/iso9660/iso.c b/src/add-ons/kernel/file_systems/iso9660/iso.c index b31c6d1d79..9ba8ee3444 100644 --- a/src/add-ons/kernel/file_systems/iso9660/iso.c +++ b/src/add-ons/kernel/file_systems/iso9660/iso.c @@ -16,18 +16,18 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include "rock.h" #include "iso.h" -#define TRACE_ISO9660 0 +//#define TRACE_ISO9660 1 #if TRACE_ISO9660 # define TRACE(x) dprintf x #else @@ -39,9 +39,6 @@ static status_t unicode_to_utf8(const char *src, int32 *srcLen, char *dst, int32 *dstLen); -// Size of primary volume descriptor for ISO9660 -#define ISO_PVD_SIZE 882 - // ISO9660 should start with this string const char *kISO9660IDString = "CD001"; @@ -55,7 +52,7 @@ static int InitVolDate(ISOVolDate *date, char *buf); static int InitRecDate(ISORecDate *date, char *buf); static int InitVolDesc(nspace *vol, char *buf); -#if 0 // currently unused +#if 0 // currently unused static int GetLogicalBlockSize(int fd) { @@ -91,7 +88,6 @@ GetNumDeviceBlocks(int fd, int block_size) } #endif - static int GetDeviceBlockSize(int fd) { @@ -271,7 +267,7 @@ ISOMount(const char *path, const int flags, nspace **newVol, bool allow_joliet) /* Initialize access to the cache so that we can do cached i/o */ TRACE(("ISO9660: cache init: dev %d, max blocks %Ld\n", vol->fd, maxBlocks)); - init_cache_for_device(vol->fd,maxBlocks); + vol->fBlockCache = block_cache_create(vol->fd, maxBlocks, vol->logicalBlkSize[FS_DATA_FORMAT]); is_iso = true; } else if ((*buffer == 0x02) && is_iso && allow_joliet) { // ISO_VD_SUPPLEMENTARY @@ -347,13 +343,13 @@ ISOReadDirEnt(nspace *ns, dircookie *cookie, struct dirent *dirent, size_t bufsi // If we're at the end of the data in a block, move to the next block. while (1) { - blockData = (char *)get_block(ns->fd, cookie->block, + blockData = (char *)block_cache_get_etc(ns->fBlockCache, cookie->block, 0, ns->logicalBlkSize[FS_DATA_FORMAT]); block_out = true; if (blockData != NULL && *(blockData + cookie->pos) == 0) { //NULL data, move to next block. - release_block(ns->fd, cookie->block); + block_cache_put(ns->fBlockCache, cookie->block); block_out = false; totalRead += ns->logicalBlkSize[FS_DATA_FORMAT] - cookie->pos; cookie->pos = 0; @@ -397,7 +393,7 @@ ISOReadDirEnt(nspace *ns, dircookie *cookie, struct dirent *dirent, size_t bufsi } if (block_out) - release_block(ns->fd, cacheBlock); + block_cache_put(ns->fBlockCache, cacheBlock); TRACE(("ISOReadDirEnt - EXIT, result is %s, vnid is %Lu\n", strerror(result), dirent->d_ino)); return result; diff --git a/src/add-ons/kernel/file_systems/iso9660/iso.h b/src/add-ons/kernel/file_systems/iso9660/iso.h index 656b78113d..3f268aabdc 100644 --- a/src/add-ons/kernel/file_systems/iso9660/iso.h +++ b/src/add-ons/kernel/file_systems/iso9660/iso.h @@ -10,13 +10,16 @@ #include #include -#include +#include #include #include #include #include +// Size of primary volume descriptor for ISO9660 +#define ISO_PVD_SIZE 882 + // ISO structure has both msb and lsb first data. These let you do a // compile-time switch for different platforms. @@ -168,10 +171,11 @@ typedef struct attrfilemap typedef struct nspace { // Start of members other drivers will definitely want. - nspace_id id; // ID passed in to fs_mount + mount_id id; // ID passed in to fs_mount int fd; // File descriptor int fdOfSession; // File descriptor of the (mounted) session //unsigned int blockSize; // usually need this, but it's part of ISO + void *fBlockCache; char devicePath[127]; //off_t numBlocks; // May need this, but it's part of ISO @@ -222,9 +226,17 @@ typedef struct nspace uint8 fileStructVers; // File structure version byte882 } nspace; +#ifdef __cplusplus +extern "C" { +#endif + int ISOMount(const char *path, const int flags, nspace** newVol, bool allow_joliet); int ISOReadDirEnt(nspace* ns, dircookie* cookie, struct dirent* buf, size_t bufsize); int InitNode(vnode* rec, char* buf, int* bytesRead, uint8 joliet_level); int ConvertRecDate(ISORecDate* inDate, time_t* outDate); +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/add-ons/kernel/file_systems/iso9660/iso9660.cpp b/src/add-ons/kernel/file_systems/iso9660/iso9660.cpp new file mode 100644 index 0000000000..44aff14f3f --- /dev/null +++ b/src/add-ons/kernel/file_systems/iso9660/iso9660.cpp @@ -0,0 +1,568 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file iso9660.cpp + \brief disk_scanner filesystem module for iso9660 CD-ROM filesystems + +
iso9660
+ The standard to which this module is written is ECMA-119 second + edition, a freely available iso9660 equivalent. + +
Joliet
+ Joliet support comes courtesy of the following document: + + http://www-plateau.cs.berkeley.edu/people/chaffee/jolspec.htm + + As specified there, the existence of any of the following escape + sequences in a supplementary volume descriptor's "escape sequences" + field denotes a Joliet volume descriptor using unicode ucs-2 + character encoding (2-byte characters, big-endian): + + - UCS-2 Level 1: 0x252F40 == "%/@" + - UCS-2 Level 2: 0x252F43 == "%/C" + - UCS-2 Level 3: 0x252F45 == "%/E" + + The following UCS-2 characters are considered illegal (we allow them, + printing out a warning if encountered): + + - All values between 0x0000 and 0x001f inclusive == control chars + - 0x002A == '*' + - 0x002F == '/' + - 0x003A == ':' + - 0x003B == ';' + - 0x003F == '?' + - 0x005C == '\' +*/ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "iso.h" +#include "iso9660.h" + +//#define TRACE(x) ; +#define TRACE(x) dprintf x + +// misc constants +static const char *kISO9660Signature = "CD001"; +static const uint32 kVolumeDescriptorLength = 2048; +#define ISO9660_VOLUME_IDENTIFIER_LENGTH 32 +#define ISO9660_ESCAPE_SEQUENCE_LENGTH 32 + +//! Volume descriptor types +typedef enum { + ISO9660VD_BOOT, + ISO9660VD_PRIMARY, + ISO9660VD_SUPPLEMENTARY, + ISO9660VD_PARTITION, + ISO9660VD_TERMINATOR = 255 +} iso9660_volume_descriptor_type; + +/*! \brief The portion of the volume descriptor common to all + descriptor types. +*/ +typedef struct iso9660_common_volume_descriptor { + uchar volume_descriptor_type; + char standard_identifier[5]; // should be 'CD001' + uchar volume_descriptor_version; + // Remaining bytes are unused +} __attribute__((packed)) iso9660_common_volume_descriptor; + +/*! \brief Primary volume descriptor +*/ +typedef struct iso9660_primary_volume_descriptor { + iso9660_common_volume_descriptor info; + uchar volume_flags; + char system_identifier[32]; + char volume_identifier[ISO9660_VOLUME_IDENTIFIER_LENGTH]; + uchar unused01[8]; + uint32 volume_space_size_little_endian; + uint32 volume_space_size_big_endian; + uchar unused02[ISO9660_ESCAPE_SEQUENCE_LENGTH]; + uint16 volume_set_size_little_endian; + uint16 volume_set_size_big_endian; + uint16 volume_sequence_number_little_endian; + uint16 volume_sequence_number_big_endian; + uint16 logical_block_size_little_endian; + uint16 logical_block_size_big_endian; + uint32 path_table_size_little_endian; + uint32 path_table_size_big_endian; + uint32 ignored02[4]; + uchar root_directory_record[34]; + char volume_set_identifier[28]; + // Remaining bytes are disinteresting to us +} __attribute__((packed)) iso9660_primary_volume_descriptor; + +typedef struct iso9660_supplementary_volume_descriptor { + iso9660_common_volume_descriptor info; + uchar volume_flags; + char system_identifier[32]; + char volume_identifier[ISO9660_VOLUME_IDENTIFIER_LENGTH]; + uchar unused01[8]; + uint32 volume_space_size_little_endian; + uint32 volume_space_size_big_endian; + char escape_sequences[ISO9660_ESCAPE_SEQUENCE_LENGTH]; + uint16 volume_set_size_little_endian; + uint16 volume_set_size_big_endian; + uint16 volume_sequence_number_little_endian; + uint16 volume_sequence_number_big_endian; + uint16 logical_block_size_little_endian; + uint16 logical_block_size_big_endian; + uint32 path_table_size_little_endian; + uint32 path_table_size_big_endian; + uint32 ignored02[4]; + uchar root_directory_record[34]; + char volume_set_identifier[28]; + // Remaining bytes are disinteresting to us +} __attribute__((packed)) iso9660_supplementary_volume_descriptor; + +typedef struct iso9660_directory_record { + uint8 length; + uint8 extended_attribute_record_length; + uint32 location_le; + uint32 location_be; + uint32 data_length; + uchar ignored[14]; + uint16 volume_space_le; +} __attribute__((packed)) iso9660_directory_record; + +//---------------------------------------------------------------------------- +// iso9660_info +//---------------------------------------------------------------------------- + +/*! \brief Creates a new iso9660_info struct with empty volume names. + + \note Use the applicable set_XYZ_volume_name() functions rather than + messing with the volume name data members directly. +*/ +iso9660_info::iso9660_info() + : iso9660_volume_name(NULL) + , joliet_volume_name(NULL) +{ +} + +/*! \brief Destroys the struct, freeing the volume name strings. +*/ +iso9660_info::~iso9660_info() +{ + if (iso9660_volume_name) { + free(iso9660_volume_name); + iso9660_volume_name = NULL; + } + if (joliet_volume_name) { + free(joliet_volume_name); + joliet_volume_name = NULL; + } +} + +/*! \brief Returns true if a valid volume name exists. +*/ +bool +iso9660_info::is_valid() +{ + return iso9660_volume_name || joliet_volume_name; +} + +/*! \brief Sets the iso9660 volume name. + + \param name UTF-8 string containing the name. + \param length The length (in bytes) of the string. +*/ +void +iso9660_info::set_iso9660_volume_name(const char *name, uint32 length) +{ + set_string(&iso9660_volume_name, name, length); +} + +/*! \brief Sets the Joliet volume name. + + \param name UTF-8 string containing the name. + \param length The length (in bytes) of the string. +*/ +void +iso9660_info::set_joliet_volume_name(const char *name, uint32 length) +{ + set_string(&joliet_volume_name, name, length); +} + +/*! \brief Returns the volume name of highest precedence. + + Currently, the ordering is (decreasingly): + - Joliet + - iso9660 +*/ +const char* +iso9660_info::get_preferred_volume_name() +{ + if (joliet_volume_name) + return joliet_volume_name; + else + return iso9660_volume_name; +} + +/*! \brief Copies the given string into the old string, managing memory + deallocation and allocation as necessary. +*/ +void +iso9660_info::set_string(char **string, const char *new_string, uint32 new_length) +{ + TRACE(("iso9660_info::set_string(%p (`%s'), `%s', %ld)\n", string, *string, new_string, new_length)); + if (string) { + char *&old_string = *string; + if (old_string) + free(old_string); + if (new_string) { + old_string = (char*)malloc(new_length+1); + if (old_string) { + strncpy(old_string, new_string, new_length); + old_string[new_length] = 0; + } + } else { + old_string = NULL; + } + } +} + +//---------------------------------------------------------------------------- +// C functions +//---------------------------------------------------------------------------- + +/*! \brief Converts the given unicode character to utf8. + + Courtesy Mr. Axel Dörfler. + + \todo Once OpenTracker's locale kit is done, perhaps that functionality + should be used rather than outright stealing the code. +*/ +static +void +unicode_to_utf8(uint32 c, char **out) +{ + char *s = *out; + + if (c < 0x80) + *(s++) = c; + else if (c < 0x800) { + *(s++) = 0xc0 | (c>>6); + *(s++) = 0x80 | (c & 0x3f); + } else if (c < 0x10000) { + *(s++) = 0xe0 | (c>>12); + *(s++) = 0x80 | ((c>>6) & 0x3f); + *(s++) = 0x80 | (c & 0x3f); + } else if (c <= 0x10ffff) { + *(s++) = 0xf0 | (c>>18); + *(s++) = 0x80 | ((c>>12) & 0x3f); + *(s++) = 0x80 | ((c>>6) & 0x3f); + *(s++) = 0x80 | (c & 0x3f); + } + *out = s; +} + +static +const char* +volume_descriptor_type_to_string(iso9660_volume_descriptor_type type) +{ + switch (type) { + case ISO9660VD_BOOT: return "boot"; + case ISO9660VD_PRIMARY: return "primary"; + case ISO9660VD_SUPPLEMENTARY: return "supplementary"; + case ISO9660VD_PARTITION: return "partiton"; + case ISO9660VD_TERMINATOR: return "terminator"; + default: return "invalid"; + } +} + +static +void +dump_common_volume_descriptor(iso9660_common_volume_descriptor *common, const char *indent, + bool print_header) +{ + if (print_header) + TRACE(("%siso9660_common_volume_descriptor:\n", indent)); + + TRACE(("%s volume descriptor type == %d (%s)\n", indent, + common->volume_descriptor_type, + volume_descriptor_type_to_string((iso9660_volume_descriptor_type)common->volume_descriptor_type))); + TRACE(("%s standard identifier == %.5s (%s)\n", indent, common->standard_identifier, + strncmp(common->standard_identifier, kISO9660Signature, 5) == 0 ? "valid" : "INVALID")); + TRACE(("%s volume descriptor version == %d\n", indent, common->volume_descriptor_version)); +} + +static +void +dump_directory_record(iso9660_directory_record *record, const char *indent); + +static +void +dump_primary_volume_descriptor(iso9660_primary_volume_descriptor *primary, const char *indent, + bool print_header) +{ + if (print_header) + TRACE(("%siso9660_primary_volume_descriptor:\n", indent)); + + dump_common_volume_descriptor(&(primary->info), indent, false); + TRACE(("%s volume identifier == `%.32s'\n", indent, + primary->volume_identifier)); + TRACE(("%s volume space size == %ld\n", indent, + primary->volume_space_size_little_endian)); + TRACE(("%s volume set size == %d\n", indent, + primary->volume_set_size_little_endian)); + TRACE(("%s volume sequence number == %d\n", indent, + primary->volume_sequence_number_little_endian)); + TRACE(("%s logical block size == %d\n", indent, + primary->logical_block_size_little_endian)); + TRACE(("%s path table size == %ld\n", indent, + primary->path_table_size_little_endian)); + TRACE(("%s volume set identifier == %.28s\n", indent, + primary->volume_set_identifier)); + dump_directory_record((iso9660_directory_record*)primary->root_directory_record, indent); +} + +static +void +dump_supplementary_volume_descriptor(iso9660_supplementary_volume_descriptor *supplementary, const char *indent, + bool print_header) +{ + if (print_header) + TRACE(("%siso9660_supplementary_volume_descriptor:\n", indent)); + + dump_primary_volume_descriptor((iso9660_primary_volume_descriptor*)supplementary, indent, false); + TRACE(("%s escape sequences ==", indent)); + for (int i = 0; i < ISO9660_ESCAPE_SEQUENCE_LENGTH; i++) { + TRACE((" %2x", supplementary->escape_sequences[i])); + if (i == ISO9660_ESCAPE_SEQUENCE_LENGTH/2-1) + TRACE(("\n ")); + } + TRACE(("\n")); +} + +static +void +dump_directory_record(iso9660_directory_record *record, const char *indent) +{ + TRACE(("%s root directory record:\n", indent)); + TRACE(("%s length == %d\n", indent, record->length)); + TRACE(("%s location == %ld\n", indent, record->location_le)); + TRACE(("%s data length == %ld\n", indent, record->data_length)); + TRACE(("%s volume sequence number == %d\n", indent, record->volume_space_le)); +} + +static +status_t +check_common_volume_descriptor(iso9660_common_volume_descriptor *common) +{ + status_t error = common ? B_OK : B_BAD_VALUE; + if (!error) { + error = strncmp(common->standard_identifier, kISO9660Signature, + 5) == 0 ? B_OK : B_BAD_DATA; + } + return error; +} + + +// iso9660_fs_identify +/*! \brief Returns true if the given partition is a valid iso9660 partition. + + See fs_identify_hook() for more information. + + \todo Fill in partitionInfo->mounted_at with something useful. +*/ +status_t +iso9660_fs_identify(int deviceFD, iso9660_info *info) +{ + bool result = false; + uchar *buffer = NULL; + bool exit = false; + status_t error = B_OK; + nspace *vol; + + TRACE(("identify(%d, %p)\n", deviceFD, info)); + off_t offset = 0x8000; + + vol = (nspace *)calloc(sizeof(nspace), 1); + if (vol == NULL) { + return ENOMEM; + } + + vol->fd = deviceFD; + + // Read through the volume descriptors looking for a primary descriptor. + // If for some reason there are more than one primary descriptor, the + // volume name from the last encountered descriptor will be used. + while (!error && !exit) {// && count++ < 10) { + iso9660_common_volume_descriptor *common = NULL; + + // Read the block containing the current descriptor + error = read_pos (vol->fdOfSession, offset, (void *)&buffer, ISO_PVD_SIZE); + offset += ISO_PVD_SIZE; + if (error < ISO_PVD_SIZE) { + break; + } + + common = (iso9660_common_volume_descriptor*)buffer; + error = check_common_volume_descriptor(common); +// dump_common_volume_descriptor(common, "", true); + + // Handle each type of descriptor appropriately + if (!error) { + TRACE(("found %s descriptor\n", volume_descriptor_type_to_string((iso9660_volume_descriptor_type)common->volume_descriptor_type))); + + switch (common->volume_descriptor_type) { + case ISO9660VD_BOOT: + break; + + case ISO9660VD_PRIMARY: + { + int i; + iso9660_primary_volume_descriptor *primary = (iso9660_primary_volume_descriptor*)buffer; + + dump_primary_volume_descriptor(primary, " ", true); + + // Cut off any trailing spaces from the volume id. Note + // that this allows for spaces INSIDE the volume id, even + // though that's not technically allowed by the standard; + // this was necessary to support certain RedHat 6.2 CD-ROMs + // from a certain Linux company who shall remain unnamed. ;-) + for (i = ISO9660_VOLUME_IDENTIFIER_LENGTH-1; i >= 0; i--) { + if (primary->volume_identifier[i] != 0x20) + break; + } + + // Give a holler if the iso9660 name is already set + if (info->iso9660_volume_name) { + char str[ISO9660_VOLUME_IDENTIFIER_LENGTH+1]; + strncpy(str, primary->volume_identifier, i+1); + str[i+1] = 0; + TRACE(("duplicate iso9660 volume name found, using latter (`%s') " + "instead of former (`%s')\n", str, + info->iso9660_volume_name)); + } + + info->set_iso9660_volume_name(primary->volume_identifier, i+1); + info->maxBlocks = primary->volume_set_size_little_endian; + break; + } + + case ISO9660VD_SUPPLEMENTARY: + { + iso9660_supplementary_volume_descriptor *supplementary = (iso9660_supplementary_volume_descriptor*)buffer; + dump_supplementary_volume_descriptor((iso9660_supplementary_volume_descriptor*)supplementary, " ", true); + + // Copy and null terminate the escape sequences + char escapes[ISO9660_ESCAPE_SEQUENCE_LENGTH+1]; + strncpy(escapes, supplementary->escape_sequences, ISO9660_ESCAPE_SEQUENCE_LENGTH); + escapes[ISO9660_ESCAPE_SEQUENCE_LENGTH] = 0; + + // Check for a Joliet VD + if (strstr(escapes, "%/@") || strstr(escapes, "%/C") || strstr(escapes, "%/E")) { + char str[(ISO9660_VOLUME_IDENTIFIER_LENGTH*3/2)+1]; + // Since we're dealing with 16-bit Unicode, each UTF-8 sequence + // will be at most 3 bytes long. So we need 3/2 as many chars as + // we start out with. + char *str_iterator = str; + uint16 ch; + + // Walk thru the unicode volume name, converting to utf8 as we go. + for (int i = 0; + (ch = B_BENDIAN_TO_HOST_INT16(((uint16*)supplementary->volume_identifier)[i])) + && i < ISO9660_VOLUME_IDENTIFIER_LENGTH; + i++) { + // Give a warning if the character is technically illegal + if ( ch <= 0x001F + || ch == 0x002A + || ch == 0x002F + || ch == 0x003A + || ch == 0x003B + || ch == 0x003F + || ch == 0x005C) + { + TRACE(("warning: illegal Joliet character found: 0%4x\n", ch)); + } + + // Convert to utf-8 + unicode_to_utf8(ch, &str_iterator); + } + *str_iterator = 0; + + // Give a holler if the joliet name is already set + if (info->joliet_volume_name) { + TRACE(("duplicate joliet volume name found, using latter (`%s') " + "instead of former (`%s')\n", str, + info->joliet_volume_name)); + } + + info->set_joliet_volume_name(str, strlen(str)); + } // end "if Joliet VD" + break; + } + + case ISO9660VD_PARTITION: + break; + + case ISO9660VD_TERMINATOR: + exit = true; + break; + + default: + break; + } + } + if (buffer) { + free(buffer); + buffer = NULL; + } + } + + free(vol); + + return error; +/* + switch (error) { + case B_OK: + if (info.is_valid()) { + result = true; + if (partitionInfo->file_system_short_name) + strcpy(partitionInfo->file_system_short_name, "iso9660"); + if (partitionInfo->file_system_long_name) + strcpy(partitionInfo->file_system_long_name, "iso9660 CD-ROM File System"); + partitionInfo->file_system_flags = B_FS_IS_PERSISTENT; + if (priority) + *priority = 0; + // Copy the volume name of highest precedence + if (partitionInfo->volume_name) { + TRACE(("%s: iso9660 name: `%s'\n", kModuleDebugName, info.iso9660_volume_name)); + TRACE(("%s: joliet name: `%s'\n", kModuleDebugName, info.joliet_volume_name)); + const char *name = info.get_preferred_volume_name(); + int length = strlen(name); + if (length > B_FILE_NAME_LENGTH-1) + length = B_FILE_NAME_LENGTH-1; + strncpy(partitionInfo->volume_name, name, length); + partitionInfo->volume_name[length] = 0; + } + return 0.8; + } + break; + + case B_BAD_DATA: + TRACE(("%s: identify: bad signature\n", kModuleDebugName)); + break; + + default: + TRACE(("%s: identify error: 0x%lx\n", kModuleDebugName, + error)); + break; + } + + return 0.0; +*/ +} + diff --git a/src/add-ons/kernel/file_systems/iso9660/iso9660.h b/src/add-ons/kernel/file_systems/iso9660/iso9660.h new file mode 100644 index 0000000000..ef3ee57def --- /dev/null +++ b/src/add-ons/kernel/file_systems/iso9660/iso9660.h @@ -0,0 +1,34 @@ +#ifndef _ISO9660_H +#define _ISO9660_H + +/*! \brief Contains all the info of interest pertaining to an + iso9660 volume. + + Currently supported character set encoding styles (in decreasing + order of precedence): + - Joliet (UCS-12 (16-bit unicode), which is converted to UTF-8) + - iso9660 (some absurdly tiny character set, but we actually allow UTF-8) +*/ +struct iso9660_info { + iso9660_info(); + ~iso9660_info(); + + bool is_valid(); + + void set_iso9660_volume_name(const char *name, uint32 length); + void set_joliet_volume_name(const char *name, uint32 length); + + const char* get_preferred_volume_name(); + + char *iso9660_volume_name; + char *joliet_volume_name; + + off_t maxBlocks; + + void set_string(char **string, const char *new_string, uint32 new_length); +}; + +status_t iso9660_fs_identify(int deviceFD, iso9660_info *info); + +#endif + diff --git a/src/add-ons/kernel/file_systems/iso9660/kernel_interface.c b/src/add-ons/kernel/file_systems/iso9660/kernel_interface.cpp similarity index 66% rename from src/add-ons/kernel/file_systems/iso9660/kernel_interface.c rename to src/add-ons/kernel/file_systems/iso9660/kernel_interface.cpp index 30bb3c21fa..b317a89ac8 100644 --- a/src/add-ons/kernel/file_systems/iso9660/kernel_interface.c +++ b/src/add-ons/kernel/file_systems/iso9660/kernel_interface.cpp @@ -13,21 +13,31 @@ #include #include #include -#include #include #include #include #include -#include #include -#include #include -#include #include -#include "iso.h" +#include +#include +#include +#include -#define TRACE_ISO9660 0 +#include +#include +#include +#include +#include + +#include + +#include "iso.h" +#include "iso9660.h" + +//#define TRACE_ISO9660 1 #if TRACE_ISO9660 # define TRACE(x) dprintf x #else @@ -36,125 +46,101 @@ /* Start of fundamental (read-only) required functions */ -static int fs_mount(nspace_id nsid, const char *device, ulong flags, - void *parms, size_t len, void **data, vnode_id *vnid); -static int fs_unmount(void *_ns); +static status_t fs_mount(mount_id mountID, const char *device, uint32 flags, + const char *args, void **_data, vnode_id *_rootID); +static status_t fs_unmount(void *ns); -int fs_walk(void *_ns, void *_base, const char *file, - char **newpath, vnode_id *vnid); +static status_t fs_walk(void *_ns, void *_base, const char *file, + vnode_id *_vnodeID, int *_type); -int fs_read_vnode(void *_ns, vnode_id vnid, char r, void **node); -int fs_write_vnode(void *_ns, void *_node, char r); -static int fs_read_stat(void *_ns, void *_node, struct stat *st); -static int fs_open(void *_ns, void *_node, int omode, void **cookie); -static int fs_read(void *_ns, void *_node, void *cookie, off_t pos, - void *buf, size_t *len); +static status_t fs_read_vnode(void *_ns, vnode_id vnid, void **node, bool reenter); +static status_t fs_release_vnode(void *_ns, void *_node, bool reenter); +static status_t fs_read_stat(void *_ns, void *_node, struct stat *st); +static status_t fs_open(void *_ns, void *_node, int omode, void **cookie); +static status_t fs_read(void *_ns, void *_node, void *cookie, off_t pos, + void *buf, size_t *len); /// fs_free_cookie - free cookie for file created in open. -static int fs_free_cookie(void *ns, void *node, void *cookie); -static int fs_close(void *ns, void *node, void *cookie); +static status_t fs_free_cookie(void *ns, void *node, void *cookie); +static status_t fs_close(void *ns, void *node, void *cookie); // fs_access - checks permissions for access. -static int fs_access(void *_ns, void *_node, int mode); +static status_t fs_access(void *_ns, void *_node, int mode); // fs_opendir - creates fs-specific "cookie" struct that can tell where // we are at in the directory list. -static int fs_open_dir(void* _ns, void* _node, void** cookie); +static status_t fs_open_dir(void* _ns, void* _node, void** cookie); // fs_readdir - read 1 or more dirents, keep state in cookie, return // 0 when no more entries. -static int fs_read_dir(void *_ns, void *_node, void *cookie, - long *num, struct dirent *buf, size_t bufsize); +static status_t fs_read_dir(void *_ns, void *_node, void *cookie, struct dirent *buf, + size_t bufsize, uint32 *_num); // fs_rewinddir - set cookie to represent beginning of directory, so // later fs_readdir calls start at beginning. -static int fs_rewind_dir(void *_ns, void *_node, void *cookie); +static status_t fs_rewind_dir(void *_ns, void *_node, void *cookie); // fs_closedir - Do whatever you need to to close a directory (sometimes // nothing), but DON'T free the cookie! -static int fs_close_dir(void *_ns, void *_node, void *cookie); +static status_t fs_close_dir(void *_ns, void *_node, void *cookie); // fs_fee_dircookie - Free the fs-specific cookie struct -static int fs_free_dir_cookie(void *_ns, void *_node, void *cookie); +static status_t fs_free_dir_cookie(void *_ns, void *_node, void *cookie); // fs_rfsstat - Fill in fs_info struct for device. -static int fs_read_fs_stat(void *_ns, struct fs_info *); +static status_t fs_read_fs_stat(void *_ns, struct fs_info *); // fs_readlink - Read in the name of a symbolic link. -static int fs_read_link(void *_ns, void *_node, char *buf, size_t *bufsize); +static status_t fs_read_link(void *_ns, void *_node, char *buf, size_t *bufsize); +// #pragma mark - Scanning -/* vnode_ops struct. Fill this in to tell the kernel how to call - functions in your driver. -*/ - -vnode_ops fs_entry = { - &fs_read_vnode, // read_vnode func ptr - &fs_write_vnode, // write_vnode func ptr - NULL, // remove_vnode func ptr - NULL, // secure_vnode func ptr - &fs_walk, // walk func ptr - &fs_access, // access func ptr - NULL, // create func ptr - NULL, // mkdir func ptr - NULL, - NULL, - NULL, - NULL, // unlink func ptr - NULL, // rmdir func ptr - &fs_read_link, // readlink func ptr - &fs_open_dir, // opendir func ptr - &fs_close_dir, // closedir func ptr - &fs_free_dir_cookie, // free_dircookie func ptr - &fs_rewind_dir, // rewinddir func ptr - &fs_read_dir, // readdir func ptr - &fs_open, // open file func ptr - &fs_close, // close file func ptr - &fs_free_cookie, // free cookie func ptr - &fs_read, // read file func ptr - NULL, // write file func ptr - NULL, /* readv */ - NULL, /* writev */ - NULL, // ioctl func ptr - NULL, // setflags file func ptr - &fs_read_stat, // rstat func ptr - NULL, // wstat func ptr - NULL, - NULL, // initialize func ptr - &fs_mount, // mount func ptr - &fs_unmount, // unmount func ptr - NULL, // sync func ptr - &fs_read_fs_stat, // rfsstat func ptr - NULL, // wfsstat func ptr - NULL, - NULL, - NULL, // open indexdir func ptr - NULL, // close indexdir func ptr - NULL, // free indexdir cookie func ptr - NULL, // rewind indexdir func ptr - NULL, // read indexdir func ptr - NULL, // create index func ptr - NULL, // remove index func ptr - NULL, // rename index func ptr - NULL, // stat index func ptr - NULL, //&isofs_open_attrdir, // open attrdir func ptr - NULL, //&isofs_close_attrdir, // close attrdir func ptr - NULL, //&isofs_free_attrdir_cookie, // free attrdir cookie func ptr - NULL, //&isofs_rewind_attrdir, // rewind attrdir func ptr - NULL, //&isofs_read_attrdir, // read attrdir func ptr - NULL, // write attr func ptr - NULL, //&isofs_read_attr, // read attr func ptr - NULL, // remove attr func ptr - NULL, // rename attr func ptr - NULL, //&isofs_stat_attr, // stat attr func ptr - NULL, // open query func ptr - NULL, // close query func ptr - NULL, // free query cookie func ptr - NULL // read query func ptr +struct identify_cookie { + iso9660_info info; }; -int32 api_version = B_CUR_FS_API_VERSION; + +static float +fs_identify_partition(int fd, partition_data *partition, void **_cookie) +{ + iso9660_info info; + status_t status = iso9660_fs_identify(fd, &info); + if (status != B_OK) + return status; + + identify_cookie *cookie = new identify_cookie; + memcpy(&cookie->info, &info, sizeof(info)); + + *_cookie = cookie; + return 0.8f; +} -static int -fs_mount(nspace_id nsid, const char *device, ulong flags, void *parms, - size_t len, void **data, vnode_id *vnid) +static status_t +fs_scan_partition(int fd, partition_data *partition, void *_cookie) +{ + identify_cookie *cookie = (identify_cookie *)_cookie; + + partition->status = B_PARTITION_VALID; + partition->flags |= B_PARTITION_FILE_SYSTEM | B_PARTITION_READ_ONLY ; + partition->block_size = ISO_PVD_SIZE; + partition->content_size = ISO_PVD_SIZE * cookie->info.maxBlocks; + partition->content_name = strdup(cookie->info.get_preferred_volume_name()); + if (partition->content_name == NULL) + return B_NO_MEMORY; + + return B_OK; +} + + +static void +fs_free_identify_partition_cookie(partition_data *partition, void *_cookie) +{ + identify_cookie *cookie = (identify_cookie *)_cookie; + + delete cookie; +} + + +static status_t +fs_mount(mount_id mountID, const char *device, uint32 flags, + const char *args, void **_data, vnode_id *_rootID) { /* Kernel passes in nspace_id, (representing a disk or partition?) @@ -167,7 +153,7 @@ fs_mount(nspace_id nsid, const char *device, ulong flags, void *parms, fs driver functions. vnid should also be passed back to the kernel, representing the vnode id of the root vnode. */ - int result = EINVAL; + status_t result = EINVAL; // return EINVAL if it's not a device compatible with the driver. bool allow_joliet = true; nspace *vol; @@ -179,21 +165,12 @@ fs_mount(nspace_id nsid, const char *device, ulong flags, void *parms, // Check for a 'nojoliet' parm // all we check for is the existance of 'nojoliet' in the parms. - if (parms != NULL) { + if (args != NULL) { uint32 i; char *spot; - char *buf; + char *buf = strdup(args); - // Make sure the len argument isn't too large - if (len > 1024) - return EINVAL; - - buf = malloc(len + 1); - if (!buf) - return ENOMEM; - - memcpy(buf, parms, len); - buf[len] = 0; + uint32 len = strlen(buf); // lower case the parms data for (i = 0; i < len + 1; i++) buf[i] = tolower(buf[i]); @@ -202,7 +179,7 @@ fs_mount(nspace_id nsid, const char *device, ulong flags, void *parms, spot = strstr(buf, "nojoliet"); if (spot != NULL) allow_joliet = false; - + free(buf); } @@ -213,15 +190,15 @@ fs_mount(nspace_id nsid, const char *device, ulong flags, void *parms, if (result == B_NO_ERROR) { //vnode_id rootID = vol->rootDirRec.startLBN[FS_DATA_FORMAT]; //*vnid = rootID; - *vnid = ISO_ROOTNODE_ID; - *data = (void*)vol; - - vol->id = nsid; + *_rootID = ISO_ROOTNODE_ID; + *_data = (void*)vol; + + vol->id = mountID; // You MUST do this. Create the vnode for the root. - result = new_vnode(nsid, *vnid, (void*)&(vol->rootDirRec)); + result = publish_vnode(mountID, *_rootID, (void*)&(vol->rootDirRec)); if (result != B_NO_ERROR) { - remove_cached_device_blocks(vol->fd, 0); + block_cache_delete(vol->fBlockCache, false); free(vol); result = EINVAL; } else @@ -231,15 +208,15 @@ fs_mount(nspace_id nsid, const char *device, ulong flags, void *parms, } -static int +static status_t fs_unmount(void *_ns) { - int result = B_NO_ERROR; + status_t result = B_NO_ERROR; nspace *ns = (nspace *)_ns; TRACE(("fs_unmount - ENTER\n")); - remove_cached_device_blocks(ns->fd, 0); + block_cache_delete(ns->fBlockCache, false); close(ns->fdOfSession); result = close(ns->fd); @@ -250,7 +227,7 @@ fs_unmount(void *_ns) } -static int +static status_t fs_read_fs_stat(void *_ns, struct fs_info *fss) { // Fill in fs_info struct for device. @@ -304,10 +281,8 @@ fs_read_fs_stat(void *_ns, struct fs_info *fss) the specified file. When you find it, call get_vnode on its vnid to init it for the kernel. */ - -int -fs_walk(void *_ns, void *base, const char *file, char **newpath, - vnode_id *vnid) +static status_t +fs_walk(void *_ns, void *base, const char *file, vnode_id *_vnodeID, int *_type) { /* Starting at the base, find file in the subdir, and return path string and vnode id of file. */ @@ -315,7 +290,7 @@ fs_walk(void *_ns, void *base, const char *file, char **newpath, vnode *baseNode = (vnode*)base; uint32 dataLen = baseNode->dataLen[FS_DATA_FORMAT]; vnode *newNode = NULL; - int result = ENOENT; + status_t result = ENOENT; bool done = FALSE; uint32 totalRead = 0; off_t block = baseNode->startLBN[FS_DATA_FORMAT]; @@ -326,16 +301,18 @@ fs_walk(void *_ns, void *base, const char *file, char **newpath, if (strcmp(file, ".") == 0) { // base directory TRACE(("fs_walk - found \".\" file.\n")); - *vnid = baseNode->id; - if (get_vnode(ns->id, *vnid, (void **)&newNode) != 0) + *_vnodeID = baseNode->id; + *_type = S_IFDIR; + if (get_vnode(ns->id, *_vnodeID, (void **)&newNode) != 0) result = EINVAL; else result = B_NO_ERROR; } else if (strcmp(file, "..") == 0) { // parent directory TRACE(("fs_walk - found \"..\" file.\n")); - *vnid = baseNode->parID; - if (get_vnode(ns->id, *vnid, (void **)&newNode) != 0) + *_vnodeID = baseNode->parID; + *_type = S_IFDIR; + if (get_vnode(ns->id, *_vnodeID, (void **)&newNode) != 0) result = EINVAL; else result = B_NO_ERROR; @@ -346,7 +323,7 @@ fs_walk(void *_ns, void *base, const char *file, char **newpath, while ((totalRead < dataLen) && !done) { off_t cachedBlock = block; - blockData = (char *)get_block(ns->fd, block, ns->logicalBlkSize[FS_DATA_FORMAT]); + blockData = (char *)block_cache_get_etc(ns->fBlockCache, block, 0, ns->logicalBlkSize[FS_DATA_FORMAT]); if (blockData != NULL) { int bytesRead = 0; off_t blockBytesRead = 0; @@ -375,10 +352,10 @@ fs_walk(void *_ns, void *base, const char *file, char **newpath, && !strncmp(node.fileIDString, file, strlen(file))) { TRACE(("fs_walk - success, found vnode at block %Ld, pos %Ld\n", block, blockBytesRead)); - *vnid = (block << 30) + (blockBytesRead & 0xFFFFFFFF); - TRACE(("fs_walk - New vnode id is %Ld\n", *vnid)); + *_vnodeID = (block << 30) + (blockBytesRead & 0xFFFFFFFF); + TRACE(("fs_walk - New vnode id is %Ld\n", *_vnodeID)); - if (get_vnode(ns->id, *vnid, (void **)&newNode) != 0) + if (get_vnode(ns->id, *_vnodeID, (void **)&newNode) != 0) result = EINVAL; else { newNode->parID = baseNode->id; @@ -410,33 +387,26 @@ fs_walk(void *_ns, void *base, const char *file, char **newpath, block++; TRACE(("fs_walk - moving to next block %Ld, total read %Ld\n", block, totalRead)); - release_block(ns->fd, cachedBlock); + block_cache_put(ns->fBlockCache, cachedBlock); } else done = TRUE; } - // Check to see if vnode is a symbolic link. If so, fill in the newpath variable - // with the path to the real file, and call put_vnode. - if (newNode != NULL) { - if (S_ISLNK(newNode->attr.stat[FS_DATA_FORMAT].st_mode) && newpath != NULL) { - TRACE(("fs_walk - symbolic link file \'%s\' requested.\n", newNode->attr.slName)); - result = new_path(newNode->attr.slName, newpath); - put_vnode(ns->id, *vnid); - } - } + *_type = newNode->attr.stat[FS_DATA_FORMAT].st_mode; + } - TRACE(("fs_walk - EXIT, result is %s, vnid is %Lu\n", strerror(result), *vnid)); + TRACE(("fs_walk - EXIT, result is %s, vnid is %Lu\n", strerror(result), *_vnodeID)); return result; } -int -fs_read_vnode(void *_ns, vnode_id vnid, char reenter, void **node) +static status_t +fs_read_vnode(void *_ns, vnode_id vnid, void **node, bool reenter) { uint32 block, pos; nspace *ns = (nspace*)_ns; - int result = B_NO_ERROR; + status_t result = B_NO_ERROR; vnode *newNode = (vnode*)calloc(sizeof(vnode), 1); (void)reenter; @@ -453,16 +423,16 @@ fs_read_vnode(void *_ns, vnode_id vnid, char reenter, void **node) memcpy(newNode, &(ns->rootDirRec), sizeof(vnode)); *node = (void*)newNode; } else { - char *blockData = (char *)get_block(ns->fd, block, ns->logicalBlkSize[FS_DATA_FORMAT]); + char *blockData = (char *)block_cache_get_etc(ns->fBlockCache, block, 0, ns->logicalBlkSize[FS_DATA_FORMAT]); if (pos > ns->logicalBlkSize[FS_DATA_FORMAT]) { if (blockData != NULL) - release_block(ns->fd, block); + block_cache_put(ns->fBlockCache, block); result = EINVAL; } else if (blockData != NULL) { result = InitNode(newNode, blockData + pos, NULL, ns->joliet_level); - release_block(ns->fd, block); + block_cache_put(ns->fBlockCache, block); newNode->id = vnid; TRACE(("fs_read_vnode - init result is %s\n", strerror(result))); @@ -478,10 +448,10 @@ fs_read_vnode(void *_ns, vnode_id vnid, char reenter, void **node) } -int -fs_write_vnode(void *ns, void *_node, char reenter) +static status_t +fs_release_vnode(void *ns, void *_node, bool reenter) { - int result = B_NO_ERROR; + status_t result = B_NO_ERROR; vnode *node = (vnode*)_node; (void)ns; @@ -505,7 +475,7 @@ fs_write_vnode(void *ns, void *_node, char reenter) } -static int +static status_t fs_read_stat(void *_ns, void *_node, struct stat *st) { nspace *ns = (nspace*)_ns; @@ -534,10 +504,10 @@ fs_read_stat(void *_ns, void *_node, struct stat *st) } -static int +static status_t fs_open(void *_ns, void *_node, int omode, void **cookie) { - int result = B_NO_ERROR; + status_t result = B_NO_ERROR; (void)_ns; (void)cookie; @@ -552,17 +522,17 @@ fs_open(void *_ns, void *_node, int omode, void **cookie) } -static int +static status_t fs_read(void *_ns, void *_node, void *cookie, off_t pos, void *buf, size_t *len) { nspace *ns = (nspace *)_ns; // global stuff vnode *node = (vnode *)_node; // The read file vnode. uint16 blockSize = ns->logicalBlkSize[FS_DATA_FORMAT]; uint32 startBlock = node->startLBN[FS_DATA_FORMAT] + (pos / blockSize); - off_t blockPos = pos %blockSize; + off_t blockPos = pos % blockSize; off_t numBlocks = 0; uint32 dataLen = node->dataLen[FS_DATA_FORMAT]; - int result = B_NO_ERROR; + status_t result = B_NO_ERROR; size_t endLen = 0; size_t reqLen = *len; size_t startLen = 0; @@ -596,7 +566,7 @@ fs_read(void *_ns, void *_node, void *cookie, off_t pos, void *buf, size_t *len) // Compute the length of the partial end-block read, if any. if (reqLen + blockPos > blockSize) - endLen = (reqLen +blockPos) % blockSize; + endLen = (reqLen + blockPos) % blockSize; // Compute the number of middle blocks to read. numBlocks = ((reqLen - endLen - startLen) / blockSize); @@ -620,12 +590,12 @@ fs_read(void *_ns, void *_node, void *cookie, off_t pos, void *buf, size_t *len) // Read in the first, potentially partial, block. if (startLen > 0) { off_t cachedBlock = startBlock; - char *blockData = (char *)get_block(ns->fd, startBlock, blockSize); + char *blockData = (char *)block_cache_get_etc(ns->fBlockCache, startBlock, 0, blockSize); if (blockData != NULL) { //dprintf("fs_read - copying first block, len is %d.\n", startLen); memcpy(buf, blockData+blockPos, startLen); *len += startLen; - release_block(ns->fd, cachedBlock); + block_cache_put(ns->fBlockCache, cachedBlock); startBlock++; } else result = EIO; @@ -634,23 +604,31 @@ fs_read(void *_ns, void *_node, void *cookie, off_t pos, void *buf, size_t *len) // Read in the middle blocks. if (numBlocks > 0 && result == B_NO_ERROR) { TRACE(("fs_read - getting middle blocks\n")); + /* result = cached_read(ns->fd, startBlock, ((char *)buf) + startLen, numBlocks, blockSize); - if (result == B_NO_ERROR) - *len += blockSize * numBlocks; + */ + for (int32 i=startBlock; ifBlockCache, i, 0, blockSize); + memcpy(((char *)buf) + startLen + (i - startBlock) * blockSize, blockData, blockSize); + *len += blockSize; + block_cache_put(ns->fBlockCache, i); + } + /*if (result == B_NO_ERROR) + *len += blockSize * numBlocks;*/ } // Read in the last partial block. if (result == B_NO_ERROR && endLen > 0) { off_t endBlock = startBlock + numBlocks; - char *endBlockData = (char*)get_block(ns->fd, endBlock, blockSize); + char *endBlockData = (char*)block_cache_get_etc(ns->fBlockCache, endBlock, 0, blockSize); if (endBlockData != NULL) { char *endBuf = ((char *)buf) + (reqLen - endLen); memcpy(endBuf, endBlockData, endLen); - release_block(ns->fd, endBlock); + block_cache_put(ns->fBlockCache, endBlock); *len += endLen; } else result = EIO; @@ -661,7 +639,7 @@ fs_read(void *_ns, void *_node, void *cookie, off_t pos, void *buf, size_t *len) } -static int +static status_t fs_close(void *ns, void *node, void *cookie) { (void)ns; @@ -670,10 +648,10 @@ fs_close(void *ns, void *node, void *cookie) //dprintf("fs_close - ENTER\n"); //dprintf("fs_close - EXIT\n"); - return 0; + return B_OK; } -static int +static status_t fs_free_cookie(void *ns, void *node, void *cookie) { (void)ns; @@ -684,11 +662,11 @@ fs_free_cookie(void *ns, void *node, void *cookie) //dprintf("fs_free_cookie - ENTER\n"); //if (cookie != NULL) free (cookie); //dprintf("fs_free_cookie - EXIT\n"); - return 0; + return B_OK; } // fs_access - checks permissions for access. -static int +static status_t fs_access(void *ns, void *node, int mode) { (void)ns; @@ -700,14 +678,14 @@ fs_access(void *ns, void *node, int mode) // mode - requested permissions on node. //dprintf("fs_access - ENTER\n"); //dprintf("fs_access - EXIT\n"); - return 0; + return B_OK; } -static int +static status_t fs_read_link(void *_ns, void *_node, char *buffer, size_t *_bufferSize) { vnode *node = (vnode *)_node; - int result = EINVAL; + status_t result = EINVAL; (void)_ns; @@ -726,11 +704,11 @@ fs_read_link(void *_ns, void *_node, char *buffer, size_t *_bufferSize) } -static int +static status_t fs_open_dir(void *_ns, void *_node, void **cookie) { vnode *node = (vnode *)_node; - int result = B_NO_ERROR; + status_t result = B_NO_ERROR; dircookie *dirCookie = (dircookie *)malloc(sizeof(dircookie)); (void)_ns; @@ -755,11 +733,11 @@ fs_open_dir(void *_ns, void *_node, void **cookie) } -static int -fs_read_dir(void *_ns, void *_node, void *_cookie, long *num, - struct dirent *buffer, size_t bufferSize) +static status_t +fs_read_dir(void *_ns, void *_node, void *_cookie, struct dirent *buffer, + size_t bufferSize, uint32 *num) { - int result = B_NO_ERROR; + status_t result = B_NO_ERROR; nspace *ns = (nspace *)_ns; dircookie *dirCookie = (dircookie *)_cookie; @@ -786,10 +764,10 @@ fs_read_dir(void *_ns, void *_node, void *_cookie, long *num, } -static int +static status_t fs_rewind_dir(void *ns, void *node, void* _cookie) { - int result = EINVAL; + status_t result = EINVAL; dircookie *cookie = (dircookie*)_cookie; (void)ns; @@ -806,7 +784,7 @@ fs_rewind_dir(void *ns, void *node, void* _cookie) } -static int +static status_t fs_close_dir(void *ns, void *node, void *cookie) { (void)ns; @@ -818,11 +796,11 @@ fs_close_dir(void *ns, void *node, void *cookie) // cookie - current cookie for directory. //dprintf("fs_closedir - ENTER\n"); //dprintf("fs_closedir - EXIT\n"); - return 0; + return B_OK; } -static int +static status_t fs_free_dir_cookie(void *ns, void *node, void *cookie) { (void)ns; @@ -836,5 +814,137 @@ fs_free_dir_cookie(void *ns, void *node, void *cookie) free(cookie); //dprintf("fs_free_dircookie - EXIT\n"); - return 0; + return B_OK; } + +// #pragma mark - + + +static status_t +iso_std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + return B_OK; + case B_MODULE_UNINIT: + return B_OK; + default: + return B_ERROR; + } +} + + +static file_system_module_info sISO660FileSystem = { + { + "file_systems/iso9660" B_CURRENT_FS_API_VERSION, + 0, + iso_std_ops, + }, + + "ISO9660 File System", + + // scanning + fs_identify_partition, + fs_scan_partition, + fs_free_identify_partition_cookie, + NULL, // free_partition_content_cookie() + + &fs_mount, + &fs_unmount, + &fs_read_fs_stat, + NULL, + NULL, + + /* vnode operations */ + &fs_walk, + NULL, // &fs_get_vnode_name() + &fs_read_vnode, + &fs_release_vnode, + NULL, // &fs_remove_vnode() + + /* VM file access */ + NULL, // &fs_can_page + NULL, // &fs_read_pages + NULL, // &fs_write_pages + + NULL, // &fs_get_file_map + + NULL, // &fs_ioctl + NULL, // &fs_set_flags + NULL, // &bfs_select + NULL, // &bfs_deselect + NULL, // &fs_fsync + + &fs_read_link, + NULL, // write link + NULL, // &fs_create_symlink, + + NULL, // &fs_link, + NULL, // &fs_unlink + NULL, // &fs_rename + + &fs_access, + &fs_read_stat, + NULL, // &fs_write_stat + + /* file operations */ + NULL, // &fs_create + &fs_open, + &fs_close, + &fs_free_cookie, + &fs_read, + NULL, // &fs_write + + /* directory operations */ + NULL, // &fs_create_dir + NULL, // &fs_remove_dir + &fs_open_dir, + &fs_close_dir, + &fs_free_dir_cookie, + &fs_read_dir, + &fs_rewind_dir, + + /* attribute directory operations */ + NULL, // &fs_open_attr_dir + NULL, // &fs_close_attr_dir + NULL, // &fs_free_attr_dir_cookie + NULL, // &fs_read_attr_dir + NULL, // &fs_rewind_attr_dir + + /* attribute operations */ + NULL, // &fs_create_attr + NULL, // &fs_open_attr + NULL, // &fs_close_attr + NULL, // &fs_free_attr_cookie + NULL, // &fs_read_attr + NULL, // &fs_write_attr + + NULL, // &fs_read_attr_stat + NULL, // &fs_write_attr_stat + NULL, // &fs_rename_attr + NULL, // &fs_remove_attr + + /* index directory & index operations */ + NULL, // &fs_open_index_dir + NULL, // &fs_close_index_dir + NULL, // &fs_free_index_dir_cookie + NULL, // &fs_read_index_dir + NULL, // &fs_rewind_index_dir + + NULL, // &fs_create_index + NULL, // &fs_remove_index + NULL, // &fs_stat_index + + /* query operations */ + NULL, // &fs_open_query + NULL, // &fs_close_query + NULL, // &fs_free_query_cookie + NULL, // &fs_read_query + NULL, // &fs_rewind_query +}; + +module_info *modules[] = { + (module_info *)&sISO660FileSystem, + NULL, +}; +