Added the multisession capable ISO-9660 file system based on Be's sample code.

Cleaned up the sources to match our coding style better. Partially removed
fs API documentation (since it really doesn't belong here).
Added to the build.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2960 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2003-03-19 17:38:42 +00:00
parent bfa7190f02
commit faa9239d5b
10 changed files with 2531 additions and 0 deletions

View File

@ -1,3 +1,4 @@
SubDir OBOS_TOP src add-ons kernel file_systems ;
SubInclude OBOS_TOP src add-ons kernel file_systems bfs ;
SubInclude OBOS_TOP src add-ons kernel file_systems iso9660 ;

View File

@ -0,0 +1,45 @@
SubDir OBOS_TOP src add-ons kernel file_systems iso9660 ;
# save original optimization level
oldOPTIM = $(OPTIM) ;
# set some additional defines (most of them are currently unused in the iso9660 add-on)
{
local defines =
KEEP_WRONG_DIRENT_RECLEN
;
if $(COMPILE_FOR_R5) {
defines += COMPILE_FOR_R5 ;
}
if $(DEBUG) {
defines += DEBUG ;
} else {
# the gcc on BeOS doesn't compile BFS correctly with -O2 or more
OPTIM = -O1 ;
}
defines = [ FDefines $(defines) ] ;
SubDirCcFlags $(defines) -Wall -Wno-multichar ;
}
R5KernelAddon iso9660 : [ FDirName kernel file_systems iso9660 ] :
iso.c
kernel_interface.c
;
rule InstallISO9660
{
Depends $(<) : $(>) ;
}
actions ignore InstallISO9660
{
cp $(>) /boot/home/config/add-ons/kernel/file_systems/
}
InstallISO9660 install : iso9660 ;
# restore original optimization level
OPTIM = $(oldOPTIM) ;

View File

@ -0,0 +1,31 @@
----------------------
Be Sample Code License
----------------------
Copyright 1991-1999, Be Incorporated.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,103 @@
#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

@ -0,0 +1,241 @@
#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 void notify_select_event(selectsync *sync, uint32 ref);
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

@ -0,0 +1,961 @@
/*
** Copyright 1999, Be Incorporated. All Rights Reserved.
** This file may be used under the terms of the Be Sample Code License.
**
** Copyright 2001, pinc Software. All Rights Reserved.
**
** iso9960/multi-session
** 2001-03-11: added multi-session support, axeld.
*/
#include <malloc.h>
#include <SupportDefs.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#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 "rock.h"
#include "iso.h"
#define TRACE_ISO9660 1
#if TRACE_ISO9660
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
// Just needed here
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";
#if 0
static int GetLogicalBlockSize(int fd);
static off_t GetNumDeviceBlocks(int fd, int block_size);
#endif
static int GetDeviceBlockSize(int fd);
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
static int
GetLogicalBlockSize(int fd)
{
partition_info p_info;
if (ioctl(fd, B_GET_PARTITION_INFO, &p_info) == B_NO_ERROR) {
TRACE(("GetLogicalBlockSize: ioctl suceed\n"));
return p_info.logical_block_size;
}
TRACE(("GetLogicalBlockSize = ioctl returned error\n"));
return 0;
}
static off_t
GetNumDeviceBlocks(int fd, int block_size)
{
struct stat st;
device_geometry dg;
if (ioctl(fd, B_GET_GEOMETRY, &dg) >= 0) {
return (off_t)dg.cylinder_count *
(off_t)dg.sectors_per_track *
(off_t)dg.head_count;
}
/* if the ioctl fails, try just stat'ing in case it's a regular file */
if (fstat(fd, &st) < 0)
return 0;
return st.st_size / block_size;
}
#endif
static int
GetDeviceBlockSize(int fd)
{
struct stat st;
device_geometry dg;
if (ioctl(fd, B_GET_GEOMETRY, &dg) < 0) {
if (fstat(fd, &st) < 0 || S_ISDIR(st.st_mode))
return 0;
return 512; /* just assume it's a plain old file or something */
}
return dg.bytes_per_sector;
}
// From EncodingComversions.cpp
// Pierre's (modified) Uber Macro
// NOTE: iso9660 seems to store the unicode text in big-endian form
#define u_to_utf8(str, uni_str)\
{\
if ((B_BENDIAN_TO_HOST_INT16(uni_str[0])&0xff80) == 0)\
*str++ = B_BENDIAN_TO_HOST_INT16(*uni_str++);\
else if ((B_BENDIAN_TO_HOST_INT16(uni_str[0])&0xf800) == 0) {\
str[0] = 0xc0|(B_BENDIAN_TO_HOST_INT16(uni_str[0])>>6);\
str[1] = 0x80|(B_BENDIAN_TO_HOST_INT16(*uni_str++)&0x3f);\
str += 2;\
} else if ((B_BENDIAN_TO_HOST_INT16(uni_str[0])&0xfc00) != 0xd800) {\
str[0] = 0xe0|(B_BENDIAN_TO_HOST_INT16(uni_str[0])>>12);\
str[1] = 0x80|((B_BENDIAN_TO_HOST_INT16(uni_str[0])>>6)&0x3f);\
str[2] = 0x80|(B_BENDIAN_TO_HOST_INT16(*uni_str++)&0x3f);\
str += 3;\
} else {\
int val;\
val = ((B_BENDIAN_TO_HOST_INT16(uni_str[0])-0xd7c0)<<10) | (B_BENDIAN_TO_HOST_INT16(uni_str[1])&0x3ff);\
str[0] = 0xf0 | (val>>18);\
str[1] = 0x80 | ((val>>12)&0x3f);\
str[2] = 0x80 | ((val>>6)&0x3f);\
str[3] = 0x80 | (val&0x3f);\
uni_str += 2; str += 4;\
}\
}
static status_t
unicode_to_utf8(const char *src, int32 *srcLen, char *dst, int32 *dstLen)
{
int32 srcLimit = *srcLen;
int32 dstLimit = *dstLen;
int32 srcCount = 0;
int32 dstCount = 0;
for (srcCount = 0; srcCount < srcLimit; srcCount += 2) {
uint16 *UNICODE = (uint16 *)&src[srcCount];
uchar utf8[4];
uchar *UTF8 = utf8;
int32 utf8Len;
int32 j;
u_to_utf8(UTF8, UNICODE);
utf8Len = UTF8 - utf8;
if ((dstCount + utf8Len) > dstLimit)
break;
for (j = 0; j < utf8Len; j++)
dst[dstCount + j] = utf8[j];
dstCount += utf8Len;
}
*srcLen = srcCount;
*dstLen = dstCount;
return ((dstCount > 0) ? B_NO_ERROR : B_ERROR);
}
// #pragma mark -
// Functions specific to iso driver.
int
ISOMount(const char *path, const int flags, nspace **newVol, bool allow_joliet)
{
// path: path to device (eg, /dev/disk/scsi/030/raw)
// partition: partition number on device ????
// flags: currently unused
// determine if it is an ISO volume.
char buffer[ISO_PVD_SIZE];
bool done = false;
bool is_iso = false;
off_t offset = 0x8000;
ssize_t retval;
partition_info partitionInfo;
int deviceBlockSize, multiplier;
nspace *vol;
int result = B_NO_ERROR;
(void)flags;
TRACE(("ISOMount - ENTER\n"));
vol = (nspace *)calloc(sizeof(nspace), 1);
if (vol == NULL) {
TRACE(("ISOMount - mem error \n"));
return ENOMEM;
}
memset(&partitionInfo,0,sizeof(partition_info));
/* open and lock the device */
vol->fdOfSession = open(path, O_RDONLY);
/* try to open the raw device to get access to the other sessions as well */
if (vol->fdOfSession >= 0) {
if (ioctl(vol->fdOfSession,B_GET_PARTITION_INFO,&partitionInfo) < B_NO_ERROR) {
TRACE(("B_GET_PARTITION_INFO: ioctl returned error\n"));
strcpy(partitionInfo.device,path);
}
TRACE(("ISOMount: open device/file \"%s\"\n",partitionInfo.device));
vol->fd = open(partitionInfo.device,O_RDONLY);
}
if (vol->fdOfSession < 0 || vol->fd < 0) {
close(vol->fd);
close(vol->fdOfSession);
TRACE(("ISO9660 ERROR - Unable to open <%s>\n", path));
free(vol);
return EINVAL;
}
deviceBlockSize = GetDeviceBlockSize(vol->fdOfSession);
if (deviceBlockSize < 0) {
TRACE(("ISO9660 ERROR - device block size is 0\n"));
close(vol->fd);
close(vol->fdOfSession);
free(vol);
return EINVAL;
}
vol->joliet_level = 0;
while ((!done) && (offset < 0x10000)) {
retval = read_pos (vol->fdOfSession, offset, (void *)buffer, ISO_PVD_SIZE);
if (retval < ISO_PVD_SIZE) {
is_iso = false;
break;
}
if (strncmp(buffer + 1, kISO9660IDString, 5) == 0) {
if ((*buffer == 0x01) && (!is_iso)) {
// ISO_VD_PRIMARY
off_t maxBlocks;
TRACE(("ISOMount: Is an ISO9660 volume, initting rec\n"));
InitVolDesc(vol, buffer);
strncpy(vol->devicePath,path,127);
vol->id = ISO_ROOTNODE_ID;
TRACE(("ISO9660: vol->blockSize = %d\n", vol->logicalBlkSize[FS_DATA_FORMAT]));
multiplier = deviceBlockSize / vol->logicalBlkSize[FS_DATA_FORMAT];
TRACE(("ISOMount: block size multiplier is %d\n", multiplier));
// if the session is on a real device, size != 0
if (partitionInfo.size != 0)
maxBlocks = (partitionInfo.size+partitionInfo.offset) / vol->logicalBlkSize[FS_DATA_FORMAT];
else
maxBlocks = vol->volSpaceSize[FS_DATA_FORMAT];
/* 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);
is_iso = true;
} else if ((*buffer == 0x02) && is_iso && allow_joliet) {
// ISO_VD_SUPPLEMENTARY
// JOLIET extension
// test escape sequence for level of UCS-2 characterset
if (buffer[88] == 0x25 && buffer[89] == 0x2f) {
switch (buffer[90]) {
case 0x40: vol->joliet_level = 1; break;
case 0x43: vol->joliet_level = 2; break;
case 0x45: vol->joliet_level = 3; break;
}
TRACE(("ISO9660 Extensions: Microsoft Joliet Level %d\n", vol->joliet_level));
// Because Joliet-stuff starts at other sector,
// update root directory record.
if (vol->joliet_level > 0)
InitNode(&(vol->rootDirRec), &buffer[156], NULL, 0);
}
} else if (*(unsigned char *)buffer == 0xff) {
// ISO_VD_END
done = true;
} else
TRACE(("found header %d\n",*buffer));
}
offset += 0x800;
}
if (!is_iso) {
// It isn't an ISO disk.
if (vol->fdOfSession >= 0)
close(vol->fdOfSession);
if (vol->fd >= 0)
close(vol->fd);
free(vol);
vol = NULL;
result = EINVAL;
TRACE(("ISOMount: Not an ISO9660 volume!\n"));
}
TRACE(("ISOMount - EXIT, result %s, returning %p\n", strerror(result), vol));
*newVol = vol;
return result;
}
/** Reads in a single directory entry and fills in the values in the
* dirent struct. Uses the cookie to keep track of the current block
* and position within the block. Also uses the cookie to determine when
* it has reached the end of the directory file.
*
* NOTE: If your file sytem seems to work ok from the command line, but
* the tracker doesn't seem to like it, check what you do here closely;
* in particular, if the d_ino in the stat struct isn't correct, the tracker
* will not display the entry.
*/
int
ISOReadDirEnt(nspace *ns, dircookie *cookie, struct dirent *dirent, size_t bufsize)
{
off_t totalRead = cookie->pos + ((cookie->block - cookie->startBlock) *
ns->logicalBlkSize[FS_DATA_FORMAT]);
off_t cacheBlock;
char *blockData;
int result = B_NO_ERROR;
int bytesRead = 0;
bool block_out = false;
TRACE(("ISOReadDirEnt - ENTER\n"));
// 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,
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_out = false;
totalRead += ns->logicalBlkSize[FS_DATA_FORMAT] - cookie->pos;
cookie->pos = 0;
cookie->block++;
}
else
break;
if (totalRead >= cookie->totalSize)
break;
}
cacheBlock = cookie->block;
if (blockData != NULL && totalRead < cookie->totalSize) {
vnode node;
if ((result = InitNode(&node, blockData + cookie->pos, &bytesRead, ns->joliet_level)) ==
B_NO_ERROR)
{
int nameBufSize = (bufsize - (2 * sizeof(dev_t) + 2* sizeof(ino_t) +
sizeof(unsigned short)));
dirent->d_ino = (cookie->block << 30) + (cookie->pos & 0xFFFFFFFF);
dirent->d_reclen = node.fileIDLen;
if (node.fileIDLen <= nameBufSize) {
// need to do some size checking here.
strncpy(dirent->d_name, node.fileIDString, node.fileIDLen +1);
TRACE(("ISOReadDirEnt - success, name is %s\n", dirent->d_name));
} else {
TRACE(("ISOReadDirEnt - ERROR, name %s does not fit in buffer of size %d\n", node.fileIDString, nameBufSize));
result = EINVAL;
}
cookie->pos += bytesRead;
}
} else {
if (totalRead >= cookie->totalSize)
result = ENOENT;
else
result = ENOMEM;
}
if (block_out)
release_block(ns->fd, cacheBlock);
TRACE(("ISOReadDirEnt - EXIT, result is %s, vnid is %Lu\n", strerror(result), dirent->d_ino));
return result;
}
int
InitVolDesc(nspace *vol, char *buffer)
{
TRACE(("InitVolDesc - ENTER\n"));
vol->volDescType = *(uint8 *)buffer++;
vol->stdIDString[5] = '\0';
strncpy(vol->stdIDString, buffer, 5);
buffer += 5;
vol->volDescVersion = *(uint8 *)buffer;
buffer += 2; // 8th byte unused
vol->systemIDString[32] = '\0';
strncpy(vol->systemIDString, buffer, 32);
buffer += 32;
TRACE(("InitVolDesc - system id string is %s\n", vol->systemIDString));
vol->volIDString[32] = '\0';
strncpy(vol->volIDString, buffer, 32);
buffer += (32 + 80-73 + 1); // bytes 80-73 unused
TRACE(("InitVolDesc - volume id string is %s\n", vol->volIDString));
vol->volSpaceSize[LSB_DATA] = *(uint32 *)buffer;
buffer += 4;
vol->volSpaceSize[MSB_DATA] = *(uint32 *)buffer;
buffer+= (4 + 120-89 + 1); // bytes 120-89 unused
vol->volSetSize[LSB_DATA] = *(uint16*)buffer;
buffer += 2;
vol->volSetSize[MSB_DATA] = *(uint16*)buffer;
buffer += 2;
vol->volSeqNum[LSB_DATA] = *(uint16*)buffer;
buffer += 2;
vol->volSeqNum[MSB_DATA] = *(uint16*)buffer;
buffer += 2;
vol->logicalBlkSize[LSB_DATA] = *(uint16*)buffer;
buffer += 2;
vol->logicalBlkSize[MSB_DATA] = *(uint16*)buffer;
buffer += 2;
vol->pathTblSize[LSB_DATA] = *(uint32*)buffer;
buffer += 4;
vol->pathTblSize[MSB_DATA] = *(uint32*)buffer;
buffer += 4;
vol->lPathTblLoc[LSB_DATA] = *(uint16*)buffer;
buffer += 2;
vol->lPathTblLoc[MSB_DATA] = *(uint16*)buffer;
buffer += 2;
vol->optLPathTblLoc[LSB_DATA] = *(uint16*)buffer;
buffer += 2;
vol->optLPathTblLoc[MSB_DATA] = *(uint16*)buffer;
buffer += 2;
vol->mPathTblLoc[LSB_DATA] = *(uint16*)buffer;
buffer += 2;
vol->mPathTblLoc[MSB_DATA] = *(uint16*)buffer;
buffer += 2;
vol->optMPathTblLoc[LSB_DATA] = *(uint16*)buffer;
buffer += 2;
vol->optMPathTblLoc[MSB_DATA] = *(uint16*)buffer;
buffer += 2;
// Fill in directory record.
InitNode(&(vol->rootDirRec), buffer, NULL, 0);
vol->rootDirRec.id = ISO_ROOTNODE_ID;
buffer += 34;
vol->volSetIDString[128] = '\0';
strncpy(vol->volSetIDString, buffer, 128);
buffer += 128;
TRACE(("InitVolDesc - volume set id string is %s\n", vol->volSetIDString));
vol->pubIDString[128] = '\0';
strncpy(vol->pubIDString, buffer, 128);
buffer += 128;
TRACE(("InitVolDesc - volume pub id string is %s\n", vol->pubIDString));
vol->dataPreparer[128] = '\0';
strncpy(vol->dataPreparer, buffer, 128);
buffer += 128;
TRACE(("InitVolDesc - volume dataPreparer string is %s\n", vol->dataPreparer));
vol->appIDString[128] = '\0';
strncpy(vol->appIDString, buffer, 128);
buffer += 128;
TRACE(("InitVolDesc - volume app id string is %s\n", vol->appIDString));
vol->copyright[38] = '\0';
strncpy(vol->copyright, buffer, 38);
buffer += 38;
TRACE(("InitVolDesc - copyright is %s\n", vol->copyright));
vol->abstractFName[38] = '\0';
strncpy(vol->abstractFName, buffer, 38);
buffer += 38;
vol->biblioFName[38] = '\0';
strncpy(vol->biblioFName, buffer, 38);
buffer += 38;
InitVolDate(&(vol->createDate), buffer);
buffer += 17;
InitVolDate(&(vol->modDate), buffer);
buffer += 17;
InitVolDate(&(vol->expireDate), buffer);
buffer += 17;
InitVolDate(&(vol->effectiveDate), buffer);
buffer += 17;
vol->fileStructVers = *(uint8 *)buffer;
return 0;
}
int
InitNode(vnode *rec, char *buffer, int *_bytesRead, uint8 joliet_level)
{
int result = B_NO_ERROR;
uint8 recLen = *(uint8 *)buffer++;
bool no_rock_ridge_stat_struct = TRUE;
if (_bytesRead != NULL)
*_bytesRead = recLen;
TRACE(("InitNode - ENTER, bufstart is %p, record length is %d bytes\n", buffer, recLen));
if (recLen > 0) {
rec->extAttrRecLen = *(uint8 *)buffer++;
rec->startLBN[LSB_DATA] = *(uint32 *)buffer;
buffer += 4;
rec->startLBN[MSB_DATA] = *(uint32 *)buffer;
buffer += 4;
TRACE(("InitNode - data start LBN is %ld\n", rec->startLBN[FS_DATA_FORMAT]));
rec->dataLen[LSB_DATA] = *(uint32 *)buffer;
buffer += 4;
rec->dataLen[MSB_DATA] = *(uint32 *)buffer;
buffer += 4;
TRACE(("InitNode - data length is %ld\n", rec->dataLen[FS_DATA_FORMAT]));
InitRecDate(&(rec->recordDate), buffer);
buffer += 7;
rec->flags = *(uint8 *)buffer;
buffer++;
TRACE(("InitNode - flags are %d\n", rec->flags));
rec->fileUnitSize = *(uint8 *)buffer;
buffer++;
TRACE(("InitNode - fileUnitSize is %d\n", rec->fileUnitSize));
rec->interleaveGapSize = *(uint8 *)buffer;
buffer++;
TRACE(("InitNode - interleave gap size = %d\n", rec->interleaveGapSize));
rec->volSeqNum = *(uint32 *)buffer;
buffer += 4;
TRACE(("InitNode - volume seq num is %ld\n", rec->volSeqNum));
rec->fileIDLen = *(uint8*)buffer;
buffer++;
TRACE(("InitNode - file id length is %d\n", rec->fileIDLen));
if (rec->fileIDLen > 0) {
// JOLIET extension:
// on joliet discs, buffer[0] can be 0 for Unicoded filenames,
// so I've added a check here to test explicitely for
// directories (which have length 1)
if (rec->fileIDLen == 1) {
// Take care of "." and "..", the first two dirents are
// these in iso.
if (buffer[0] == 0) {
rec->fileIDString = strdup(".");
rec->fileIDLen = 1;
} else if (buffer[0] == 1) {
rec->fileIDString = strdup("..");
rec->fileIDLen = 2;
}
} else {
// JOLIET extension:
// convert Unicode16 string to UTF8
if (joliet_level > 0) {
// Assume that the unicode->utf8 conversion produces 4 byte
// utf8 characters, and allocate that much space
rec->fileIDString = (char *)malloc(rec->fileIDLen * 2 + 1);
if (rec->fileIDString != NULL) {
status_t err;
int32 srcLen = rec->fileIDLen;
int32 dstLen = rec->fileIDLen * 2;
err = unicode_to_utf8(buffer, &srcLen, rec->fileIDString, &dstLen);
if (err < B_NO_ERROR) {
dprintf("iso9660: error converting unicode->utf8\n");
result = err;
} else {
rec->fileIDString[dstLen] = '\0';
rec->fileIDLen = dstLen;
}
} else {
// Error
result = ENOMEM;
TRACE(("InitNode - unable to allocate memory!\n"));
}
} else {
rec->fileIDString = (char *)malloc((rec->fileIDLen) + 1);
if (rec->fileIDString != NULL) {
strncpy(rec->fileIDString, buffer, rec->fileIDLen);
rec->fileIDString[rec->fileIDLen] = '\0';
} else {
// Error
result = ENOMEM;
TRACE(("InitNode - unable to allocate memory!\n"));
}
}
}
// Get rid of semicolons, which are used to delineate file versions.q
{
char *semi = NULL;
while ((semi = strchr(rec->fileIDString, ';')) != NULL)
semi[0] = '\0';
}
TRACE(("DirRec ID String is: %s\n", rec->fileIDString));
if (result == B_NO_ERROR) {
buffer += rec->fileIDLen;
if (!(rec->fileIDLen % 2))
buffer++;
// Now we're at the start of the rock ridge stuff
{
char *altName = NULL;
char *slName = NULL;
uint16 altNameSize = 0;
uint16 slNameSize = 0;
uint8 slFlags = 0;
uint8 length = 0;
bool done = FALSE;
TRACE(("RR: Start of extensions, but at %p\n", buffer));
memset(&(rec->attr.stat), 0, 2 * sizeof(struct stat));
// Set defaults, in case there is no RR stuff.
rec->attr.stat[FS_DATA_FORMAT].st_mode = (S_IRUSR | S_IRGRP | S_IROTH);
while (!done)
{
buffer += length;
length = *(uint8 *)(buffer + 2);
switch (0x100 * buffer[0] + buffer[1])
{
// Stat structure stuff
case 'PX':
{
uint8 bytePos = 3;
TRACE(("RR: found PX, length %u\n", length));
rec->attr.pxVer = *(uint8*)(buffer + bytePos++);
no_rock_ridge_stat_struct = FALSE;
// st_mode
rec->attr.stat[LSB_DATA].st_mode = *(mode_t*)(buffer + bytePos);
bytePos += 4;
rec->attr.stat[MSB_DATA].st_mode = *(mode_t*)(buffer + bytePos);
bytePos += 4;
// st_nlink
rec->attr.stat[LSB_DATA].st_nlink = *(nlink_t*)(buffer+bytePos);
bytePos += 4;
rec->attr.stat[MSB_DATA].st_nlink = *(nlink_t*)(buffer + bytePos);
bytePos += 4;
// st_uid
rec->attr.stat[LSB_DATA].st_uid = *(uid_t*)(buffer+bytePos);
bytePos += 4;
rec->attr.stat[MSB_DATA].st_uid = *(uid_t*)(buffer+bytePos);
bytePos += 4;
// st_gid
rec->attr.stat[LSB_DATA].st_gid = *(gid_t*)(buffer+bytePos);
bytePos += 4;
rec->attr.stat[MSB_DATA].st_gid = *(gid_t*)(buffer+bytePos);
bytePos += 4;
break;
}
case 'PN':
TRACE(("RR: found PN, length %u\n", length));
break;
// Symbolic link info
case 'SL':
{
uint8 bytePos = 3;
uint8 lastCompFlag = 0;
uint8 addPos = 0;
bool slDone = FALSE;
bool useSeparator = TRUE;
TRACE(("RR: found SL, length %u\n", length));
TRACE(("Buffer is at %p\n", buffer));
TRACE(("Current length is %u\n", slNameSize));
//kernel_debugger("");
rec->attr.slVer = *(uint8*)(buffer + bytePos++);
slFlags = *(uint8*)(buffer + bytePos++);
TRACE(("sl flags are %u\n", slFlags));
while (!slDone && bytePos < length)
{
uint8 compFlag = *(uint8*)(buffer + bytePos++);
uint8 compLen = *(uint8*)(buffer + bytePos++);
if (slName == NULL) useSeparator = FALSE;
addPos = slNameSize;
TRACE(("sl comp flags are %u, length is %u\n", compFlag, compLen));
TRACE(("Current name size is %u\n", slNameSize));
switch (compFlag)
{
case SLCP_CONTINUE:
useSeparator = FALSE;
default:
// Add the component to the total path.
slNameSize += compLen;
if ( useSeparator ) slNameSize++;
if (slName == NULL)
slName = (char*)malloc(slNameSize + 1);
else
slName = (char*)realloc(slName, slNameSize + 1);
if (useSeparator)
{
TRACE(("Adding separator\n"));
slName[addPos++] = '/';
}
TRACE(("doing memcopy of %u bytes at offset %d\n", compLen, addPos));
memcpy((slName + addPos), (buffer + bytePos), compLen);
addPos += compLen;
useSeparator = TRUE;
break;
case SLCP_CURRENT:
TRACE(("InitNode - found link to current directory\n"));
slNameSize += 2;
if (slName == NULL)
slName = (char*)malloc(slNameSize + 1);
else
slName = (char*)realloc(slName, slNameSize + 1);
memcpy(slName + addPos, "./", 2);
useSeparator = FALSE;
break;
case SLCP_PARENT:
slNameSize += 3;
if (slName == NULL)
slName = (char*)malloc(slNameSize + 1);
else
slName = (char*)realloc(slName, slNameSize + 1);
memcpy(slName + addPos, "../", 3);
useSeparator = FALSE;
break;
case SLCP_ROOT:
TRACE(("InitNode - found link to root directory\n"));
slNameSize += 1;
if (slName == NULL)
slName = (char*)malloc(slNameSize + 1);
else
slName = (char*)realloc(slName, slNameSize + 1);
memcpy(slName + addPos, "/", 1);
useSeparator = FALSE;
break;
case SLCP_VOLROOT:
slDone = TRUE;
break;
case SLCP_HOST:
slDone = TRUE;
break;
}
slName[slNameSize] = '\0';
lastCompFlag = compFlag;
bytePos += compLen;
TRACE(("Current sl name is \'%s\'\n", slName));
}
rec->attr.slName = slName;
TRACE(("InitNode = symlink name is \'%s\'\n", slName));
break;
}
// Altername name
case 'NM':
{
uint8 bytePos = 3;
uint8 flags = 0;
uint16 oldEnd = altNameSize;
altNameSize += length - 5;
if (altName == NULL)
altName = (char *)malloc(altNameSize + 1);
else
altName = (char *)realloc(altName, altNameSize + 1);
TRACE(("RR: found NM, length %u\n", length));
// Read flag and version.
rec->attr.nmVer = *(uint8 *)(buffer + bytePos++);
flags = *(uint8 *)(buffer + bytePos++);
TRACE(("RR: nm buffer is %s, start at %p\n", (buffer + bytePos), buffer + bytePos));
// Build the file name.
memcpy(altName + oldEnd, buffer + bytePos, length - 5);
altName[altNameSize] = '\0';
TRACE(("RR: alt name is %s\n", altName));
// If the name is not continued in another record, update
// the record name.
if (!(flags & NM_CONTINUE))
{
// Get rid of the ISO name, replace with RR name.
if (rec->fileIDString != NULL)
free(rec->fileIDString);
rec->fileIDString = altName;
rec->fileIDLen = altNameSize;
}
break;
}
// Deep directory record masquerading as a file.
case 'CL':
TRACE(("RR: found CL, length %u\n", length));
rec->flags |= ISO_ISDIR;
rec->startLBN[LSB_DATA] = *(uint32*)(buffer+4);
rec->startLBN[MSB_DATA] = *(uint32*)(buffer+8);
break;
case 'PL':
TRACE(("RR: found PL, length %u\n", length));
break;
// Relocated directory, we should skip.
case 'RE':
result = EINVAL;
TRACE(("RR: found RE, length %u\n", length));
break;
case 'TF':
TRACE(("RR: found TF, length %u\n", length));
break;
case 'RR':
TRACE(("RR: found RR, length %u\n", length));
break;
default:
TRACE(("RR: %c%c (%d, %d)\n",buffer[0],buffer[1],buffer[0],buffer[1]));
TRACE(("RR: End of extensions.\n"));
done = TRUE;
break;
}
}
}
}
} else {
TRACE(("InitNode - File ID String is 0 length\n"));
result = ENOENT;
}
} else
result = ENOENT;
TRACE(("InitNode - EXIT, result is %s name is \'%s\'\n", strerror(result), rec->fileIDString));
if (no_rock_ridge_stat_struct) {
if (rec->flags & ISO_ISDIR)
rec->attr.stat[FS_DATA_FORMAT].st_mode |= (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH);
else
rec->attr.stat[FS_DATA_FORMAT].st_mode |= (S_IFREG);
}
return result;
}
static int
InitVolDate(ISOVolDate *date, char *buffer)
{
memcpy(date, buffer, 17);
return 0;
}
static int
InitRecDate(ISORecDate *date, char *buffer)
{
memcpy(date, buffer, 7);
return 0;
}
int
ConvertRecDate(ISORecDate* inDate, time_t* outDate)
{
time_t time;
int days, i, year, tz;
year = inDate->year -70;
tz = inDate->offsetGMT;
if (year < 0) {
time = 0;
} else {
const int monlen[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
days = (year * 365);
if (year > 2)
days += (year + 1)/ 4;
for (i = 1; (i < inDate->month) && (i < 12); i++) {
days += monlen[i-1];
}
if (((year + 2) % 4) == 0 && inDate->month > 2)
days++;
days += inDate->date - 1;
time = ((((days*24) + inDate->hour) * 60 + inDate->minute) * 60)
+ inDate->second;
if (tz & 0x80)
tz |= (-1 << 8);
if (-48 <= tz && tz <= 52)
time += tz *15 * 60;
}
*outDate = time;
return 0;
}

View File

@ -0,0 +1,230 @@
/*
** Copyright 1999, Be Incorporated. All Rights Reserved.
** This file may be used under the terms of the Be Sample Code License.
**
** Copyright 2001, pinc Software. All Rights Reserved.
*/
#ifndef _ISO_H
#define _ISO_H
#include <stdio.h>
#include <sys/types.h>
#include <fsproto.h>
#include <lock.h>
#include <time.h>
#include <endian.h>
#include <SupportDefs.h>
// ISO structure has both msb and lsb first data. These let you do a
// compile-time switch for different platforms.
enum
{
LSB_DATA = 0,
MSB_DATA
};
// This defines the data format for the platform we are compiling
// for.
#if BYTE_ORDER == __LITTLE_ENDIAN
#define FS_DATA_FORMAT LSB_DATA
#else
#define FS_DATA_FORMAT MSB_DATA
#endif
// ISO pdf file spec I read appears to be WRONG about the date format. See
// www.alumni.caltech.edu/~pje/iso9660.html, definition there seems
// to match.
typedef struct ISOVolDate
{
char year[5];
char month[3];
char day[3];
char hour[3];
char minute[3];
char second[3];
char hunSec[3];
int8 offsetGMT;
} ISOVolDate;
typedef struct ISORecDate
{
uint8 year; // Year - 1900
uint8 month;
uint8 date;
uint8 hour;
uint8 minute;
uint8 second;
int8 offsetGMT;
} ISORecDate;
/* This next section is data structure to hold the data found in the rock ridge extensions. */
typedef struct RRAttr
{
char* slName;
struct stat stat[2];
uint8 nmVer;
uint8 pxVer;
uint8 slVer;
} RRAttr;
/* For each item on the disk (directory, file, etc), your filesystem should allocate a vnode struct and
pass it back to the kernel when fs_read_vnode is called. This struct is then passed back in to
your file system by functions that reference an item on the disk. You'll need to be able to
create a vnode from a vnode id, either by hashing the id number or encoding the information needed
to create the vnode in the vnode id itself. Vnode ids are assigned by your file system when the
filesystem walk function is called. For this driver, the block number is encoded in the upper bits
of the vnode id, and the offset within the block in the lower, allowing me to just read the info
to fill in the vnode struct from the disk. When the kernel is done with a vnode, it will call
fs_write_vnode (somewhat of a misnomer) where you should deallocate the struct.
*/
typedef struct vnode
{
/* Most drivers will probably want the first things defined here. */
vnode_id id;
vnode_id parID; // parent vnode ID.
// End of members other drivers will definitely want.
/* The rest of this struct is very ISO-specific. You should replace the rest of this
definition with the stuff your file system needs.
*/
uint8 extAttrRecLen; // Length of extended attribute record.
uint32 startLBN[2]; // Logical block # of start of file/directory data
uint32 dataLen[2]; // Length of file section in bytes
ISORecDate recordDate; // Date file was recorded.
// BIT MEANING
// --- -----------------------------
uint8 flags; // 0 - is hidden
// 1 - is directory
// 2 - is "Associated File"
// 3 - Info is structed according to extended attr record
// 4 - Owner, group, ppermisssions are specified in the
// extended attr record
// 5 - Reserved
// 6 - Reserved
// 7 - File has more that one directory record
uint8 fileUnitSize; // Interleave only
uint8 interleaveGapSize; // Interleave only
uint32 volSeqNum; // Volume sequence number of volume
uint8 fileIDLen; // Length of volume "ID" (name)
char* fileIDString; // Volume "ID" (name)
// The rest is Rock Ridge extensions. I suggest www.leo.org for spec info.
RRAttr attr;
} vnode;
// These go with the flags member of the nspace struct.
enum
{
ISO_ISHIDDEN = 0,
ISO_ISDIR = 2,
ISO_ISASSOCFILE = 4,
ISO_EXTATTR = 8,
ISO_EXTPERM = 16,
ISO_MOREDIRS = 128
};
// Arbitrarily - selected root vnode id
#define ISO_ROOTNODE_ID 1
/* Structure used for directory "cookie". When you are asked
to open a directory, you are asked to create a cookie for it
and pass it back. The cookie should contain the information you
need to determine where you are at in reading the directory
entries, incremented every time readdir is called, until finally
the end is reached, when readdir returns NULL. */
typedef struct dircookie
{
off_t startBlock;
off_t block; // Current block
off_t pos; // Position within block.
off_t totalSize; // Size of directory file
off_t id;
} dircookie;
/* You may also need to define a cookie for files, which again is
allocated every time a file is opened and freed when the free
cookie function is called. For ISO, we didn't need one.
*/
typedef struct attrfilemap
{
char *name;
off_t offset;
} attrfilemap;
/* This is the global volume nspace struct. When mount is called , this struct should
be allocated. It is passed back into the functions so that you can get at any
global information you need. You'll need to change this struct to suit your purposes.
*/
typedef struct nspace
{
// Start of members other drivers will definitely want.
nspace_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
char devicePath[127];
//off_t numBlocks; // May need this, but it's part of ISO
// End of members other drivers will definitely want.
// attribute extensions
int32 readAttributes;
attrfilemap *attrFileMap;
vnode_id attributesID;
// JOLIET extension: joliet_level for this volume
uint8 joliet_level;
// All this stuff comes straight from ISO primary volume
// descriptor structure.
uint8 volDescType; // Volume Descriptor type byte1
char stdIDString[6]; // Standard ID, 1 extra for null byte2-6
uint8 volDescVersion; // Volume Descriptor version byte7
// 8th byte unused
char systemIDString[33]; // System ID, 1 extra for null byte9-40
char volIDString[33]; // Volume ID, 1 extra for null byte41-72
// bytes 73-80 unused
uint32 volSpaceSize[2]; // #logical blocks, lsb and msb byte81-88
// bytes 89-120 unused
uint16 volSetSize[2]; // Assigned Volume Set Size of Vol byte121-124
uint16 volSeqNum[2]; // Ordinal number of volume in Set byte125-128
uint16 logicalBlkSize[2]; // Logical blocksize, usually 2048 byte129-132
uint32 pathTblSize[2]; // Path table size byte133-149
uint16 lPathTblLoc[2]; // Loc (Logical block #) of "Type L" path table byte141-144
uint16 optLPathTblLoc[2]; // Loc (Logical block #) of optional Type L path tbl byte145-148
uint16 mPathTblLoc[2]; // Loc (Logical block #) of "Type M" path table byte149-152
uint16 optMPathTblLoc[2]; // Loc (Logical block #) of optional Type M path tbl byte153-156
vnode rootDirRec; // Directory record for root directory byte157-190
char volSetIDString[29]; // Name of multi-volume set where vol is member byte191-318
char pubIDString[129]; // Name of publisher byte319-446
char dataPreparer[129]; // Name of data preparer byte447-574
char appIDString[129]; // Identifies data fomrat byte575-702
char copyright[38]; // Copyright string byte703-739
char abstractFName[38]; // Name of file in root that has abstract byte740-776
char biblioFName[38]; // Name of file in root that has biblio byte777-813
ISOVolDate createDate; // Creation date byte
ISOVolDate modDate; // Modification date
ISOVolDate expireDate; // Data expiration date
ISOVolDate effectiveDate; // Data effective data
uint8 fileStructVers; // File structure version byte882
} nspace;
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);
#endif

View File

@ -0,0 +1,855 @@
/*
** Copyright 1999, Be Incorporated. All Rights Reserved.
** This file may be used under the terms of the Be Sample Code License.
**
** Copyright 2001, pinc Software. All Rights Reserved.
**
** iso9960/multi-session, 1.0.0
** 2001-03-11: added multi-session support, axeld.
*/
#include <stdlib.h>
#include <unistd.h>
#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"
/* 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);
int fs_walk(void *_ns, void *_base, const char *file,
char **newpath, vnode_id *vnid);
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);
/// 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);
// fs_access - checks permissions for access.
static int 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);
// 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);
// 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);
// 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);
// fs_fee_dircookie - Free the fs-specific cookie struct
static int 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 *);
// fs_readlink - Read in the name of a symbolic link.
static int fs_read_link(void *_ns, void *_node, char *buf, size_t *bufsize);
/* 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
};
int32 api_version = B_CUR_FS_API_VERSION;
static int
fs_mount(nspace_id nsid, const char *device, ulong flags, void *parms,
size_t len, void **data, vnode_id *vnid)
{
/*
Kernel passes in nspace_id, (representing a disk or partition?)
and a string representing the device (eg, "/dev/scsi/disk/030/raw)
Flags will be used for things like specifying read-only mounting.
parms is parameters passed in as switches from the mount command,
and len is the length of the otions. data is a pointer to a
driver-specific struct that should be allocated in this routine.
It will then be passed back in by the kernel to a number of the other
fs driver functions. vnid should also be passed back to the kernel,
representing the vnode id of the root vnode.
*/
int result = EINVAL;
// return EINVAL if it's not a device compatible with the driver.
bool allow_joliet = true;
nspace *vol;
(void)flags;
/* Create semaphore if it's not already created. When do we need to
use semaphores? */
// Check for a 'nojoliet' parm
// all we check for is the existance of 'nojoliet' in the parms.
if (parms != NULL) {
int i;
char *spot;
char *buf;
// 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;
// lower case the parms data
for (i = 0; i < len + 1; i++)
buf[i] = tolower(buf[i]);
// look for nojoliet
spot = strstr(buf, "nojoliet");
if (spot != NULL)
allow_joliet = false;
free(buf);
}
// Try and mount volume as an ISO volume.
result = ISOMount(device, O_RDONLY, &vol, allow_joliet);
// If it is ISO …
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;
// You MUST do this. Create the vnode for the root.
result = new_vnode(nsid, *vnid, (void*)&(vol->rootDirRec));
if (result != B_NO_ERROR) {
remove_cached_device_blocks(vol->fd, 0);
free(vol);
result = EINVAL;
} else
result = B_NO_ERROR;
}
return result;
}
static int
fs_unmount(void *_ns)
{
int result = B_NO_ERROR;
nspace* ns = (nspace*)_ns;
//dprintf("fs_unmount - ENTER\n");
//dprintf("fs_unmount - removing cached blocks\n");
remove_cached_device_blocks(ns->fd, 0);
//dprintf("fs_unmount - closing volume\n");
close(ns->fdOfSession);
result = close(ns->fd);
//dprintf("fs_unmount - freeing volume data\n");
free(ns);
//dprintf("fs_unmount - EXIT, result is %s\n", strerror(result));
return result;
}
static int
fs_read_fs_stat(void *_ns, struct fs_info *fss)
{
// Fill in fs_info struct for device.
nspace *ns = (nspace *)_ns;
int i;
//dprintf("fs_rfsstat - ENTER\n");
// Fill in device id.
//fss->dev = ns->fd;
// Root vnode ID
//fss->root = ISO_ROOTNODE_ID;
// File system flags.
fss->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY;
// FS block size.
fss->block_size = ns->logicalBlkSize[FS_DATA_FORMAT];
// IO size - specifies buffer size for file copying
fss->io_size = 65536;
// Total blocks?
fss->total_blocks = ns->volSpaceSize[FS_DATA_FORMAT];
// Free blocks = 0, read only
fss->free_blocks = 0;
// Device name.
strncpy(fss->device_name, ns->devicePath, sizeof(fss->device_name));
strncpy(fss->volume_name, ns->volIDString, sizeof(fss->volume_name));
for (i=strlen(fss->volume_name)-1;i>=0;i--)
if (fss->volume_name[i] != ' ')
break;
if (i < 0)
strcpy(fss->volume_name, "UNKNOWN");
else
fss->volume_name[i+1] = 0;
// File system name
strcpy(fss->fsh_name,"iso9660");
//dprintf("fs_rfsstat - EXIT\n");
return 0;
}
/* fs_walk - the walk function just "walks" through a directory looking for
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)
{
/* Starting at the base, find file in the subdir, and return path
string and vnode id of file. */
nspace* ns = (nspace*)_ns;
vnode* baseNode = (vnode*)base;
uint32 dataLen = baseNode->dataLen[FS_DATA_FORMAT];
vnode* newNode = NULL;
int result = ENOENT;
bool done = FALSE;
uint32 totalRead = 0;
off_t block;
block = baseNode->startLBN[FS_DATA_FORMAT];
//dprintf("fs_walk - ENTER\n");
//dprintf("fs_walk - looking for %s in dir file of length %d\n", file,baseNode->dataLen[FS_DATA_FORMAT]);
if (strcmp(file,".") == 0)
{
//dprintf("fs_walk - found \".\" file.\n");
*vnid = baseNode->id;
if (get_vnode(ns->id,*vnid,(void **)&newNode) != 0)
result = EINVAL;
else
{
result = B_NO_ERROR;
}
}
else if (strcmp(file, "..") == 0)
{
//dprintf("fs_walk - found \"..\" file.\n");
*vnid = baseNode->parID;
if (get_vnode(ns->id, *vnid, (void**)&newNode) != 0)
result = EINVAL;
else
{
result = B_NO_ERROR;
}
}
else
{
char* blockData;
while ((totalRead < dataLen) && !done)
{
off_t cachedBlock = block;
blockData = (char*)get_block(ns->fd, block, ns->logicalBlkSize[FS_DATA_FORMAT]);
if (blockData != NULL)
{
int bytesRead = 0;
off_t blockBytesRead = 0;
vnode node;
int initResult;
//dprintf("fs_walk - read buffer from disk at LBN %Ld into buffer 0x%x.\n", block, blockData);
//kernel_debugger("");
// Move to the next 2-block set if necessary
// Don't go over end of buffer, if dir record sits on boundary.
node.fileIDString = NULL;
node.attr.slName = NULL;
while (blockBytesRead < 2*ns->logicalBlkSize[FS_DATA_FORMAT] &&
(totalRead + blockBytesRead < dataLen) &&
blockData[0] != 0 &&
!done)
{
initResult = InitNode(&node, blockData, &bytesRead, ns->joliet_level);
//dprintf("fs_walk - InitNode returned %s, filename %s, %d bytes read\n", strerror(initResult), node.fileIDString, bytesRead);
if (initResult == B_NO_ERROR)
{
if ((strlen(node.fileIDString) == strlen(file)) &&
!strncmp(node.fileIDString, file, strlen(file)))
{
//dprintf("fs_walk - success, found vnode at block %Ld, pos %Ld\n", block, blockBytesRead);
*vnid = (block << 30) + (blockBytesRead & 0xFFFFFFFF);
//dprintf("fs_walk - New vnode id is %Ld\n", *vnid);
if (get_vnode(ns->id,*vnid,(void **)&newNode) != 0)
result = EINVAL;
else
{
newNode->parID = baseNode->id;
done = TRUE;
result = B_NO_ERROR;
}
}
else
{
if (node.fileIDString != NULL)
{
free(node.fileIDString);
node.fileIDString = NULL;
}
if (node.attr.slName != NULL)
{
free(node.attr.slName);
node.attr.slName = NULL;
}
}
}
else
{
result = initResult;
if (bytesRead == 0) done = TRUE;
}
blockData += bytesRead;
blockBytesRead += bytesRead;
//dprintf("fs_walk - Adding %d bytes to blockBytes read (total %Ld/%Ld).\n", bytesRead, blockBytesRead, baseNode->dataLen[FS_DATA_FORMAT]);
}
totalRead += ns->logicalBlkSize[FS_DATA_FORMAT];
block++;
//dprintf("fs_walk - moving to next block %Ld, total read %Ld\n", block, totalRead);
release_block(ns->fd, 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)
{
//dprintf ("fs_walk - symbolic link file \'%s\' requested.\n", newNode->attr.slName);
result = new_path(newNode->attr.slName, newpath);
//dprintf ("fs_walk - putting vnode.\n");
put_vnode(ns->id, *vnid);
}
}
}
//dprintf("fs_walk - EXIT, result is %s, vnid is %Lu\n", strerror(result), *vnid);
return result;
}
// fs_read_vnode - Using vnode id, read in vnode information into fs-specific struct,
// and return it in node. the reenter flag tells you if this function
// is being called via some other fs routine, so that things like
// double-locking can be avoided.
int
fs_read_vnode(void *_ns, vnode_id vnid, char reenter, void **node)
{
uint32 block, pos;
nspace *ns = (nspace*)_ns;
int result = B_NO_ERROR;
vnode *newNode = (vnode*)calloc(sizeof(vnode), 1);
(void)reenter;
pos = (vnid & 0x3FFFFFFF);
block = (vnid >> 30);
//dprintf("fs_read_vnode - ENTER, block = %ld, pos = %ld, raw = %Lu node 0x%x\n", block, pos, vnid, newNode);
if (newNode != NULL)
{
if (vnid == ISO_ROOTNODE_ID)
{
//dprintf("fs_read_vnode - root node requested.\n");
memcpy(newNode, &(ns->rootDirRec), sizeof(vnode));
*node = (void*)newNode;
}
else
{
char* blockData = (char*)get_block(ns->fd, block, ns->logicalBlkSize[FS_DATA_FORMAT]);
if (pos > ns->logicalBlkSize[FS_DATA_FORMAT]) {
if(blockData != NULL) release_block(ns->fd, block);
result = EINVAL;
} else if (blockData != NULL) {
result = InitNode(newNode, blockData + pos, NULL, ns->joliet_level);
release_block(ns->fd, block);
newNode->id = vnid;
//dprintf("fs_read_vnode - init result is %s\n", strerror(result));
*node = (void*)newNode;
//dprintf("fs_read_vnode - new file %s, size %ld\n", newNode->fileIDString, newNode->dataLen[FS_DATA_FORMAT]);
}
}
}
else result = ENOMEM;
//dprintf("fs_read_vnode - EXIT, result is %s\n", strerror(result));
return result;
}
int
fs_write_vnode(void *ns, void *_node, char reenter)
{
int result = B_NO_ERROR;
vnode *node = (vnode*)_node;
(void)ns;
(void)reenter;
//dprintf("fs_write_vnode - ENTER (0x%x)\n", node);
if (node != NULL) {
if (node->id != ISO_ROOTNODE_ID) {
if (node->fileIDString != NULL)
free (node->fileIDString);
if (node->attr.slName != NULL)
free (node->attr.slName);
free(node);
}
}
//dprintf("fs_write_vnode - EXIT\n");
return result;
}
static int
fs_read_stat(void *_ns, void *_node, struct stat *st)
{
nspace *ns = (nspace*)_ns;
vnode *node = (vnode*)_node;
int result = B_NO_ERROR;
time_t time;
//dprintf("fs_rstat - ENTER\n");
st->st_dev = ns->id;
st->st_ino = node->id;
st->st_nlink = node->attr.stat[FS_DATA_FORMAT].st_nlink;
st->st_uid = node->attr.stat[FS_DATA_FORMAT].st_uid;
st->st_gid = node->attr.stat[FS_DATA_FORMAT].st_gid;
st->st_blksize = 65536;
st->st_mode = node->attr.stat[FS_DATA_FORMAT].st_mode;
// Same for file/dir in ISO9660
st->st_size = node->dataLen[FS_DATA_FORMAT];
if (ConvertRecDate(&(node->recordDate), &time) == B_NO_ERROR)
st->st_ctime = st->st_mtime = st->st_atime = time;
//dprintf("fs_rstat - EXIT, result is %s\n", strerror(result));
return result;
}
// fs_open - Create a vnode cookie, if necessary, to use when
// reading/writing a file
static int
fs_open(void *_ns, void *_node, int omode, void **cookie)
{
int result = B_NO_ERROR;
(void)_ns;
(void)cookie;
// Do not allow any of the write-like open modes to get by
if ((omode == O_WRONLY) || (omode == O_RDWR))
result = EROFS;
else if((omode & O_TRUNC) || (omode & O_CREAT))
result = EROFS;
return result;
}
// fs_read
// Read a file specified by node, using information in cookie
// and at offset specified by pos. read len bytes into buffer buf.
static int
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 numBlocks = 0;
uint32 dataLen = node->dataLen[FS_DATA_FORMAT];
int result = B_NO_ERROR;
size_t endLen = 0;
size_t reqLen = *len;
size_t startLen = 0;
(void)cookie;
// Allow an open to work on a dir, but no reads
if (node->flags & ISO_ISDIR)
return EISDIR;
if (pos < 0)
pos = 0;
*len = 0;
// If passed-in requested length is bigger than file size, change it to
// file size.
if (reqLen + pos > dataLen)
reqLen = dataLen - pos;
// Compute the length of the partial start-block read, if any.
if (reqLen + blockPos <= blockSize)
startLen = reqLen;
else if (blockPos > 0)
startLen = blockSize - blockPos;
if (blockPos == 0 && reqLen >= blockSize) {
//dprintf("Setting startLen to 0, even block read\n");
startLen = 0;
}
// Compute the length of the partial end-block read, if any.
if (reqLen + blockPos > blockSize)
endLen = (reqLen +blockPos) % blockSize;
// Compute the number of middle blocks to read.
numBlocks = ((reqLen - endLen - startLen) / blockSize);
//dprintf("fs_read - ENTER, pos is %Ld, len is %lu\n", pos, reqLen);
//dprintf("fs_read - filename is %s\n", node->fileIDString);
//dprintf("fs_read - total file length is %lu\n", dataLen);
//dprintf("fs_read - start block of file is %lu\n", node->startLBN[FS_DATA_FORMAT]);
//dprintf("fs_read - block pos is %Lu\n", blockPos);
//dprintf("fs_read - read block will be %lu\n", startBlock);
//dprintf("fs_read - startLen is %lu\n", startLen);
//dprintf("fs_read - endLen is %lu\n", endLen);
//dprintf("fs_read - num blocks to read is %Ld\n", numBlocks);
if (pos >= dataLen) {
// If pos >= file length, return length of 0.
*len = 0;
return B_OK;
}
// Read in the first, potentially partial, block.
if (startLen > 0) {
off_t cachedBlock = startBlock;
char *blockData = (char *)get_block(ns->fd, startBlock, 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);
startBlock++;
}
else result = EIO;
}
// Read in the middle blocks.
if (numBlocks > 0 && result == B_NO_ERROR) {
//dprintf("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;
}
// 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);
if (endBlockData != NULL) {
char *endBuf = ((char *)buf) + (reqLen - endLen);
memcpy(endBuf, endBlockData, endLen);
release_block(ns->fd, endBlock);
*len += endLen;
} else
result = EIO;
}
//dprintf("fs_read - EXIT, result is %s\n", strerror(result));
return result;
}
// fs_close - Do whatever is necessary to close a file, EXCEPT for freeing
// the cookie!
static int
fs_close(void *ns, void *node, void *cookie)
{
(void)ns;
(void)node;
(void)cookie;
//dprintf("fs_close - ENTER\n");
//dprintf("fs_close - EXIT\n");
return 0;
}
static int
fs_free_cookie(void *ns, void *node, void *cookie)
{
(void)ns;
(void)node;
(void)cookie;
// We don't allocate file cookies, so we do nothing here.
//dprintf("fs_free_cookie - ENTER\n");
//if (cookie != NULL) free (cookie);
//dprintf("fs_free_cookie - EXIT\n");
return 0;
}
// fs_access - checks permissions for access.
static int
fs_access(void *ns, void *node, int mode)
{
(void)ns;
(void)node;
(void)mode;
// ns - global, fs-specific struct for device
// node - node to check permissions for
// mode - requested permissions on node.
//dprintf("fs_access - ENTER\n");
//dprintf("fs_access - EXIT\n");
return 0;
}
static int
fs_read_link(void *_ns, void *_node, char *buffer, size_t *_bufferSize)
{
vnode *node = (vnode *)_node;
int result = EINVAL;
(void)_ns;
if (S_ISLNK(node->attr.stat[FS_DATA_FORMAT].st_mode)) {
size_t length = strlen(node->attr.slName);
if (length > *_bufferSize)
memcpy(buffer, node->attr.slName, length);
else
memcpy(buffer, node->attr.slName, length);
result = B_NO_ERROR;
*_bufferSize = length;
}
return result;
}
static int
fs_open_dir(void *_ns, void *_node, void **cookie)
{
// creates fs-specific "cookie" struct that keeps track of where
// you are at in reading through directory entries in fs_readdir.
vnode *node = (vnode *)_node;
int result = B_NO_ERROR;
dircookie *dirCookie = (dircookie *)malloc(sizeof(dircookie));
(void)_ns;
//dprintf("fs_opendir - ENTER, node is 0x%x\n", _node);
if (!(node->flags & ISO_ISDIR))
result = EMFILE;
if (dirCookie != NULL) {
dirCookie->startBlock = node->startLBN[FS_DATA_FORMAT];
dirCookie->block = node->startLBN[FS_DATA_FORMAT];
dirCookie->totalSize = node->dataLen[FS_DATA_FORMAT];
dirCookie->pos = 0;
dirCookie->id = node->id;
*cookie = (void *)dirCookie;
} else
result = ENOMEM;
//dprintf("fs_opendir - EXIT\n");
return result;
}
static int
fs_read_dir(void *_ns, void *_node, void *_cookie, long *num,
struct dirent *buffer, size_t bufferSize)
{
int result = B_NO_ERROR;
nspace *ns = (nspace *)_ns;
dircookie *dirCookie = (dircookie *)_cookie;
(void)_node;
//dprintf("fs_readdir - ENTER\n");
result = ISOReadDirEnt(ns, dirCookie, buffer, bufferSize);
// If we succeeded, return 1, the number of dirents we read.
if (result == B_NO_ERROR)
*num = 1;
else
*num = 0;
// When you get to the end, don't return an error, just return
// a zero in *num.
if (result == ENOENT)
result = B_NO_ERROR;
//dprintf("fs_readdir - EXIT, result is %s\n", strerror(result));
return result;
}
static int
fs_rewind_dir(void *ns, void *node, void* _cookie)
{
int result = EINVAL;
dircookie *cookie = (dircookie*)_cookie;
(void)ns;
(void)node;
//dprintf("fs_rewinddir - ENTER\n");
if (cookie != NULL) {
cookie->block = cookie->startBlock;
cookie->pos = 0;
result = B_NO_ERROR;
}
//dprintf("fs_rewinddir - EXIT, result is %s\n", strerror(result));
return result;
}
static int
fs_close_dir(void *ns, void *node, void *cookie)
{
(void)ns;
(void)node;
(void)cookie;
// ns - global, fs-specific struct for device
// node - directory to close
// cookie - current cookie for directory.
//dprintf("fs_closedir - ENTER\n");
//dprintf("fs_closedir - EXIT\n");
return 0;
}
static int
fs_free_dir_cookie(void *ns, void *node, void *cookie)
{
(void)ns;
(void)node;
// ns - global, fs-specific struct for device
// node - directory related to cookie
// cookie - current cookie for directory, to free.
//dprintf("fs_free_dircookie - ENTER\n");
if (cookie != NULL)
free(cookie);
//dprintf("fs_free_dircookie - EXIT\n");
return 0;
}

