diff --git a/src/tests/add-ons/kernel/file_systems/iso9660/r5/Jamfile b/src/tests/add-ons/kernel/file_systems/iso9660/r5/Jamfile new file mode 100644 index 0000000000..8680b6564b --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/iso9660/r5/Jamfile @@ -0,0 +1,43 @@ +SubDir HAIKU_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) = 0 { + # the gcc on BeOS doesn't compile BFS correctly with -O2 or more + OPTIM = -O1 ; + } + + defines = [ FDefines $(defines) ] ; + SubDirCcFlags $(defines) -Wall -Wno-multichar ; +} + +KernelAddon iso9660 : kernel file_systems : + 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) ; diff --git a/src/tests/add-ons/kernel/file_systems/iso9660/r5/LICENSE b/src/tests/add-ons/kernel/file_systems/iso9660/r5/LICENSE new file mode 100644 index 0000000000..86a4268fa9 --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/iso9660/r5/LICENSE @@ -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. diff --git a/src/tests/add-ons/kernel/file_systems/iso9660/r5/cache.h b/src/tests/add-ons/kernel/file_systems/iso9660/r5/cache.h new file mode 100644 index 0000000000..b491d141d7 --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/iso9660/r5/cache.h @@ -0,0 +1,103 @@ +#ifndef _CACHE_H_ +#define _CACHE_H_ + +#include + +typedef struct hash_ent { + int dev; + off_t bnum; + off_t hash_val; + void *data; + struct hash_ent *next; +} hash_ent; + + +typedef struct hash_table { + hash_ent **table; + int max; + int mask; /* == max - 1 */ + int num_elements; +} hash_table; + + +#define HT_DEFAULT_MAX 128 + + +typedef struct cache_ent { + int dev; + off_t block_num; + int bsize; + volatile int flags; + + void *data; + void *clone; /* copy of data by set_block_info() */ + int lock; + + void (*func)(off_t bnum, size_t num_blocks, void *arg); + off_t logged_bnum; + void *arg; + + struct cache_ent *next, /* points toward mru end of list */ + *prev; /* points toward lru end of list */ + +} cache_ent; + +#define CE_NORMAL 0x0000 /* a nice clean pristine page */ +#define CE_DIRTY 0x0002 /* needs to be written to disk */ +#define CE_BUSY 0x0004 /* this block has i/o happening, don't touch it */ + + +typedef struct cache_ent_list { + cache_ent *lru; /* tail of the list */ + cache_ent *mru; /* head of the list */ +} cache_ent_list; + + +typedef struct block_cache { + lock lock; + int flags; + int cur_blocks; + int max_blocks; + hash_table ht; + + cache_ent_list normal, /* list of "normal" blocks (clean & dirty) */ + locked; /* list of clean and locked blocks */ +} block_cache; + +#if 0 /* XXXdbg -- need to deal with write through caches */ +#define DC_WRITE_THROUGH 0x0001 /* cache is write-through (for floppies) */ +#endif + +#define ALLOW_WRITES 1 +#define NO_WRITES 0 + +extern _IMPEXP_KERNEL int init_block_cache(int max_blocks, int flags); +extern _IMPEXP_KERNEL void shutdown_block_cache(void); + +extern _IMPEXP_KERNEL void force_cache_flush(int dev, int prefer_log_blocks); +extern _IMPEXP_KERNEL int flush_blocks(int dev, off_t bnum, int nblocks); +extern _IMPEXP_KERNEL int flush_device(int dev, int warn_locked); + +extern _IMPEXP_KERNEL int init_cache_for_device(int fd, off_t max_blocks); +extern _IMPEXP_KERNEL int remove_cached_device_blocks(int dev, int allow_write); + +extern _IMPEXP_KERNEL void *get_block(int dev, off_t bnum, int bsize); +extern _IMPEXP_KERNEL void *get_empty_block(int dev, off_t bnum, int bsize); +extern _IMPEXP_KERNEL int release_block(int dev, off_t bnum); +extern _IMPEXP_KERNEL int mark_blocks_dirty(int dev, off_t bnum, int nblocks); + + +extern _IMPEXP_KERNEL int cached_read(int dev, off_t bnum, void *data, off_t num_blocks, int bsize); +extern _IMPEXP_KERNEL int cached_write(int dev, off_t bnum, const void *data, + off_t num_blocks, int bsize); +extern _IMPEXP_KERNEL int cached_write_locked(int dev, off_t bnum, const void *data, + off_t num_blocks, int bsize); +extern _IMPEXP_KERNEL int set_blocks_info(int dev, off_t *blocks, int nblocks, + void (*func)(off_t bnum, size_t nblocks, void *arg), + void *arg); + + +extern _IMPEXP_KERNEL size_t read_phys_blocks (int fd, off_t bnum, void *data, uint num_blocks, int bsize); +extern _IMPEXP_KERNEL size_t write_phys_blocks(int fd, off_t bnum, void *data, uint num_blocks, int bsize); + +#endif /* _CACHE_H_ */ diff --git a/src/tests/add-ons/kernel/file_systems/iso9660/r5/fsproto.h b/src/tests/add-ons/kernel/file_systems/iso9660/r5/fsproto.h new file mode 100644 index 0000000000..000809c3bc --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/iso9660/r5/fsproto.h @@ -0,0 +1,240 @@ +#ifndef _FSPROTO_H +#define _FSPROTO_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +typedef dev_t nspace_id; +typedef ino_t vnode_id; + +/* + * PUBLIC PART OF THE FILE SYSTEM PROTOCOL + */ + +#define WSTAT_MODE 0x0001 +#define WSTAT_UID 0x0002 +#define WSTAT_GID 0x0004 +#define WSTAT_SIZE 0x0008 +#define WSTAT_ATIME 0x0010 +#define WSTAT_MTIME 0x0020 +#define WSTAT_CRTIME 0x0040 + +#define WFSSTAT_NAME 0x0001 + +#define B_ENTRY_CREATED 1 +#define B_ENTRY_REMOVED 2 +#define B_ENTRY_MOVED 3 +#define B_STAT_CHANGED 4 +#define B_ATTR_CHANGED 5 +#define B_DEVICE_MOUNTED 6 +#define B_DEVICE_UNMOUNTED 7 + +#define B_STOP_WATCHING 0x0000 +#define B_WATCH_NAME 0x0001 +#define B_WATCH_STAT 0x0002 +#define B_WATCH_ATTR 0x0004 +#define B_WATCH_DIRECTORY 0x0008 + +#define SELECT_READ 1 +#define SELECT_WRITE 2 +#define SELECT_EXCEPTION 3 + +#define B_CUR_FS_API_VERSION 2 + +struct attr_info; +struct index_info; + +typedef int op_read_vnode(void *ns, vnode_id vnid, char r, void **node); +typedef int op_write_vnode(void *ns, void *node, char r); +typedef int op_remove_vnode(void *ns, void *node, char r); +typedef int op_secure_vnode(void *ns, void *node); + +typedef int op_walk(void *ns, void *base, const char *file, char **newpath, + vnode_id *vnid); + +typedef int op_access(void *ns, void *node, int mode); + +typedef int op_create(void *ns, void *dir, const char *name, + int omode, int perms, vnode_id *vnid, void **cookie); +typedef int op_mkdir(void *ns, void *dir, const char *name, int perms); +typedef int op_symlink(void *ns, void *dir, const char *name, + const char *path); +typedef int op_link(void *ns, void *dir, const char *name, void *node); + +typedef int op_rename(void *ns, void *olddir, const char *oldname, + void *newdir, const char *newname); +typedef int op_unlink(void *ns, void *dir, const char *name); +typedef int op_rmdir(void *ns, void *dir, const char *name); + +typedef int op_readlink(void *ns, void *node, char *buf, size_t *bufsize); + +typedef int op_opendir(void *ns, void *node, void **cookie); +typedef int op_closedir(void *ns, void *node, void *cookie); +typedef int op_rewinddir(void *ns, void *node, void *cookie); +typedef int op_readdir(void *ns, void *node, void *cookie, long *num, + struct dirent *buf, size_t bufsize); + +typedef int op_open(void *ns, void *node, int omode, void **cookie); +typedef int op_close(void *ns, void *node, void *cookie); +typedef int op_free_cookie(void *ns, void *node, void *cookie); +typedef int op_read(void *ns, void *node, void *cookie, off_t pos, void *buf, + size_t *len); +typedef int op_write(void *ns, void *node, void *cookie, off_t pos, + const void *buf, size_t *len); +typedef int op_readv(void *ns, void *node, void *cookie, off_t pos, const iovec *vec, + size_t count, size_t *len); +typedef int op_writev(void *ns, void *node, void *cookie, off_t pos, const iovec *vec, + size_t count, size_t *len); +typedef int op_ioctl(void *ns, void *node, void *cookie, int cmd, void *buf, + size_t len); +typedef int op_setflags(void *ns, void *node, void *cookie, int flags); + +typedef int op_rstat(void *ns, void *node, struct stat *); +typedef int op_wstat(void *ns, void *node, struct stat *, long mask); +typedef int op_fsync(void *ns, void *node); + +typedef int op_select(void *ns, void *node, void *cookie, uint8 event, + uint32 ref, selectsync *sync); +typedef int op_deselect(void *ns, void *node, void *cookie, uint8 event, + selectsync *sync); + +typedef int op_initialize(const char *devname, void *parms, size_t len); +typedef int op_mount(nspace_id nsid, const char *devname, ulong flags, + void *parms, size_t len, void **data, vnode_id *vnid); +typedef int op_unmount(void *ns); +typedef int op_sync(void *ns); +typedef int op_rfsstat(void *ns, struct fs_info *); +typedef int op_wfsstat(void *ns, struct fs_info *, long mask); + + +typedef int op_open_attrdir(void *ns, void *node, void **cookie); +typedef int op_close_attrdir(void *ns, void *node, void *cookie); +typedef int op_rewind_attrdir(void *ns, void *node, void *cookie); +typedef int op_read_attrdir(void *ns, void *node, void *cookie, long *num, + struct dirent *buf, size_t bufsize); +typedef int op_remove_attr(void *ns, void *node, const char *name); +typedef int op_rename_attr(void *ns, void *node, const char *oldname, + const char *newname); +typedef int op_stat_attr(void *ns, void *node, const char *name, + struct attr_info *buf); + +typedef int op_write_attr(void *ns, void *node, const char *name, int type, + const void *buf, size_t *len, off_t pos); +typedef int op_read_attr(void *ns, void *node, const char *name, int type, + void *buf, size_t *len, off_t pos); + +typedef int op_open_indexdir(void *ns, void **cookie); +typedef int op_close_indexdir(void *ns, void *cookie); +typedef int op_rewind_indexdir(void *ns, void *cookie); +typedef int op_read_indexdir(void *ns, void *cookie, long *num, + struct dirent *buf, size_t bufsize); +typedef int op_create_index(void *ns, const char *name, int type, int flags); +typedef int op_remove_index(void *ns, const char *name); +typedef int op_rename_index(void *ns, const char *oldname, + const char *newname); +typedef int op_stat_index(void *ns, const char *name, struct index_info *buf); + +typedef int op_open_query(void *ns, const char *query, ulong flags, + port_id port, long token, void **cookie); +typedef int op_close_query(void *ns, void *cookie); +typedef int op_read_query(void *ns, void *cookie, long *num, + struct dirent *buf, size_t bufsize); + +typedef struct vnode_ops { + op_read_vnode (*read_vnode); + op_write_vnode (*write_vnode); + op_remove_vnode (*remove_vnode); + op_secure_vnode (*secure_vnode); + op_walk (*walk); + op_access (*access); + op_create (*create); + op_mkdir (*mkdir); + op_symlink (*symlink); + op_link (*link); + op_rename (*rename); + op_unlink (*unlink); + op_rmdir (*rmdir); + op_readlink (*readlink); + op_opendir (*opendir); + op_closedir (*closedir); + op_free_cookie (*free_dircookie); + op_rewinddir (*rewinddir); + op_readdir (*readdir); + op_open (*open); + op_close (*close); + op_free_cookie (*free_cookie); + op_read (*read); + op_write (*write); + op_readv (*readv); + op_writev (*writev); + op_ioctl (*ioctl); + op_setflags (*setflags); + op_rstat (*rstat); + op_wstat (*wstat); + op_fsync (*fsync); + op_initialize (*initialize); + op_mount (*mount); + op_unmount (*unmount); + op_sync (*sync); + op_rfsstat (*rfsstat); + op_wfsstat (*wfsstat); + op_select (*select); + op_deselect (*deselect); + op_open_indexdir (*open_indexdir); + op_close_indexdir (*close_indexdir); + op_free_cookie (*free_indexdircookie); + op_rewind_indexdir (*rewind_indexdir); + op_read_indexdir (*read_indexdir); + op_create_index (*create_index); + op_remove_index (*remove_index); + op_rename_index (*rename_index); + op_stat_index (*stat_index); + op_open_attrdir (*open_attrdir); + op_close_attrdir (*close_attrdir); + op_free_cookie (*free_attrdircookie); + op_rewind_attrdir (*rewind_attrdir); + op_read_attrdir (*read_attrdir); + op_write_attr (*write_attr); + op_read_attr (*read_attr); + op_remove_attr (*remove_attr); + op_rename_attr (*rename_attr); + op_stat_attr (*stat_attr); + op_open_query (*open_query); + op_close_query (*close_query); + op_free_cookie (*free_querycookie); + op_read_query (*read_query); +} vnode_ops; + +extern _IMPEXP_KERNEL int new_path(const char *path, char **copy); +extern _IMPEXP_KERNEL void free_path(char *p); + +extern _IMPEXP_KERNEL int notify_listener(int op, nspace_id nsid, + vnode_id vnida, vnode_id vnidb, + vnode_id vnidc, const char *name); +extern _IMPEXP_KERNEL int send_notification(port_id port, long token, + ulong what, long op, nspace_id nsida, + nspace_id nsidb, vnode_id vnida, + vnode_id vnidb, vnode_id vnidc, + const char *name); +extern _IMPEXP_KERNEL int get_vnode(nspace_id nsid, vnode_id vnid, void **data); +extern _IMPEXP_KERNEL int put_vnode(nspace_id nsid, vnode_id vnid); +extern _IMPEXP_KERNEL int new_vnode(nspace_id nsid, vnode_id vnid, void *data); +extern _IMPEXP_KERNEL int remove_vnode(nspace_id nsid, vnode_id vnid); +extern _IMPEXP_KERNEL int unremove_vnode(nspace_id nsid, vnode_id vnid); +extern _IMPEXP_KERNEL int is_vnode_removed(nspace_id nsid, vnode_id vnid); + + +extern _EXPORT vnode_ops fs_entry; +extern _EXPORT int32 api_version; + +#endif diff --git a/src/tests/add-ons/kernel/file_systems/iso9660/r5/iso.c b/src/tests/add-ons/kernel/file_systems/iso9660/r5/iso.c new file mode 100644 index 0000000000..b31c6d1d79 --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/iso9660/r5/iso.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rock.h" +#include "iso.h" + +#define TRACE_ISO9660 0 +#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; +} + diff --git a/src/tests/add-ons/kernel/file_systems/iso9660/r5/iso.h b/src/tests/add-ons/kernel/file_systems/iso9660/r5/iso.h new file mode 100644 index 0000000000..656b78113d --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/iso9660/r5/iso.h @@ -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 +#include +#include +#include +#include +#include + +#include + +// 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 diff --git a/src/tests/add-ons/kernel/file_systems/iso9660/r5/kernel_interface.c b/src/tests/add-ons/kernel/file_systems/iso9660/r5/kernel_interface.c new file mode 100644 index 0000000000..30bb3c21fa --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/iso9660/r5/kernel_interface.c @@ -0,0 +1,840 @@ +/* +** 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iso.h" + +#define TRACE_ISO9660 0 +#if TRACE_ISO9660 +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + + +/* 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) { + uint32 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; + + TRACE(("fs_unmount - ENTER\n")); + + remove_cached_device_blocks(ns->fd, 0); + close(ns->fdOfSession); + result = close(ns->fd); + + free(ns); + + TRACE(("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; + + TRACE(("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"); + + TRACE(("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 = baseNode->startLBN[FS_DATA_FORMAT]; + + TRACE(("fs_walk - looking for %s in dir file of length %d\n", file, + baseNode->dataLen[FS_DATA_FORMAT])); + + if (strcmp(file, ".") == 0) { + // base directory + TRACE(("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) { + // parent directory + TRACE(("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 { + // look up file in the directory + 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; + + TRACE(("fs_walk - read buffer from disk at LBN %Ld into buffer 0x%x.\n", + block, blockData)); + + // 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); + TRACE(("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))) + { + 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)); + + 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; + + TRACE(("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++; + + TRACE(("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) { + TRACE(("fs_walk - symbolic link file \'%s\' requested.\n", newNode->attr.slName)); + result = new_path(newNode->attr.slName, newpath); + put_vnode(ns->id, *vnid); + } + } + } + TRACE(("fs_walk - EXIT, result is %s, vnid is %Lu\n", strerror(result), *vnid)); + return result; +} + + +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); + + TRACE(("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) { + TRACE(("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; + + TRACE(("fs_read_vnode - init result is %s\n", strerror(result))); + *node = (void *)newNode; + TRACE(("fs_read_vnode - new file %s, size %ld\n", newNode->fileIDString, newNode->dataLen[FS_DATA_FORMAT])); + } + } + } else + result = ENOMEM; + + TRACE(("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; + + TRACE(("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); + } + } + + TRACE(("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; + + TRACE(("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; + + TRACE(("fs_rstat - EXIT, result is %s\n", strerror(result))); + + return result; +} + + +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; +} + + +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) { + TRACE(("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) { + 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; + } + + // 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; + } + + TRACE(("fs_read - EXIT, result is %s\n", strerror(result))); + return result; +} + + +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) +{ + vnode *node = (vnode *)_node; + int result = B_NO_ERROR; + dircookie *dirCookie = (dircookie *)malloc(sizeof(dircookie)); + + (void)_ns; + + TRACE(("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; + + TRACE(("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; + + TRACE(("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; + + TRACE(("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; +} diff --git a/src/tests/add-ons/kernel/file_systems/iso9660/r5/lock.h b/src/tests/add-ons/kernel/file_systems/iso9660/r5/lock.h new file mode 100644 index 0000000000..d2941ead29 --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/iso9660/r5/lock.h @@ -0,0 +1,32 @@ +#ifndef _LOCK_H +#define _LOCK_H + +#include + +#include + +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 diff --git a/src/tests/add-ons/kernel/file_systems/iso9660/r5/rock.h b/src/tests/add-ons/kernel/file_systems/iso9660/r5/rock.h new file mode 100644 index 0000000000..53736d90df --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/iso9660/r5/rock.h @@ -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;