moved iso9660 R5 version to tests
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16538 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
89d76e508d
commit
e2a69d2257
43
src/tests/add-ons/kernel/file_systems/iso9660/r5/Jamfile
Normal file
43
src/tests/add-ons/kernel/file_systems/iso9660/r5/Jamfile
Normal file
@ -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) ;
|
31
src/tests/add-ons/kernel/file_systems/iso9660/r5/LICENSE
Normal file
31
src/tests/add-ons/kernel/file_systems/iso9660/r5/LICENSE
Normal 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.
|
103
src/tests/add-ons/kernel/file_systems/iso9660/r5/cache.h
Normal file
103
src/tests/add-ons/kernel/file_systems/iso9660/r5/cache.h
Normal 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_ */
|
240
src/tests/add-ons/kernel/file_systems/iso9660/r5/fsproto.h
Normal file
240
src/tests/add-ons/kernel/file_systems/iso9660/r5/fsproto.h
Normal file
@ -0,0 +1,240 @@
|
||||
#ifndef _FSPROTO_H
|
||||
#define _FSPROTO_H
|
||||
|
||||
#include <sys/dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <iovec.h>
|
||||
|
||||
#include <OS.h>
|
||||
#include <fs_attr.h>
|
||||
#include <fs_info.h>
|
||||
#include <BeBuild.h>
|
||||
#include <Drivers.h>
|
||||
|
||||
typedef dev_t nspace_id;
|
||||
typedef ino_t vnode_id;
|
||||
|
||||
/*
|
||||
* PUBLIC PART OF THE FILE SYSTEM PROTOCOL
|
||||
*/
|
||||
|
||||
#define WSTAT_MODE 0x0001
|
||||
#define WSTAT_UID 0x0002
|
||||
#define WSTAT_GID 0x0004
|
||||
#define WSTAT_SIZE 0x0008
|
||||
#define WSTAT_ATIME 0x0010
|
||||
#define WSTAT_MTIME 0x0020
|
||||
#define WSTAT_CRTIME 0x0040
|
||||
|
||||
#define WFSSTAT_NAME 0x0001
|
||||
|
||||
#define B_ENTRY_CREATED 1
|
||||
#define B_ENTRY_REMOVED 2
|
||||
#define B_ENTRY_MOVED 3
|
||||
#define B_STAT_CHANGED 4
|
||||
#define B_ATTR_CHANGED 5
|
||||
#define B_DEVICE_MOUNTED 6
|
||||
#define B_DEVICE_UNMOUNTED 7
|
||||
|
||||
#define B_STOP_WATCHING 0x0000
|
||||
#define B_WATCH_NAME 0x0001
|
||||
#define B_WATCH_STAT 0x0002
|
||||
#define B_WATCH_ATTR 0x0004
|
||||
#define B_WATCH_DIRECTORY 0x0008
|
||||
|
||||
#define SELECT_READ 1
|
||||
#define SELECT_WRITE 2
|
||||
#define SELECT_EXCEPTION 3
|
||||
|
||||
#define B_CUR_FS_API_VERSION 2
|
||||
|
||||
struct attr_info;
|
||||
struct index_info;
|
||||
|
||||
typedef int op_read_vnode(void *ns, vnode_id vnid, char r, void **node);
|
||||
typedef int op_write_vnode(void *ns, void *node, char r);
|
||||
typedef int op_remove_vnode(void *ns, void *node, char r);
|
||||
typedef int op_secure_vnode(void *ns, void *node);
|
||||
|
||||
typedef int op_walk(void *ns, void *base, const char *file, char **newpath,
|
||||
vnode_id *vnid);
|
||||
|
||||
typedef int op_access(void *ns, void *node, int mode);
|
||||
|
||||
typedef int op_create(void *ns, void *dir, const char *name,
|
||||
int omode, int perms, vnode_id *vnid, void **cookie);
|
||||
typedef int op_mkdir(void *ns, void *dir, const char *name, int perms);
|
||||
typedef int op_symlink(void *ns, void *dir, const char *name,
|
||||
const char *path);
|
||||
typedef int op_link(void *ns, void *dir, const char *name, void *node);
|
||||
|
||||
typedef int op_rename(void *ns, void *olddir, const char *oldname,
|
||||
void *newdir, const char *newname);
|
||||
typedef int op_unlink(void *ns, void *dir, const char *name);
|
||||
typedef int op_rmdir(void *ns, void *dir, const char *name);
|
||||
|
||||
typedef int op_readlink(void *ns, void *node, char *buf, size_t *bufsize);
|
||||
|
||||
typedef int op_opendir(void *ns, void *node, void **cookie);
|
||||
typedef int op_closedir(void *ns, void *node, void *cookie);
|
||||
typedef int op_rewinddir(void *ns, void *node, void *cookie);
|
||||
typedef int op_readdir(void *ns, void *node, void *cookie, long *num,
|
||||
struct dirent *buf, size_t bufsize);
|
||||
|
||||
typedef int op_open(void *ns, void *node, int omode, void **cookie);
|
||||
typedef int op_close(void *ns, void *node, void *cookie);
|
||||
typedef int op_free_cookie(void *ns, void *node, void *cookie);
|
||||
typedef int op_read(void *ns, void *node, void *cookie, off_t pos, void *buf,
|
||||
size_t *len);
|
||||
typedef int op_write(void *ns, void *node, void *cookie, off_t pos,
|
||||
const void *buf, size_t *len);
|
||||
typedef int op_readv(void *ns, void *node, void *cookie, off_t pos, const iovec *vec,
|
||||
size_t count, size_t *len);
|
||||
typedef int op_writev(void *ns, void *node, void *cookie, off_t pos, const iovec *vec,
|
||||
size_t count, size_t *len);
|
||||
typedef int op_ioctl(void *ns, void *node, void *cookie, int cmd, void *buf,
|
||||
size_t len);
|
||||
typedef int op_setflags(void *ns, void *node, void *cookie, int flags);
|
||||
|
||||
typedef int op_rstat(void *ns, void *node, struct stat *);
|
||||
typedef int op_wstat(void *ns, void *node, struct stat *, long mask);
|
||||
typedef int op_fsync(void *ns, void *node);
|
||||
|
||||
typedef int op_select(void *ns, void *node, void *cookie, uint8 event,
|
||||
uint32 ref, selectsync *sync);
|
||||
typedef int op_deselect(void *ns, void *node, void *cookie, uint8 event,
|
||||
selectsync *sync);
|
||||
|
||||
typedef int op_initialize(const char *devname, void *parms, size_t len);
|
||||
typedef int op_mount(nspace_id nsid, const char *devname, ulong flags,
|
||||
void *parms, size_t len, void **data, vnode_id *vnid);
|
||||
typedef int op_unmount(void *ns);
|
||||
typedef int op_sync(void *ns);
|
||||
typedef int op_rfsstat(void *ns, struct fs_info *);
|
||||
typedef int op_wfsstat(void *ns, struct fs_info *, long mask);
|
||||
|
||||
|
||||
typedef int op_open_attrdir(void *ns, void *node, void **cookie);
|
||||
typedef int op_close_attrdir(void *ns, void *node, void *cookie);
|
||||
typedef int op_rewind_attrdir(void *ns, void *node, void *cookie);
|
||||
typedef int op_read_attrdir(void *ns, void *node, void *cookie, long *num,
|
||||
struct dirent *buf, size_t bufsize);
|
||||
typedef int op_remove_attr(void *ns, void *node, const char *name);
|
||||
typedef int op_rename_attr(void *ns, void *node, const char *oldname,
|
||||
const char *newname);
|
||||
typedef int op_stat_attr(void *ns, void *node, const char *name,
|
||||
struct attr_info *buf);
|
||||
|
||||
typedef int op_write_attr(void *ns, void *node, const char *name, int type,
|
||||
const void *buf, size_t *len, off_t pos);
|
||||
typedef int op_read_attr(void *ns, void *node, const char *name, int type,
|
||||
void *buf, size_t *len, off_t pos);
|
||||
|
||||
typedef int op_open_indexdir(void *ns, void **cookie);
|
||||
typedef int op_close_indexdir(void *ns, void *cookie);
|
||||
typedef int op_rewind_indexdir(void *ns, void *cookie);
|
||||
typedef int op_read_indexdir(void *ns, void *cookie, long *num,
|
||||
struct dirent *buf, size_t bufsize);
|
||||
typedef int op_create_index(void *ns, const char *name, int type, int flags);
|
||||
typedef int op_remove_index(void *ns, const char *name);
|
||||
typedef int op_rename_index(void *ns, const char *oldname,
|
||||
const char *newname);
|
||||
typedef int op_stat_index(void *ns, const char *name, struct index_info *buf);
|
||||
|
||||
typedef int op_open_query(void *ns, const char *query, ulong flags,
|
||||
port_id port, long token, void **cookie);
|
||||
typedef int op_close_query(void *ns, void *cookie);
|
||||
typedef int op_read_query(void *ns, void *cookie, long *num,
|
||||
struct dirent *buf, size_t bufsize);
|
||||
|
||||
typedef struct vnode_ops {
|
||||
op_read_vnode (*read_vnode);
|
||||
op_write_vnode (*write_vnode);
|
||||
op_remove_vnode (*remove_vnode);
|
||||
op_secure_vnode (*secure_vnode);
|
||||
op_walk (*walk);
|
||||
op_access (*access);
|
||||
op_create (*create);
|
||||
op_mkdir (*mkdir);
|
||||
op_symlink (*symlink);
|
||||
op_link (*link);
|
||||
op_rename (*rename);
|
||||
op_unlink (*unlink);
|
||||
op_rmdir (*rmdir);
|
||||
op_readlink (*readlink);
|
||||
op_opendir (*opendir);
|
||||
op_closedir (*closedir);
|
||||
op_free_cookie (*free_dircookie);
|
||||
op_rewinddir (*rewinddir);
|
||||
op_readdir (*readdir);
|
||||
op_open (*open);
|
||||
op_close (*close);
|
||||
op_free_cookie (*free_cookie);
|
||||
op_read (*read);
|
||||
op_write (*write);
|
||||
op_readv (*readv);
|
||||
op_writev (*writev);
|
||||
op_ioctl (*ioctl);
|
||||
op_setflags (*setflags);
|
||||
op_rstat (*rstat);
|
||||
op_wstat (*wstat);
|
||||
op_fsync (*fsync);
|
||||
op_initialize (*initialize);
|
||||
op_mount (*mount);
|
||||
op_unmount (*unmount);
|
||||
op_sync (*sync);
|
||||
op_rfsstat (*rfsstat);
|
||||
op_wfsstat (*wfsstat);
|
||||
op_select (*select);
|
||||
op_deselect (*deselect);
|
||||
op_open_indexdir (*open_indexdir);
|
||||
op_close_indexdir (*close_indexdir);
|
||||
op_free_cookie (*free_indexdircookie);
|
||||
op_rewind_indexdir (*rewind_indexdir);
|
||||
op_read_indexdir (*read_indexdir);
|
||||
op_create_index (*create_index);
|
||||
op_remove_index (*remove_index);
|
||||
op_rename_index (*rename_index);
|
||||
op_stat_index (*stat_index);
|
||||
op_open_attrdir (*open_attrdir);
|
||||
op_close_attrdir (*close_attrdir);
|
||||
op_free_cookie (*free_attrdircookie);
|
||||
op_rewind_attrdir (*rewind_attrdir);
|
||||
op_read_attrdir (*read_attrdir);
|
||||
op_write_attr (*write_attr);
|
||||
op_read_attr (*read_attr);
|
||||
op_remove_attr (*remove_attr);
|
||||
op_rename_attr (*rename_attr);
|
||||
op_stat_attr (*stat_attr);
|
||||
op_open_query (*open_query);
|
||||
op_close_query (*close_query);
|
||||
op_free_cookie (*free_querycookie);
|
||||
op_read_query (*read_query);
|
||||
} vnode_ops;
|
||||
|
||||
extern _IMPEXP_KERNEL int new_path(const char *path, char **copy);
|
||||
extern _IMPEXP_KERNEL void free_path(char *p);
|
||||
|
||||
extern _IMPEXP_KERNEL int notify_listener(int op, nspace_id nsid,
|
||||
vnode_id vnida, vnode_id vnidb,
|
||||
vnode_id vnidc, const char *name);
|
||||
extern _IMPEXP_KERNEL int send_notification(port_id port, long token,
|
||||
ulong what, long op, nspace_id nsida,
|
||||
nspace_id nsidb, vnode_id vnida,
|
||||
vnode_id vnidb, vnode_id vnidc,
|
||||
const char *name);
|
||||
extern _IMPEXP_KERNEL int get_vnode(nspace_id nsid, vnode_id vnid, void **data);
|
||||
extern _IMPEXP_KERNEL int put_vnode(nspace_id nsid, vnode_id vnid);
|
||||
extern _IMPEXP_KERNEL int new_vnode(nspace_id nsid, vnode_id vnid, void *data);
|
||||
extern _IMPEXP_KERNEL int remove_vnode(nspace_id nsid, vnode_id vnid);
|
||||
extern _IMPEXP_KERNEL int unremove_vnode(nspace_id nsid, vnode_id vnid);
|
||||
extern _IMPEXP_KERNEL int is_vnode_removed(nspace_id nsid, vnode_id vnid);
|
||||
|
||||
|
||||
extern _EXPORT vnode_ops fs_entry;
|
||||
extern _EXPORT int32 api_version;
|
||||
|
||||
#endif
|
961
src/tests/add-ons/kernel/file_systems/iso9660/r5/iso.c
Normal file
961
src/tests/add-ons/kernel/file_systems/iso9660/r5/iso.c
Normal 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 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;
|
||||
}
|
||||
|
230
src/tests/add-ons/kernel/file_systems/iso9660/r5/iso.h
Normal file
230
src/tests/add-ons/kernel/file_systems/iso9660/r5/iso.h
Normal 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
|
@ -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 <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"
|
||||
|
||||
#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;
|
||||
}
|
32
src/tests/add-ons/kernel/file_systems/iso9660/r5/lock.h
Normal file
32
src/tests/add-ons/kernel/file_systems/iso9660/r5/lock.h
Normal 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
|
32
src/tests/add-ons/kernel/file_systems/iso9660/r5/rock.h
Normal file
32
src/tests/add-ons/kernel/file_systems/iso9660/r5/rock.h
Normal 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;
|
Loading…
x
Reference in New Issue
Block a user