haiku version of iso9660 filesystem

working, except for autodetection


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16539 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval 2006-02-27 23:34:05 +00:00
parent e2a69d2257
commit 21e1553eb5
8 changed files with 930 additions and 546 deletions

View File

@ -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 $(<) : $(>) ;

View File

@ -1,103 +0,0 @@
#ifndef _CACHE_H_
#define _CACHE_H_
#include <BeBuild.h>
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_ */

View File

@ -1,240 +0,0 @@
#ifndef _FSPROTO_H
#define _FSPROTO_H
#include <sys/dirent.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iovec.h>
#include <OS.h>
#include <fs_attr.h>
#include <fs_info.h>
#include <BeBuild.h>
#include <Drivers.h>
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

View File

@ -16,18 +16,18 @@
#include <Drivers.h>
#include <OS.h>
#include <lock.h>
#include <cache.h>
#include <KernelExport.h>
#include <string.h>
#include <dirent.h>
#include <time.h>
#include <malloc.h>
#include <ByteOrder.h>
#include <fs_cache.h>
#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;

View File

@ -10,13 +10,16 @@
#include <stdio.h>
#include <sys/types.h>
#include <fsproto.h>
#include <fs_interface.h>
#include <lock.h>
#include <time.h>
#include <endian.h>
#include <SupportDefs.h>
// 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

View File

@ -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
<h5>iso9660</h5>
The standard to which this module is written is ECMA-119 second
edition, a freely available iso9660 equivalent.
<h5>Joliet</h5>
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 <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <ByteOrder.h>
#include <fs_info.h>
#include <KernelExport.h>
#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;
*/
}

View File

@ -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

View File

@ -13,21 +13,31 @@
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <KernelExport.h>
#include <time.h>
#include <fsproto.h>
#include <lock.h>
#include <cache.h>
#include <malloc.h>
#include "iso.h"
#include <KernelExport.h>
#include <NodeMonitor.h>
#include <fs_interface.h>
#include <fs_cache.h>
#define TRACE_ISO9660 0
#include <fs_attr.h>
#include <fs_info.h>
#include <fs_index.h>
#include <fs_query.h>
#include <fs_volume.h>
#include <util/kernel_cpp.h>
#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; i<startBlock+numBlocks; i++) {
char *blockData = (char *)block_cache_get_etc(ns->fBlockCache, 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,
};