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:
parent
e2a69d2257
commit
21e1553eb5
@ -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 $(<) : $(>) ;
|
||||
|
@ -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_ */
|
@ -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
|
@ -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;
|
||||
|
@ -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
|
||||
|
568
src/add-ons/kernel/file_systems/iso9660/iso9660.cpp
Normal file
568
src/add-ons/kernel/file_systems/iso9660/iso9660.cpp
Normal 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;
|
||||
*/
|
||||
}
|
||||
|
34
src/add-ons/kernel/file_systems/iso9660/iso9660.h
Normal file
34
src/add-ons/kernel/file_systems/iso9660/iso9660.h
Normal 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
|
||||
|
@ -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,
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user