View File

@ -0,0 +1,32 @@
#ifndef _LOCK_H
#define _LOCK_H
#include <BeBuild.h>
#include <OS.h>
typedef struct lock lock;
typedef struct mlock mlock;
struct lock {
sem_id s;
long c;
};
struct mlock {
sem_id s;
};
extern _IMPEXP_KERNEL int new_lock(lock *l, const char *name);
extern _IMPEXP_KERNEL int free_lock(lock *l);
#define LOCK(l) if (atomic_add(&l.c, -1) <= 0) acquire_sem(l.s);
#define UNLOCK(l) if (atomic_add(&l.c, 1) < 0) release_sem(l.s);
extern _IMPEXP_KERNEL int new_mlock(mlock *l, long c, const char *name);
extern _IMPEXP_KERNEL int free_mlock(mlock *l);
#define LOCKM(l,cnt) acquire_sem_etc(l.s, cnt, 0, 0)
#define UNLOCKM(l,cnt) release_sem_etc(l.s, cnt, 0)
#endif

View File

@ -0,0 +1,32 @@
// rock.h
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
// Altername name field flags.
enum
{
NM_CONTINUE = 1,
NM_CURRENT = 2,
NM_PARENT = 4,
NM_HOST = 32
} NMFLAGS;
// Symbolic link field flags
enum
{
SL_CONTINUE = 1
} SLFLAGS;
// Symbolic link field component flags
enum
{
SLCP_CONTINUE = 1,
SLCP_CURRENT = 2,
SLCP_PARENT = 4,
SLCP_ROOT = 8,
SLCP_VOLROOT = 16,
SLCP_HOST = 32
} SLCPFLAGS;