Added the multisession capable ISO-9660 file system based on Be's sample code.
Cleaned up the sources to match our coding style better. Partially removed fs API documentation (since it really doesn't belong here). Added to the build. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2960 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
bfa7190f02
commit
faa9239d5b
@ -1,3 +1,4 @@
|
||||
SubDir OBOS_TOP src add-ons kernel file_systems ;
|
||||
|
||||
SubInclude OBOS_TOP src add-ons kernel file_systems bfs ;
|
||||
SubInclude OBOS_TOP src add-ons kernel file_systems iso9660 ;
|
||||
|
45
src/add-ons/kernel/file_systems/iso9660/Jamfile
Normal file
45
src/add-ons/kernel/file_systems/iso9660/Jamfile
Normal file
@ -0,0 +1,45 @@
|
||||
SubDir OBOS_TOP src add-ons kernel file_systems iso9660 ;
|
||||
|
||||
# save original optimization level
|
||||
oldOPTIM = $(OPTIM) ;
|
||||
|
||||
# set some additional defines (most of them are currently unused in the iso9660 add-on)
|
||||
{
|
||||
local defines =
|
||||
KEEP_WRONG_DIRENT_RECLEN
|
||||
;
|
||||
|
||||
if $(COMPILE_FOR_R5) {
|
||||
defines += COMPILE_FOR_R5 ;
|
||||
}
|
||||
|
||||
if $(DEBUG) {
|
||||
defines += DEBUG ;
|
||||
} else {
|
||||
# the gcc on BeOS doesn't compile BFS correctly with -O2 or more
|
||||
OPTIM = -O1 ;
|
||||
}
|
||||
|
||||
defines = [ FDefines $(defines) ] ;
|
||||
SubDirCcFlags $(defines) -Wall -Wno-multichar ;
|
||||
}
|
||||
|
||||
R5KernelAddon iso9660 : [ FDirName kernel file_systems iso9660 ] :
|
||||
iso.c
|
||||
kernel_interface.c
|
||||
;
|
||||
|
||||
rule InstallISO9660
|
||||
{
|
||||
Depends $(<) : $(>) ;
|
||||
}
|
||||
|
||||
actions ignore InstallISO9660
|
||||
{
|
||||
cp $(>) /boot/home/config/add-ons/kernel/file_systems/
|
||||
}
|
||||
|
||||
InstallISO9660 install : iso9660 ;
|
||||
|
||||
# restore original optimization level
|
||||
OPTIM = $(oldOPTIM) ;
|
31
src/add-ons/kernel/file_systems/iso9660/LICENSE
Normal file
31
src/add-ons/kernel/file_systems/iso9660/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/add-ons/kernel/file_systems/iso9660/cache.h
Normal file
103
src/add-ons/kernel/file_systems/iso9660/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_ */
|
241
src/add-ons/kernel/file_systems/iso9660/fsproto.h
Normal file
241
src/add-ons/kernel/file_systems/iso9660/fsproto.h
Normal file
@ -0,0 +1,241 @@
|
||||
#ifndef _FSPROTO_H
|
||||
#define _FSPROTO_H
|
||||
|
||||
#include <sys/dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <iovec.h>
|
||||
|
||||
#include <OS.h>
|
||||
#include <fs_attr.h>
|
||||
#include <fs_info.h>
|
||||
#include <BeBuild.h>
|
||||
#include <Drivers.h>
|
||||
|
||||
typedef dev_t nspace_id;
|
||||
typedef ino_t vnode_id;
|
||||
|
||||
/*
|
||||
* PUBLIC PART OF THE FILE SYSTEM PROTOCOL
|
||||
*/
|
||||
|
||||
#define WSTAT_MODE 0x0001
|
||||
#define WSTAT_UID 0x0002
|
||||
#define WSTAT_GID 0x0004
|
||||
#define WSTAT_SIZE 0x0008
|
||||
#define WSTAT_ATIME 0x0010
|
||||
#define WSTAT_MTIME 0x0020
|
||||
#define WSTAT_CRTIME 0x0040
|
||||
|
||||
#define WFSSTAT_NAME 0x0001
|
||||
|
||||
#define B_ENTRY_CREATED 1
|
||||
#define B_ENTRY_REMOVED 2
|
||||
#define B_ENTRY_MOVED 3
|
||||
#define B_STAT_CHANGED 4
|
||||
#define B_ATTR_CHANGED 5
|
||||
#define B_DEVICE_MOUNTED 6
|
||||
#define B_DEVICE_UNMOUNTED 7
|
||||
|
||||
#define B_STOP_WATCHING 0x0000
|
||||
#define B_WATCH_NAME 0x0001
|
||||
#define B_WATCH_STAT 0x0002
|
||||
#define B_WATCH_ATTR 0x0004
|
||||
#define B_WATCH_DIRECTORY 0x0008
|
||||
|
||||
#define SELECT_READ 1
|
||||
#define SELECT_WRITE 2
|
||||
#define SELECT_EXCEPTION 3
|
||||
|
||||
#define B_CUR_FS_API_VERSION 2
|
||||
|
||||
struct attr_info;
|
||||
struct index_info;
|
||||
|
||||
typedef int op_read_vnode(void *ns, vnode_id vnid, char r, void **node);
|
||||
typedef int op_write_vnode(void *ns, void *node, char r);
|
||||
typedef int op_remove_vnode(void *ns, void *node, char r);
|
||||
typedef int op_secure_vnode(void *ns, void *node);
|
||||
|
||||
typedef int op_walk(void *ns, void *base, const char *file, char **newpath,
|
||||
vnode_id *vnid);
|
||||
|
||||
typedef int op_access(void *ns, void *node, int mode);
|
||||
|
||||
typedef int op_create(void *ns, void *dir, const char *name,
|
||||
int omode, int perms, vnode_id *vnid, void **cookie);
|
||||
typedef int op_mkdir(void *ns, void *dir, const char *name, int perms);
|
||||
typedef int op_symlink(void *ns, void *dir, const char *name,
|
||||
const char *path);
|
||||
typedef int op_link(void *ns, void *dir, const char *name, void *node);
|
||||
|
||||
typedef int op_rename(void *ns, void *olddir, const char *oldname,
|
||||
void *newdir, const char *newname);
|
||||
typedef int op_unlink(void *ns, void *dir, const char *name);
|
||||
typedef int op_rmdir(void *ns, void *dir, const char *name);
|
||||
|
||||
typedef int op_readlink(void *ns, void *node, char *buf, size_t *bufsize);
|
||||
|
||||
typedef int op_opendir(void *ns, void *node, void **cookie);
|
||||
typedef int op_closedir(void *ns, void *node, void *cookie);
|
||||
typedef int op_rewinddir(void *ns, void *node, void *cookie);
|
||||
typedef int op_readdir(void *ns, void *node, void *cookie, long *num,
|
||||
struct dirent *buf, size_t bufsize);
|
||||
|
||||
typedef int op_open(void *ns, void *node, int omode, void **cookie);
|
||||
typedef int op_close(void *ns, void *node, void *cookie);
|
||||
typedef int op_free_cookie(void *ns, void *node, void *cookie);
|
||||
typedef int op_read(void *ns, void *node, void *cookie, off_t pos, void *buf,
|
||||
size_t *len);
|
||||
typedef int op_write(void *ns, void *node, void *cookie, off_t pos,
|
||||
const void *buf, size_t *len);
|
||||
typedef int op_readv(void *ns, void *node, void *cookie, off_t pos, const iovec *vec,
|
||||
size_t count, size_t *len);
|
||||
typedef int op_writev(void *ns, void *node, void *cookie, off_t pos, const iovec *vec,
|
||||
size_t count, size_t *len);
|
||||
typedef int op_ioctl(void *ns, void *node, void *cookie, int cmd, void *buf,
|
||||
size_t len);
|
||||
typedef int op_setflags(void *ns, void *node, void *cookie, int flags);
|
||||
|
||||
typedef int op_rstat(void *ns, void *node, struct stat *);
|
||||
typedef int op_wstat(void *ns, void *node, struct stat *, long mask);
|
||||
typedef int op_fsync(void *ns, void *node);
|
||||
|
||||
typedef int op_select(void *ns, void *node, void *cookie, uint8 event,
|
||||
uint32 ref, selectsync *sync);
|
||||
typedef int op_deselect(void *ns, void *node, void *cookie, uint8 event,
|
||||
selectsync *sync);
|
||||
|
||||
typedef int op_initialize(const char *devname, void *parms, size_t len);
|
||||
typedef int op_mount(nspace_id nsid, const char *devname, ulong flags,
|
||||
void *parms, size_t len, void **data, vnode_id *vnid);
|
||||
typedef int op_unmount(void *ns);
|
||||
typedef int op_sync(void *ns);
|
||||
typedef int op_rfsstat(void *ns, struct fs_info *);
|
||||
typedef int op_wfsstat(void *ns, struct fs_info *, long mask);
|
||||
|
||||
|
||||
typedef int op_open_attrdir(void *ns, void *node, void **cookie);
|
||||
typedef int op_close_attrdir(void *ns, void *node, void *cookie);
|
||||
typedef int op_rewind_attrdir(void *ns, void *node, void *cookie);
|
||||
typedef int op_read_attrdir(void *ns, void *node, void *cookie, long *num,
|
||||
struct dirent *buf, size_t bufsize);
|
||||
typedef int op_remove_attr(void *ns, void *node, const char *name);
|
||||
typedef int op_rename_attr(void *ns, void *node, const char *oldname,
|
||||
const char *newname);
|
||||
typedef int op_stat_attr(void *ns, void *node, const char *name,
|
||||
struct attr_info *buf);
|
||||
|
||||
typedef int op_write_attr(void *ns, void *node, const char *name, int type,
|
||||
const void *buf, size_t *len, off_t pos);
|
||||
typedef int op_read_attr(void *ns, void *node, const char *name, int type,
|
||||
void *buf, size_t *len, off_t pos);
|
||||
|
||||
typedef int op_open_indexdir(void *ns, void **cookie);
|
||||
typedef int op_close_indexdir(void *ns, void *cookie);
|
||||
typedef int op_rewind_indexdir(void *ns, void *cookie);
|
||||
typedef int op_read_indexdir(void *ns, void *cookie, long *num,
|
||||
struct dirent *buf, size_t bufsize);
|
||||
typedef int op_create_index(void *ns, const char *name, int type, int flags);
|
||||
typedef int op_remove_index(void *ns, const char *name);
|
||||
typedef int op_rename_index(void *ns, const char *oldname,
|
||||
const char *newname);
|
||||
typedef int op_stat_index(void *ns, const char *name, struct index_info *buf);
|
||||
|
||||
typedef int op_open_query(void *ns, const char *query, ulong flags,
|
||||
port_id port, long token, void **cookie);
|
||||
typedef int op_close_query(void *ns, void *cookie);
|
||||
typedef int op_read_query(void *ns, void *cookie, long *num,
|
||||
struct dirent *buf, size_t bufsize);
|
||||
|
||||
typedef struct vnode_ops {
|
||||
op_read_vnode (*read_vnode);
|
||||
op_write_vnode (*write_vnode);
|
||||
op_remove_vnode (*remove_vnode);
|
||||
op_secure_vnode (*secure_vnode);
|
||||
op_walk (*walk);
|
||||
op_access (*access);
|
||||
op_create (*create);
|
||||
op_mkdir (*mkdir);
|
||||
op_symlink (*symlink);
|
||||
op_link (*link);
|
||||
op_rename (*rename);
|
||||
op_unlink (*unlink);
|
||||
op_rmdir (*rmdir);
|
||||
op_readlink (*readlink);
|
||||
op_opendir (*opendir);
|
||||
op_closedir (*closedir);
|
||||
op_free_cookie (*free_dircookie);
|
||||
op_rewinddir (*rewinddir);
|
||||
op_readdir (*readdir);
|
||||
op_open (*open);
|
||||
op_close (*close);
|
||||
op_free_cookie (*free_cookie);
|
||||
op_read (*read);
|
||||
op_write (*write);
|
||||
op_readv (*readv);
|
||||
op_writev (*writev);
|
||||
op_ioctl (*ioctl);
|
||||
op_setflags (*setflags);
|
||||
op_rstat (*rstat);
|
||||
op_wstat (*wstat);
|
||||
op_fsync (*fsync);
|
||||
op_initialize (*initialize);
|
||||
op_mount (*mount);
|
||||
op_unmount (*unmount);
|
||||
op_sync (*sync);
|
||||
op_rfsstat (*rfsstat);
|
||||
op_wfsstat (*wfsstat);
|
||||
op_select (*select);
|
||||
op_deselect (*deselect);
|
||||
op_open_indexdir (*open_indexdir);
|
||||
op_close_indexdir (*close_indexdir);
|
||||
op_free_cookie (*free_indexdircookie);
|
||||
op_rewind_indexdir (*rewind_indexdir);
|
||||
op_read_indexdir (*read_indexdir);
|
||||
op_create_index (*create_index);
|
||||
op_remove_index (*remove_index);
|
||||
op_rename_index (*rename_index);
|
||||
op_stat_index (*stat_index);
|
||||
op_open_attrdir (*open_attrdir);
|
||||
op_close_attrdir (*close_attrdir);
|
||||
op_free_cookie (*free_attrdircookie);
|
||||
op_rewind_attrdir (*rewind_attrdir);
|
||||
op_read_attrdir (*read_attrdir);
|
||||
op_write_attr (*write_attr);
|
||||
op_read_attr (*read_attr);
|
||||
op_remove_attr (*remove_attr);
|
||||
op_rename_attr (*rename_attr);
|
||||
op_stat_attr (*stat_attr);
|
||||
op_open_query (*open_query);
|
||||
op_close_query (*close_query);
|
||||
op_free_cookie (*free_querycookie);
|
||||
op_read_query (*read_query);
|
||||
} vnode_ops;
|
||||
|
||||
extern _IMPEXP_KERNEL int new_path(const char *path, char **copy);
|
||||
extern _IMPEXP_KERNEL void free_path(char *p);
|
||||
|
||||
extern _IMPEXP_KERNEL int notify_listener(int op, nspace_id nsid,
|
||||
vnode_id vnida, vnode_id vnidb,
|
||||
vnode_id vnidc, const char *name);
|
||||
extern _IMPEXP_KERNEL void notify_select_event(selectsync *sync, uint32 ref);
|
||||
extern _IMPEXP_KERNEL int send_notification(port_id port, long token,
|
||||
ulong what, long op, nspace_id nsida,
|
||||
nspace_id nsidb, vnode_id vnida,
|
||||
vnode_id vnidb, vnode_id vnidc,
|
||||
const char *name);
|
||||
extern _IMPEXP_KERNEL int get_vnode(nspace_id nsid, vnode_id vnid, void **data);
|
||||
extern _IMPEXP_KERNEL int put_vnode(nspace_id nsid, vnode_id vnid);
|
||||
extern _IMPEXP_KERNEL int new_vnode(nspace_id nsid, vnode_id vnid, void *data);
|
||||
extern _IMPEXP_KERNEL int remove_vnode(nspace_id nsid, vnode_id vnid);
|
||||
extern _IMPEXP_KERNEL int unremove_vnode(nspace_id nsid, vnode_id vnid);
|
||||
extern _IMPEXP_KERNEL int is_vnode_removed(nspace_id nsid, vnode_id vnid);
|
||||
|
||||
|
||||
extern _EXPORT vnode_ops fs_entry;
|
||||
extern _EXPORT int32 api_version;
|
||||
|
||||
#endif
|
961
src/add-ons/kernel/file_systems/iso9660/iso.c
Normal file
961
src/add-ons/kernel/file_systems/iso9660/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 1
|
||||
#if TRACE_ISO9660
|
||||
# define TRACE(x) dprintf x
|
||||
#else
|
||||
# define TRACE(x) ;
|
||||
#endif
|
||||
|
||||
|
||||
// Just needed here
|
||||
static status_t unicode_to_utf8(const char *src, int32 *srcLen, char *dst, int32 *dstLen);
|
||||
|
||||
|
||||
// Size of primary volume descriptor for ISO9660
|
||||
#define ISO_PVD_SIZE 882
|
||||
|
||||
// ISO9660 should start with this string
|
||||
const char *kISO9660IDString = "CD001";
|
||||
|
||||
#if 0
|
||||
static int GetLogicalBlockSize(int fd);
|
||||
static off_t GetNumDeviceBlocks(int fd, int block_size);
|
||||
#endif
|
||||
static int GetDeviceBlockSize(int fd);
|
||||
|
||||
static int InitVolDate(ISOVolDate *date, char *buf);
|
||||
static int InitRecDate(ISORecDate *date, char *buf);
|
||||
static int InitVolDesc(nspace *vol, char *buf);
|
||||
|
||||
#if 0 // currently unused
|
||||
static int
|
||||
GetLogicalBlockSize(int fd)
|
||||
{
|
||||
partition_info p_info;
|
||||
|
||||
if (ioctl(fd, B_GET_PARTITION_INFO, &p_info) == B_NO_ERROR) {
|
||||
TRACE(("GetLogicalBlockSize: ioctl suceed\n"));
|
||||
return p_info.logical_block_size;
|
||||
}
|
||||
TRACE(("GetLogicalBlockSize = ioctl returned error\n"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static off_t
|
||||
GetNumDeviceBlocks(int fd, int block_size)
|
||||
{
|
||||
struct stat st;
|
||||
device_geometry dg;
|
||||
|
||||
if (ioctl(fd, B_GET_GEOMETRY, &dg) >= 0) {
|
||||
return (off_t)dg.cylinder_count *
|
||||
(off_t)dg.sectors_per_track *
|
||||
(off_t)dg.head_count;
|
||||
}
|
||||
|
||||
/* if the ioctl fails, try just stat'ing in case it's a regular file */
|
||||
if (fstat(fd, &st) < 0)
|
||||
return 0;
|
||||
|
||||
return st.st_size / block_size;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int
|
||||
GetDeviceBlockSize(int fd)
|
||||
{
|
||||
struct stat st;
|
||||
device_geometry dg;
|
||||
|
||||
if (ioctl(fd, B_GET_GEOMETRY, &dg) < 0) {
|
||||
if (fstat(fd, &st) < 0 || S_ISDIR(st.st_mode))
|
||||
return 0;
|
||||
|
||||
return 512; /* just assume it's a plain old file or something */
|
||||
}
|
||||
|
||||
return dg.bytes_per_sector;
|
||||
}
|
||||
|
||||
|
||||
// From EncodingComversions.cpp
|
||||
|
||||
// Pierre's (modified) Uber Macro
|
||||
|
||||
// NOTE: iso9660 seems to store the unicode text in big-endian form
|
||||
#define u_to_utf8(str, uni_str)\
|
||||
{\
|
||||
if ((B_BENDIAN_TO_HOST_INT16(uni_str[0])&0xff80) == 0)\
|
||||
*str++ = B_BENDIAN_TO_HOST_INT16(*uni_str++);\
|
||||
else if ((B_BENDIAN_TO_HOST_INT16(uni_str[0])&0xf800) == 0) {\
|
||||
str[0] = 0xc0|(B_BENDIAN_TO_HOST_INT16(uni_str[0])>>6);\
|
||||
str[1] = 0x80|(B_BENDIAN_TO_HOST_INT16(*uni_str++)&0x3f);\
|
||||
str += 2;\
|
||||
} else if ((B_BENDIAN_TO_HOST_INT16(uni_str[0])&0xfc00) != 0xd800) {\
|
||||
str[0] = 0xe0|(B_BENDIAN_TO_HOST_INT16(uni_str[0])>>12);\
|
||||
str[1] = 0x80|((B_BENDIAN_TO_HOST_INT16(uni_str[0])>>6)&0x3f);\
|
||||
str[2] = 0x80|(B_BENDIAN_TO_HOST_INT16(*uni_str++)&0x3f);\
|
||||
str += 3;\
|
||||
} else {\
|
||||
int val;\
|
||||
val = ((B_BENDIAN_TO_HOST_INT16(uni_str[0])-0xd7c0)<<10) | (B_BENDIAN_TO_HOST_INT16(uni_str[1])&0x3ff);\
|
||||
str[0] = 0xf0 | (val>>18);\
|
||||
str[1] = 0x80 | ((val>>12)&0x3f);\
|
||||
str[2] = 0x80 | ((val>>6)&0x3f);\
|
||||
str[3] = 0x80 | (val&0x3f);\
|
||||
uni_str += 2; str += 4;\
|
||||
}\
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
unicode_to_utf8(const char *src, int32 *srcLen, char *dst, int32 *dstLen)
|
||||
{
|
||||
int32 srcLimit = *srcLen;
|
||||
int32 dstLimit = *dstLen;
|
||||
int32 srcCount = 0;
|
||||
int32 dstCount = 0;
|
||||
|
||||
for (srcCount = 0; srcCount < srcLimit; srcCount += 2) {
|
||||
uint16 *UNICODE = (uint16 *)&src[srcCount];
|
||||
uchar utf8[4];
|
||||
uchar *UTF8 = utf8;
|
||||
int32 utf8Len;
|
||||
int32 j;
|
||||
|
||||
u_to_utf8(UTF8, UNICODE);
|
||||
|
||||
utf8Len = UTF8 - utf8;
|
||||
if ((dstCount + utf8Len) > dstLimit)
|
||||
break;
|
||||
|
||||
for (j = 0; j < utf8Len; j++)
|
||||
dst[dstCount + j] = utf8[j];
|
||||
dstCount += utf8Len;
|
||||
}
|
||||
|
||||
*srcLen = srcCount;
|
||||
*dstLen = dstCount;
|
||||
|
||||
return ((dstCount > 0) ? B_NO_ERROR : B_ERROR);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// Functions specific to iso driver.
|
||||
|
||||
|
||||
int
|
||||
ISOMount(const char *path, const int flags, nspace **newVol, bool allow_joliet)
|
||||
{
|
||||
// path: path to device (eg, /dev/disk/scsi/030/raw)
|
||||
// partition: partition number on device ????
|
||||
// flags: currently unused
|
||||
|
||||
// determine if it is an ISO volume.
|
||||
char buffer[ISO_PVD_SIZE];
|
||||
bool done = false;
|
||||
bool is_iso = false;
|
||||
off_t offset = 0x8000;
|
||||
ssize_t retval;
|
||||
partition_info partitionInfo;
|
||||
int deviceBlockSize, multiplier;
|
||||
nspace *vol;
|
||||
int result = B_NO_ERROR;
|
||||
|
||||
(void)flags;
|
||||
|
||||
TRACE(("ISOMount - ENTER\n"));
|
||||
|
||||
vol = (nspace *)calloc(sizeof(nspace), 1);
|
||||
if (vol == NULL) {
|
||||
TRACE(("ISOMount - mem error \n"));
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
memset(&partitionInfo,0,sizeof(partition_info));
|
||||
|
||||
/* open and lock the device */
|
||||
vol->fdOfSession = open(path, O_RDONLY);
|
||||
|
||||
/* try to open the raw device to get access to the other sessions as well */
|
||||
if (vol->fdOfSession >= 0) {
|
||||
if (ioctl(vol->fdOfSession,B_GET_PARTITION_INFO,&partitionInfo) < B_NO_ERROR) {
|
||||
TRACE(("B_GET_PARTITION_INFO: ioctl returned error\n"));
|
||||
strcpy(partitionInfo.device,path);
|
||||
}
|
||||
TRACE(("ISOMount: open device/file \"%s\"\n",partitionInfo.device));
|
||||
|
||||
vol->fd = open(partitionInfo.device,O_RDONLY);
|
||||
}
|
||||
|
||||
if (vol->fdOfSession < 0 || vol->fd < 0) {
|
||||
close(vol->fd);
|
||||
close(vol->fdOfSession);
|
||||
|
||||
TRACE(("ISO9660 ERROR - Unable to open <%s>\n", path));
|
||||
free(vol);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
deviceBlockSize = GetDeviceBlockSize(vol->fdOfSession);
|
||||
if (deviceBlockSize < 0) {
|
||||
TRACE(("ISO9660 ERROR - device block size is 0\n"));
|
||||
close(vol->fd);
|
||||
close(vol->fdOfSession);
|
||||
|
||||
free(vol);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
vol->joliet_level = 0;
|
||||
while ((!done) && (offset < 0x10000)) {
|
||||
retval = read_pos (vol->fdOfSession, offset, (void *)buffer, ISO_PVD_SIZE);
|
||||
if (retval < ISO_PVD_SIZE) {
|
||||
is_iso = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strncmp(buffer + 1, kISO9660IDString, 5) == 0) {
|
||||
if ((*buffer == 0x01) && (!is_iso)) {
|
||||
// ISO_VD_PRIMARY
|
||||
|
||||
off_t maxBlocks;
|
||||
|
||||
TRACE(("ISOMount: Is an ISO9660 volume, initting rec\n"));
|
||||
|
||||
InitVolDesc(vol, buffer);
|
||||
strncpy(vol->devicePath,path,127);
|
||||
vol->id = ISO_ROOTNODE_ID;
|
||||
TRACE(("ISO9660: vol->blockSize = %d\n", vol->logicalBlkSize[FS_DATA_FORMAT]));
|
||||
|
||||
multiplier = deviceBlockSize / vol->logicalBlkSize[FS_DATA_FORMAT];
|
||||
TRACE(("ISOMount: block size multiplier is %d\n", multiplier));
|
||||
|
||||
// if the session is on a real device, size != 0
|
||||
if (partitionInfo.size != 0)
|
||||
maxBlocks = (partitionInfo.size+partitionInfo.offset) / vol->logicalBlkSize[FS_DATA_FORMAT];
|
||||
else
|
||||
maxBlocks = vol->volSpaceSize[FS_DATA_FORMAT];
|
||||
|
||||
/* Initialize access to the cache so that we can do cached i/o */
|
||||
TRACE(("ISO9660: cache init: dev %d, max blocks %Ld\n", vol->fd, maxBlocks));
|
||||
init_cache_for_device(vol->fd,maxBlocks);
|
||||
is_iso = true;
|
||||
} else if ((*buffer == 0x02) && is_iso && allow_joliet) {
|
||||
// ISO_VD_SUPPLEMENTARY
|
||||
|
||||
// JOLIET extension
|
||||
// test escape sequence for level of UCS-2 characterset
|
||||
if (buffer[88] == 0x25 && buffer[89] == 0x2f) {
|
||||
switch (buffer[90]) {
|
||||
case 0x40: vol->joliet_level = 1; break;
|
||||
case 0x43: vol->joliet_level = 2; break;
|
||||
case 0x45: vol->joliet_level = 3; break;
|
||||
}
|
||||
|
||||
TRACE(("ISO9660 Extensions: Microsoft Joliet Level %d\n", vol->joliet_level));
|
||||
|
||||
// Because Joliet-stuff starts at other sector,
|
||||
// update root directory record.
|
||||
if (vol->joliet_level > 0)
|
||||
InitNode(&(vol->rootDirRec), &buffer[156], NULL, 0);
|
||||
|
||||
}
|
||||
} else if (*(unsigned char *)buffer == 0xff) {
|
||||
// ISO_VD_END
|
||||
done = true;
|
||||
} else
|
||||
TRACE(("found header %d\n",*buffer));
|
||||
}
|
||||
offset += 0x800;
|
||||
}
|
||||
|
||||
if (!is_iso) {
|
||||
// It isn't an ISO disk.
|
||||
if (vol->fdOfSession >= 0)
|
||||
close(vol->fdOfSession);
|
||||
if (vol->fd >= 0)
|
||||
close(vol->fd);
|
||||
|
||||
free(vol);
|
||||
vol = NULL;
|
||||
result = EINVAL;
|
||||
TRACE(("ISOMount: Not an ISO9660 volume!\n"));
|
||||
}
|
||||
|
||||
TRACE(("ISOMount - EXIT, result %s, returning %p\n", strerror(result), vol));
|
||||
*newVol = vol;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/** Reads in a single directory entry and fills in the values in the
|
||||
* dirent struct. Uses the cookie to keep track of the current block
|
||||
* and position within the block. Also uses the cookie to determine when
|
||||
* it has reached the end of the directory file.
|
||||
*
|
||||
* NOTE: If your file sytem seems to work ok from the command line, but
|
||||
* the tracker doesn't seem to like it, check what you do here closely;
|
||||
* in particular, if the d_ino in the stat struct isn't correct, the tracker
|
||||
* will not display the entry.
|
||||
*/
|
||||
|
||||
int
|
||||
ISOReadDirEnt(nspace *ns, dircookie *cookie, struct dirent *dirent, size_t bufsize)
|
||||
{
|
||||
off_t totalRead = cookie->pos + ((cookie->block - cookie->startBlock) *
|
||||
ns->logicalBlkSize[FS_DATA_FORMAT]);
|
||||
off_t cacheBlock;
|
||||
char *blockData;
|
||||
int result = B_NO_ERROR;
|
||||
int bytesRead = 0;
|
||||
bool block_out = false;
|
||||
|
||||
TRACE(("ISOReadDirEnt - ENTER\n"));
|
||||
|
||||
// If we're at the end of the data in a block, move to the next block.
|
||||
while (1) {
|
||||
blockData = (char *)get_block(ns->fd, cookie->block,
|
||||
ns->logicalBlkSize[FS_DATA_FORMAT]);
|
||||
block_out = true;
|
||||
|
||||
if (blockData != NULL && *(blockData + cookie->pos) == 0) {
|
||||
//NULL data, move to next block.
|
||||
release_block(ns->fd, cookie->block);
|
||||
block_out = false;
|
||||
totalRead += ns->logicalBlkSize[FS_DATA_FORMAT] - cookie->pos;
|
||||
cookie->pos = 0;
|
||||
cookie->block++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
if (totalRead >= cookie->totalSize)
|
||||
break;
|
||||
}
|
||||
|
||||
cacheBlock = cookie->block;
|
||||
if (blockData != NULL && totalRead < cookie->totalSize) {
|
||||
vnode node;
|
||||
|
||||
if ((result = InitNode(&node, blockData + cookie->pos, &bytesRead, ns->joliet_level)) ==
|
||||
B_NO_ERROR)
|
||||
{
|
||||
int nameBufSize = (bufsize - (2 * sizeof(dev_t) + 2* sizeof(ino_t) +
|
||||
sizeof(unsigned short)));
|
||||
|
||||
dirent->d_ino = (cookie->block << 30) + (cookie->pos & 0xFFFFFFFF);
|
||||
dirent->d_reclen = node.fileIDLen;
|
||||
|
||||
if (node.fileIDLen <= nameBufSize) {
|
||||
// need to do some size checking here.
|
||||
strncpy(dirent->d_name, node.fileIDString, node.fileIDLen +1);
|
||||
TRACE(("ISOReadDirEnt - success, name is %s\n", dirent->d_name));
|
||||
} else {
|
||||
TRACE(("ISOReadDirEnt - ERROR, name %s does not fit in buffer of size %d\n", node.fileIDString, nameBufSize));
|
||||
result = EINVAL;
|
||||
}
|
||||
cookie->pos += bytesRead;
|
||||
}
|
||||
} else {
|
||||
if (totalRead >= cookie->totalSize)
|
||||
result = ENOENT;
|
||||
else
|
||||
result = ENOMEM;
|
||||
}
|
||||
|
||||
if (block_out)
|
||||
release_block(ns->fd, cacheBlock);
|
||||
|
||||
TRACE(("ISOReadDirEnt - EXIT, result is %s, vnid is %Lu\n", strerror(result), dirent->d_ino));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
InitVolDesc(nspace *vol, char *buffer)
|
||||
{
|
||||
TRACE(("InitVolDesc - ENTER\n"));
|
||||
|
||||
vol->volDescType = *(uint8 *)buffer++;
|
||||
|
||||
vol->stdIDString[5] = '\0';
|
||||
strncpy(vol->stdIDString, buffer, 5);
|
||||
buffer += 5;
|
||||
|
||||
vol->volDescVersion = *(uint8 *)buffer;
|
||||
buffer += 2; // 8th byte unused
|
||||
|
||||
vol->systemIDString[32] = '\0';
|
||||
strncpy(vol->systemIDString, buffer, 32);
|
||||
buffer += 32;
|
||||
TRACE(("InitVolDesc - system id string is %s\n", vol->systemIDString));
|
||||
|
||||
vol->volIDString[32] = '\0';
|
||||
strncpy(vol->volIDString, buffer, 32);
|
||||
buffer += (32 + 80-73 + 1); // bytes 80-73 unused
|
||||
TRACE(("InitVolDesc - volume id string is %s\n", vol->volIDString));
|
||||
|
||||
vol->volSpaceSize[LSB_DATA] = *(uint32 *)buffer;
|
||||
buffer += 4;
|
||||
vol->volSpaceSize[MSB_DATA] = *(uint32 *)buffer;
|
||||
buffer+= (4 + 120-89 + 1); // bytes 120-89 unused
|
||||
|
||||
vol->volSetSize[LSB_DATA] = *(uint16*)buffer;
|
||||
buffer += 2;
|
||||
vol->volSetSize[MSB_DATA] = *(uint16*)buffer;
|
||||
buffer += 2;
|
||||
|
||||
vol->volSeqNum[LSB_DATA] = *(uint16*)buffer;
|
||||
buffer += 2;
|
||||
vol->volSeqNum[MSB_DATA] = *(uint16*)buffer;
|
||||
buffer += 2;
|
||||
|
||||
vol->logicalBlkSize[LSB_DATA] = *(uint16*)buffer;
|
||||
buffer += 2;
|
||||
vol->logicalBlkSize[MSB_DATA] = *(uint16*)buffer;
|
||||
buffer += 2;
|
||||
|
||||
vol->pathTblSize[LSB_DATA] = *(uint32*)buffer;
|
||||
buffer += 4;
|
||||
vol->pathTblSize[MSB_DATA] = *(uint32*)buffer;
|
||||
buffer += 4;
|
||||
|
||||
vol->lPathTblLoc[LSB_DATA] = *(uint16*)buffer;
|
||||
buffer += 2;
|
||||
vol->lPathTblLoc[MSB_DATA] = *(uint16*)buffer;
|
||||
buffer += 2;
|
||||
|
||||
vol->optLPathTblLoc[LSB_DATA] = *(uint16*)buffer;
|
||||
buffer += 2;
|
||||
vol->optLPathTblLoc[MSB_DATA] = *(uint16*)buffer;
|
||||
buffer += 2;
|
||||
|
||||
vol->mPathTblLoc[LSB_DATA] = *(uint16*)buffer;
|
||||
buffer += 2;
|
||||
vol->mPathTblLoc[MSB_DATA] = *(uint16*)buffer;
|
||||
buffer += 2;
|
||||
|
||||
vol->optMPathTblLoc[LSB_DATA] = *(uint16*)buffer;
|
||||
buffer += 2;
|
||||
vol->optMPathTblLoc[MSB_DATA] = *(uint16*)buffer;
|
||||
buffer += 2;
|
||||
|
||||
// Fill in directory record.
|
||||
InitNode(&(vol->rootDirRec), buffer, NULL, 0);
|
||||
|
||||
vol->rootDirRec.id = ISO_ROOTNODE_ID;
|
||||
buffer += 34;
|
||||
|
||||
vol->volSetIDString[128] = '\0';
|
||||
strncpy(vol->volSetIDString, buffer, 128);
|
||||
buffer += 128;
|
||||
TRACE(("InitVolDesc - volume set id string is %s\n", vol->volSetIDString));
|
||||
|
||||
vol->pubIDString[128] = '\0';
|
||||
strncpy(vol->pubIDString, buffer, 128);
|
||||
buffer += 128;
|
||||
TRACE(("InitVolDesc - volume pub id string is %s\n", vol->pubIDString));
|
||||
|
||||
vol->dataPreparer[128] = '\0';
|
||||
strncpy(vol->dataPreparer, buffer, 128);
|
||||
buffer += 128;
|
||||
TRACE(("InitVolDesc - volume dataPreparer string is %s\n", vol->dataPreparer));
|
||||
|
||||
vol->appIDString[128] = '\0';
|
||||
strncpy(vol->appIDString, buffer, 128);
|
||||
buffer += 128;
|
||||
TRACE(("InitVolDesc - volume app id string is %s\n", vol->appIDString));
|
||||
|
||||
vol->copyright[38] = '\0';
|
||||
strncpy(vol->copyright, buffer, 38);
|
||||
buffer += 38;
|
||||
TRACE(("InitVolDesc - copyright is %s\n", vol->copyright));
|
||||
|
||||
vol->abstractFName[38] = '\0';
|
||||
strncpy(vol->abstractFName, buffer, 38);
|
||||
buffer += 38;
|
||||
|
||||
vol->biblioFName[38] = '\0';
|
||||
strncpy(vol->biblioFName, buffer, 38);
|
||||
buffer += 38;
|
||||
|
||||
InitVolDate(&(vol->createDate), buffer);
|
||||
buffer += 17;
|
||||
|
||||
InitVolDate(&(vol->modDate), buffer);
|
||||
buffer += 17;
|
||||
|
||||
InitVolDate(&(vol->expireDate), buffer);
|
||||
buffer += 17;
|
||||
|
||||
InitVolDate(&(vol->effectiveDate), buffer);
|
||||
buffer += 17;
|
||||
|
||||
vol->fileStructVers = *(uint8 *)buffer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
InitNode(vnode *rec, char *buffer, int *_bytesRead, uint8 joliet_level)
|
||||
{
|
||||
int result = B_NO_ERROR;
|
||||
uint8 recLen = *(uint8 *)buffer++;
|
||||
bool no_rock_ridge_stat_struct = TRUE;
|
||||
|
||||
if (_bytesRead != NULL)
|
||||
*_bytesRead = recLen;
|
||||
|
||||
TRACE(("InitNode - ENTER, bufstart is %p, record length is %d bytes\n", buffer, recLen));
|
||||
|
||||
if (recLen > 0) {
|
||||
rec->extAttrRecLen = *(uint8 *)buffer++;
|
||||
|
||||
rec->startLBN[LSB_DATA] = *(uint32 *)buffer;
|
||||
buffer += 4;
|
||||
rec->startLBN[MSB_DATA] = *(uint32 *)buffer;
|
||||
buffer += 4;
|
||||
TRACE(("InitNode - data start LBN is %ld\n", rec->startLBN[FS_DATA_FORMAT]));
|
||||
|
||||
rec->dataLen[LSB_DATA] = *(uint32 *)buffer;
|
||||
buffer += 4;
|
||||
rec->dataLen[MSB_DATA] = *(uint32 *)buffer;
|
||||
buffer += 4;
|
||||
TRACE(("InitNode - data length is %ld\n", rec->dataLen[FS_DATA_FORMAT]));
|
||||
|
||||
InitRecDate(&(rec->recordDate), buffer);
|
||||
buffer += 7;
|
||||
|
||||
rec->flags = *(uint8 *)buffer;
|
||||
buffer++;
|
||||
TRACE(("InitNode - flags are %d\n", rec->flags));
|
||||
|
||||
rec->fileUnitSize = *(uint8 *)buffer;
|
||||
buffer++;
|
||||
TRACE(("InitNode - fileUnitSize is %d\n", rec->fileUnitSize));
|
||||
|
||||
rec->interleaveGapSize = *(uint8 *)buffer;
|
||||
buffer++;
|
||||
TRACE(("InitNode - interleave gap size = %d\n", rec->interleaveGapSize));
|
||||
|
||||
rec->volSeqNum = *(uint32 *)buffer;
|
||||
buffer += 4;
|
||||
TRACE(("InitNode - volume seq num is %ld\n", rec->volSeqNum));
|
||||
|
||||
rec->fileIDLen = *(uint8*)buffer;
|
||||
buffer++;
|
||||
TRACE(("InitNode - file id length is %d\n", rec->fileIDLen));
|
||||
|
||||
if (rec->fileIDLen > 0) {
|
||||
// JOLIET extension:
|
||||
// on joliet discs, buffer[0] can be 0 for Unicoded filenames,
|
||||
// so I've added a check here to test explicitely for
|
||||
// directories (which have length 1)
|
||||
if (rec->fileIDLen == 1) {
|
||||
// Take care of "." and "..", the first two dirents are
|
||||
// these in iso.
|
||||
if (buffer[0] == 0) {
|
||||
rec->fileIDString = strdup(".");
|
||||
rec->fileIDLen = 1;
|
||||
} else if (buffer[0] == 1) {
|
||||
rec->fileIDString = strdup("..");
|
||||
rec->fileIDLen = 2;
|
||||
}
|
||||
} else {
|
||||
// JOLIET extension:
|
||||
// convert Unicode16 string to UTF8
|
||||
if (joliet_level > 0) {
|
||||
// Assume that the unicode->utf8 conversion produces 4 byte
|
||||
// utf8 characters, and allocate that much space
|
||||
rec->fileIDString = (char *)malloc(rec->fileIDLen * 2 + 1);
|
||||
if (rec->fileIDString != NULL) {
|
||||
status_t err;
|
||||
int32 srcLen = rec->fileIDLen;
|
||||
int32 dstLen = rec->fileIDLen * 2;
|
||||
|
||||
err = unicode_to_utf8(buffer, &srcLen, rec->fileIDString, &dstLen);
|
||||
if (err < B_NO_ERROR) {
|
||||
dprintf("iso9660: error converting unicode->utf8\n");
|
||||
result = err;
|
||||
} else {
|
||||
rec->fileIDString[dstLen] = '\0';
|
||||
rec->fileIDLen = dstLen;
|
||||
}
|
||||
} else {
|
||||
// Error
|
||||
result = ENOMEM;
|
||||
TRACE(("InitNode - unable to allocate memory!\n"));
|
||||
}
|
||||
} else {
|
||||
rec->fileIDString = (char *)malloc((rec->fileIDLen) + 1);
|
||||
|
||||
if (rec->fileIDString != NULL) {
|
||||
strncpy(rec->fileIDString, buffer, rec->fileIDLen);
|
||||
rec->fileIDString[rec->fileIDLen] = '\0';
|
||||
} else {
|
||||
// Error
|
||||
result = ENOMEM;
|
||||
TRACE(("InitNode - unable to allocate memory!\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get rid of semicolons, which are used to delineate file versions.q
|
||||
{
|
||||
char *semi = NULL;
|
||||
while ((semi = strchr(rec->fileIDString, ';')) != NULL)
|
||||
semi[0] = '\0';
|
||||
}
|
||||
TRACE(("DirRec ID String is: %s\n", rec->fileIDString));
|
||||
|
||||
if (result == B_NO_ERROR) {
|
||||
buffer += rec->fileIDLen;
|
||||
if (!(rec->fileIDLen % 2))
|
||||
buffer++;
|
||||
|
||||
// Now we're at the start of the rock ridge stuff
|
||||
{
|
||||
char *altName = NULL;
|
||||
char *slName = NULL;
|
||||
uint16 altNameSize = 0;
|
||||
uint16 slNameSize = 0;
|
||||
uint8 slFlags = 0;
|
||||
uint8 length = 0;
|
||||
bool done = FALSE;
|
||||
|
||||
TRACE(("RR: Start of extensions, but at %p\n", buffer));
|
||||
|
||||
memset(&(rec->attr.stat), 0, 2 * sizeof(struct stat));
|
||||
|
||||
// Set defaults, in case there is no RR stuff.
|
||||
rec->attr.stat[FS_DATA_FORMAT].st_mode = (S_IRUSR | S_IRGRP | S_IROTH);
|
||||
|
||||
while (!done)
|
||||
{
|
||||
buffer += length;
|
||||
length = *(uint8 *)(buffer + 2);
|
||||
switch (0x100 * buffer[0] + buffer[1])
|
||||
{
|
||||
// Stat structure stuff
|
||||
case 'PX':
|
||||
{
|
||||
uint8 bytePos = 3;
|
||||
TRACE(("RR: found PX, length %u\n", length));
|
||||
rec->attr.pxVer = *(uint8*)(buffer + bytePos++);
|
||||
no_rock_ridge_stat_struct = FALSE;
|
||||
|
||||
// st_mode
|
||||
rec->attr.stat[LSB_DATA].st_mode = *(mode_t*)(buffer + bytePos);
|
||||
bytePos += 4;
|
||||
rec->attr.stat[MSB_DATA].st_mode = *(mode_t*)(buffer + bytePos);
|
||||
bytePos += 4;
|
||||
|
||||
// st_nlink
|
||||
rec->attr.stat[LSB_DATA].st_nlink = *(nlink_t*)(buffer+bytePos);
|
||||
bytePos += 4;
|
||||
rec->attr.stat[MSB_DATA].st_nlink = *(nlink_t*)(buffer + bytePos);
|
||||
bytePos += 4;
|
||||
|
||||
// st_uid
|
||||
rec->attr.stat[LSB_DATA].st_uid = *(uid_t*)(buffer+bytePos);
|
||||
bytePos += 4;
|
||||
rec->attr.stat[MSB_DATA].st_uid = *(uid_t*)(buffer+bytePos);
|
||||
bytePos += 4;
|
||||
|
||||
// st_gid
|
||||
rec->attr.stat[LSB_DATA].st_gid = *(gid_t*)(buffer+bytePos);
|
||||
bytePos += 4;
|
||||
rec->attr.stat[MSB_DATA].st_gid = *(gid_t*)(buffer+bytePos);
|
||||
bytePos += 4;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'PN':
|
||||
TRACE(("RR: found PN, length %u\n", length));
|
||||
break;
|
||||
|
||||
// Symbolic link info
|
||||
case 'SL':
|
||||
{
|
||||
uint8 bytePos = 3;
|
||||
uint8 lastCompFlag = 0;
|
||||
uint8 addPos = 0;
|
||||
bool slDone = FALSE;
|
||||
bool useSeparator = TRUE;
|
||||
|
||||
TRACE(("RR: found SL, length %u\n", length));
|
||||
TRACE(("Buffer is at %p\n", buffer));
|
||||
TRACE(("Current length is %u\n", slNameSize));
|
||||
//kernel_debugger("");
|
||||
rec->attr.slVer = *(uint8*)(buffer + bytePos++);
|
||||
slFlags = *(uint8*)(buffer + bytePos++);
|
||||
|
||||
TRACE(("sl flags are %u\n", slFlags));
|
||||
while (!slDone && bytePos < length)
|
||||
{
|
||||
uint8 compFlag = *(uint8*)(buffer + bytePos++);
|
||||
uint8 compLen = *(uint8*)(buffer + bytePos++);
|
||||
|
||||
if (slName == NULL) useSeparator = FALSE;
|
||||
|
||||
addPos = slNameSize;
|
||||
|
||||
TRACE(("sl comp flags are %u, length is %u\n", compFlag, compLen));
|
||||
TRACE(("Current name size is %u\n", slNameSize));
|
||||
switch (compFlag)
|
||||
{
|
||||
case SLCP_CONTINUE:
|
||||
useSeparator = FALSE;
|
||||
default:
|
||||
// Add the component to the total path.
|
||||
slNameSize += compLen;
|
||||
if ( useSeparator ) slNameSize++;
|
||||
if (slName == NULL)
|
||||
slName = (char*)malloc(slNameSize + 1);
|
||||
else
|
||||
slName = (char*)realloc(slName, slNameSize + 1);
|
||||
|
||||
if (useSeparator)
|
||||
{
|
||||
TRACE(("Adding separator\n"));
|
||||
slName[addPos++] = '/';
|
||||
}
|
||||
|
||||
TRACE(("doing memcopy of %u bytes at offset %d\n", compLen, addPos));
|
||||
memcpy((slName + addPos), (buffer + bytePos), compLen);
|
||||
|
||||
addPos += compLen;
|
||||
useSeparator = TRUE;
|
||||
break;
|
||||
|
||||
case SLCP_CURRENT:
|
||||
TRACE(("InitNode - found link to current directory\n"));
|
||||
slNameSize += 2;
|
||||
if (slName == NULL)
|
||||
slName = (char*)malloc(slNameSize + 1);
|
||||
else
|
||||
slName = (char*)realloc(slName, slNameSize + 1);
|
||||
memcpy(slName + addPos, "./", 2);
|
||||
useSeparator = FALSE;
|
||||
break;
|
||||
|
||||
case SLCP_PARENT:
|
||||
slNameSize += 3;
|
||||
if (slName == NULL)
|
||||
slName = (char*)malloc(slNameSize + 1);
|
||||
else
|
||||
slName = (char*)realloc(slName, slNameSize + 1);
|
||||
memcpy(slName + addPos, "../", 3);
|
||||
useSeparator = FALSE;
|
||||
break;
|
||||
|
||||
case SLCP_ROOT:
|
||||
TRACE(("InitNode - found link to root directory\n"));
|
||||
slNameSize += 1;
|
||||
if (slName == NULL)
|
||||
slName = (char*)malloc(slNameSize + 1);
|
||||
else
|
||||
slName = (char*)realloc(slName, slNameSize + 1);
|
||||
memcpy(slName + addPos, "/", 1);
|
||||
useSeparator = FALSE;
|
||||
break;
|
||||
|
||||
case SLCP_VOLROOT:
|
||||
slDone = TRUE;
|
||||
break;
|
||||
|
||||
case SLCP_HOST:
|
||||
slDone = TRUE;
|
||||
break;
|
||||
}
|
||||
slName[slNameSize] = '\0';
|
||||
lastCompFlag = compFlag;
|
||||
bytePos += compLen;
|
||||
TRACE(("Current sl name is \'%s\'\n", slName));
|
||||
}
|
||||
rec->attr.slName = slName;
|
||||
TRACE(("InitNode = symlink name is \'%s\'\n", slName));
|
||||
break;
|
||||
}
|
||||
|
||||
// Altername name
|
||||
case 'NM':
|
||||
{
|
||||
uint8 bytePos = 3;
|
||||
uint8 flags = 0;
|
||||
uint16 oldEnd = altNameSize;
|
||||
|
||||
altNameSize += length - 5;
|
||||
if (altName == NULL)
|
||||
altName = (char *)malloc(altNameSize + 1);
|
||||
else
|
||||
altName = (char *)realloc(altName, altNameSize + 1);
|
||||
|
||||
TRACE(("RR: found NM, length %u\n", length));
|
||||
// Read flag and version.
|
||||
rec->attr.nmVer = *(uint8 *)(buffer + bytePos++);
|
||||
flags = *(uint8 *)(buffer + bytePos++);
|
||||
|
||||
TRACE(("RR: nm buffer is %s, start at %p\n", (buffer + bytePos), buffer + bytePos));
|
||||
|
||||
// Build the file name.
|
||||
memcpy(altName + oldEnd, buffer + bytePos, length - 5);
|
||||
altName[altNameSize] = '\0';
|
||||
TRACE(("RR: alt name is %s\n", altName));
|
||||
|
||||
// If the name is not continued in another record, update
|
||||
// the record name.
|
||||
if (!(flags & NM_CONTINUE))
|
||||
{
|
||||
// Get rid of the ISO name, replace with RR name.
|
||||
if (rec->fileIDString != NULL)
|
||||
free(rec->fileIDString);
|
||||
rec->fileIDString = altName;
|
||||
rec->fileIDLen = altNameSize;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Deep directory record masquerading as a file.
|
||||
case 'CL':
|
||||
TRACE(("RR: found CL, length %u\n", length));
|
||||
rec->flags |= ISO_ISDIR;
|
||||
rec->startLBN[LSB_DATA] = *(uint32*)(buffer+4);
|
||||
rec->startLBN[MSB_DATA] = *(uint32*)(buffer+8);
|
||||
break;
|
||||
|
||||
case 'PL':
|
||||
TRACE(("RR: found PL, length %u\n", length));
|
||||
break;
|
||||
|
||||
// Relocated directory, we should skip.
|
||||
case 'RE':
|
||||
result = EINVAL;
|
||||
TRACE(("RR: found RE, length %u\n", length));
|
||||
break;
|
||||
|
||||
case 'TF':
|
||||
TRACE(("RR: found TF, length %u\n", length));
|
||||
break;
|
||||
|
||||
case 'RR':
|
||||
TRACE(("RR: found RR, length %u\n", length));
|
||||
break;
|
||||
|
||||
default:
|
||||
TRACE(("RR: %c%c (%d, %d)\n",buffer[0],buffer[1],buffer[0],buffer[1]));
|
||||
TRACE(("RR: End of extensions.\n"));
|
||||
done = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TRACE(("InitNode - File ID String is 0 length\n"));
|
||||
result = ENOENT;
|
||||
}
|
||||
} else
|
||||
result = ENOENT;
|
||||
|
||||
TRACE(("InitNode - EXIT, result is %s name is \'%s\'\n", strerror(result), rec->fileIDString));
|
||||
|
||||
if (no_rock_ridge_stat_struct) {
|
||||
if (rec->flags & ISO_ISDIR)
|
||||
rec->attr.stat[FS_DATA_FORMAT].st_mode |= (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH);
|
||||
else
|
||||
rec->attr.stat[FS_DATA_FORMAT].st_mode |= (S_IFREG);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
InitVolDate(ISOVolDate *date, char *buffer)
|
||||
{
|
||||
memcpy(date, buffer, 17);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
InitRecDate(ISORecDate *date, char *buffer)
|
||||
{
|
||||
memcpy(date, buffer, 7);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ConvertRecDate(ISORecDate* inDate, time_t* outDate)
|
||||
{
|
||||
time_t time;
|
||||
int days, i, year, tz;
|
||||
|
||||
year = inDate->year -70;
|
||||
tz = inDate->offsetGMT;
|
||||
|
||||
if (year < 0) {
|
||||
time = 0;
|
||||
} else {
|
||||
const int monlen[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
|
||||
days = (year * 365);
|
||||
|
||||
if (year > 2)
|
||||
days += (year + 1)/ 4;
|
||||
|
||||
for (i = 1; (i < inDate->month) && (i < 12); i++) {
|
||||
days += monlen[i-1];
|
||||
}
|
||||
|
||||
if (((year + 2) % 4) == 0 && inDate->month > 2)
|
||||
days++;
|
||||
|
||||
days += inDate->date - 1;
|
||||
time = ((((days*24) + inDate->hour) * 60 + inDate->minute) * 60)
|
||||
+ inDate->second;
|
||||
if (tz & 0x80)
|
||||
tz |= (-1 << 8);
|
||||
|
||||
if (-48 <= tz && tz <= 52)
|
||||
time += tz *15 * 60;
|
||||
}
|
||||
*outDate = time;
|
||||
return 0;
|
||||
}
|
||||
|
230
src/add-ons/kernel/file_systems/iso9660/iso.h
Normal file
230
src/add-ons/kernel/file_systems/iso9660/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
|
855
src/add-ons/kernel/file_systems/iso9660/kernel_interface.c
Normal file
855
src/add-ons/kernel/file_systems/iso9660/kernel_interface.c
Normal file
@ -0,0 +1,855 @@
|
||||
/*
|
||||
** Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
** This file may be used under the terms of the Be Sample Code License.
|
||||
**
|
||||
** Copyright 2001, pinc Software. All Rights Reserved.
|
||||
**
|
||||
** iso9960/multi-session, 1.0.0
|
||||
** 2001-03-11: added multi-session support, axeld.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <KernelExport.h>
|
||||
#include <time.h>
|
||||
#include <fsproto.h>
|
||||
#include <lock.h>
|
||||
#include <cache.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "iso.h"
|
||||
|
||||
|
||||
/* Start of fundamental (read-only) required functions */
|
||||
static int fs_mount(nspace_id nsid, const char *device, ulong flags,
|
||||
void *parms, size_t len, void **data, vnode_id *vnid);
|
||||
static int fs_unmount(void *_ns);
|
||||
|
||||
int fs_walk(void *_ns, void *_base, const char *file,
|
||||
char **newpath, vnode_id *vnid);
|
||||
|
||||
int fs_read_vnode(void *_ns, vnode_id vnid, char r, void **node);
|
||||
int fs_write_vnode(void *_ns, void *_node, char r);
|
||||
static int fs_read_stat(void *_ns, void *_node, struct stat *st);
|
||||
static int fs_open(void *_ns, void *_node, int omode, void **cookie);
|
||||
static int fs_read(void *_ns, void *_node, void *cookie, off_t pos,
|
||||
void *buf, size_t *len);
|
||||
/// fs_free_cookie - free cookie for file created in open.
|
||||
static int fs_free_cookie(void *ns, void *node, void *cookie);
|
||||
static int fs_close(void *ns, void *node, void *cookie);
|
||||
|
||||
// fs_access - checks permissions for access.
|
||||
static int fs_access(void *_ns, void *_node, int mode);
|
||||
|
||||
// fs_opendir - creates fs-specific "cookie" struct that can tell where
|
||||
// we are at in the directory list.
|
||||
static int fs_open_dir(void* _ns, void* _node, void** cookie);
|
||||
// fs_readdir - read 1 or more dirents, keep state in cookie, return
|
||||
// 0 when no more entries.
|
||||
static int fs_read_dir(void *_ns, void *_node, void *cookie,
|
||||
long *num, struct dirent *buf, size_t bufsize);
|
||||
// fs_rewinddir - set cookie to represent beginning of directory, so
|
||||
// later fs_readdir calls start at beginning.
|
||||
static int fs_rewind_dir(void *_ns, void *_node, void *cookie);
|
||||
// fs_closedir - Do whatever you need to to close a directory (sometimes
|
||||
// nothing), but DON'T free the cookie!
|
||||
static int fs_close_dir(void *_ns, void *_node, void *cookie);
|
||||
// fs_fee_dircookie - Free the fs-specific cookie struct
|
||||
static int fs_free_dir_cookie(void *_ns, void *_node, void *cookie);
|
||||
|
||||
// fs_rfsstat - Fill in fs_info struct for device.
|
||||
static int fs_read_fs_stat(void *_ns, struct fs_info *);
|
||||
|
||||
// fs_readlink - Read in the name of a symbolic link.
|
||||
static int fs_read_link(void *_ns, void *_node, char *buf, size_t *bufsize);
|
||||
|
||||
|
||||
|
||||
/* vnode_ops struct. Fill this in to tell the kernel how to call
|
||||
functions in your driver.
|
||||
*/
|
||||
|
||||
vnode_ops fs_entry = {
|
||||
&fs_read_vnode, // read_vnode func ptr
|
||||
&fs_write_vnode, // write_vnode func ptr
|
||||
NULL, // remove_vnode func ptr
|
||||
NULL, // secure_vnode func ptr
|
||||
&fs_walk, // walk func ptr
|
||||
&fs_access, // access func ptr
|
||||
NULL, // create func ptr
|
||||
NULL, // mkdir func ptr
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL, // unlink func ptr
|
||||
NULL, // rmdir func ptr
|
||||
&fs_read_link, // readlink func ptr
|
||||
&fs_open_dir, // opendir func ptr
|
||||
&fs_close_dir, // closedir func ptr
|
||||
&fs_free_dir_cookie, // free_dircookie func ptr
|
||||
&fs_rewind_dir, // rewinddir func ptr
|
||||
&fs_read_dir, // readdir func ptr
|
||||
&fs_open, // open file func ptr
|
||||
&fs_close, // close file func ptr
|
||||
&fs_free_cookie, // free cookie func ptr
|
||||
&fs_read, // read file func ptr
|
||||
NULL, // write file func ptr
|
||||
NULL, /* readv */
|
||||
NULL, /* writev */
|
||||
NULL, // ioctl func ptr
|
||||
NULL, // setflags file func ptr
|
||||
&fs_read_stat, // rstat func ptr
|
||||
NULL, // wstat func ptr
|
||||
NULL,
|
||||
NULL, // initialize func ptr
|
||||
&fs_mount, // mount func ptr
|
||||
&fs_unmount, // unmount func ptr
|
||||
NULL, // sync func ptr
|
||||
&fs_read_fs_stat, // rfsstat func ptr
|
||||
NULL, // wfsstat func ptr
|
||||
NULL,
|
||||
NULL,
|
||||
NULL, // open indexdir func ptr
|
||||
NULL, // close indexdir func ptr
|
||||
NULL, // free indexdir cookie func ptr
|
||||
NULL, // rewind indexdir func ptr
|
||||
NULL, // read indexdir func ptr
|
||||
NULL, // create index func ptr
|
||||
NULL, // remove index func ptr
|
||||
NULL, // rename index func ptr
|
||||
NULL, // stat index func ptr
|
||||
NULL, //&isofs_open_attrdir, // open attrdir func ptr
|
||||
NULL, //&isofs_close_attrdir, // close attrdir func ptr
|
||||
NULL, //&isofs_free_attrdir_cookie, // free attrdir cookie func ptr
|
||||
NULL, //&isofs_rewind_attrdir, // rewind attrdir func ptr
|
||||
NULL, //&isofs_read_attrdir, // read attrdir func ptr
|
||||
NULL, // write attr func ptr
|
||||
NULL, //&isofs_read_attr, // read attr func ptr
|
||||
NULL, // remove attr func ptr
|
||||
NULL, // rename attr func ptr
|
||||
NULL, //&isofs_stat_attr, // stat attr func ptr
|
||||
NULL, // open query func ptr
|
||||
NULL, // close query func ptr
|
||||
NULL, // free query cookie func ptr
|
||||
NULL // read query func ptr
|
||||
};
|
||||
|
||||
int32 api_version = B_CUR_FS_API_VERSION;
|
||||
|
||||
|
||||
static int
|
||||
fs_mount(nspace_id nsid, const char *device, ulong flags, void *parms,
|
||||
size_t len, void **data, vnode_id *vnid)
|
||||
{
|
||||
/*
|
||||
Kernel passes in nspace_id, (representing a disk or partition?)
|
||||
and a string representing the device (eg, "/dev/scsi/disk/030/raw)
|
||||
Flags will be used for things like specifying read-only mounting.
|
||||
parms is parameters passed in as switches from the mount command,
|
||||
and len is the length of the otions. data is a pointer to a
|
||||
driver-specific struct that should be allocated in this routine.
|
||||
It will then be passed back in by the kernel to a number of the other
|
||||
fs driver functions. vnid should also be passed back to the kernel,
|
||||
representing the vnode id of the root vnode.
|
||||
*/
|
||||
int result = EINVAL;
|
||||
// return EINVAL if it's not a device compatible with the driver.
|
||||
bool allow_joliet = true;
|
||||
nspace *vol;
|
||||
|
||||
(void)flags;
|
||||
|
||||
/* Create semaphore if it's not already created. When do we need to
|
||||
use semaphores? */
|
||||
|
||||
// Check for a 'nojoliet' parm
|
||||
// all we check for is the existance of 'nojoliet' in the parms.
|
||||
if (parms != NULL) {
|
||||
int i;
|
||||
char *spot;
|
||||
char *buf;
|
||||
|
||||
// Make sure the len argument isn't too large
|
||||
if (len > 1024)
|
||||
return EINVAL;
|
||||
|
||||
buf = malloc(len + 1);
|
||||
if (!buf)
|
||||
return ENOMEM;
|
||||
|
||||
memcpy(buf, parms, len);
|
||||
buf[len] = 0;
|
||||
// lower case the parms data
|
||||
for (i = 0; i < len + 1; i++)
|
||||
buf[i] = tolower(buf[i]);
|
||||
|
||||
// look for nojoliet
|
||||
spot = strstr(buf, "nojoliet");
|
||||
if (spot != NULL)
|
||||
allow_joliet = false;
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
// Try and mount volume as an ISO volume.
|
||||
result = ISOMount(device, O_RDONLY, &vol, allow_joliet);
|
||||
|
||||
// If it is ISO …
|
||||
if (result == B_NO_ERROR) {
|
||||
//vnode_id rootID = vol->rootDirRec.startLBN[FS_DATA_FORMAT];
|
||||
//*vnid = rootID;
|
||||
*vnid = ISO_ROOTNODE_ID;
|
||||
*data = (void*)vol;
|
||||
|
||||
vol->id = nsid;
|
||||
|
||||
// You MUST do this. Create the vnode for the root.
|
||||
result = new_vnode(nsid, *vnid, (void*)&(vol->rootDirRec));
|
||||
if (result != B_NO_ERROR) {
|
||||
remove_cached_device_blocks(vol->fd, 0);
|
||||
free(vol);
|
||||
result = EINVAL;
|
||||
} else
|
||||
result = B_NO_ERROR;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fs_unmount(void *_ns)
|
||||
{
|
||||
int result = B_NO_ERROR;
|
||||
|
||||
nspace* ns = (nspace*)_ns;
|
||||
//dprintf("fs_unmount - ENTER\n");
|
||||
//dprintf("fs_unmount - removing cached blocks\n");
|
||||
remove_cached_device_blocks(ns->fd, 0);
|
||||
//dprintf("fs_unmount - closing volume\n");
|
||||
close(ns->fdOfSession);
|
||||
result = close(ns->fd);
|
||||
//dprintf("fs_unmount - freeing volume data\n");
|
||||
free(ns);
|
||||
//dprintf("fs_unmount - EXIT, result is %s\n", strerror(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fs_read_fs_stat(void *_ns, struct fs_info *fss)
|
||||
{
|
||||
// Fill in fs_info struct for device.
|
||||
nspace *ns = (nspace *)_ns;
|
||||
int i;
|
||||
|
||||
//dprintf("fs_rfsstat - ENTER\n");
|
||||
|
||||
// Fill in device id.
|
||||
//fss->dev = ns->fd;
|
||||
|
||||
// Root vnode ID
|
||||
//fss->root = ISO_ROOTNODE_ID;
|
||||
|
||||
// File system flags.
|
||||
fss->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY;
|
||||
|
||||
// FS block size.
|
||||
fss->block_size = ns->logicalBlkSize[FS_DATA_FORMAT];
|
||||
|
||||
// IO size - specifies buffer size for file copying
|
||||
fss->io_size = 65536;
|
||||
|
||||
// Total blocks?
|
||||
fss->total_blocks = ns->volSpaceSize[FS_DATA_FORMAT];
|
||||
|
||||
// Free blocks = 0, read only
|
||||
fss->free_blocks = 0;
|
||||
|
||||
// Device name.
|
||||
strncpy(fss->device_name, ns->devicePath, sizeof(fss->device_name));
|
||||
|
||||
strncpy(fss->volume_name, ns->volIDString, sizeof(fss->volume_name));
|
||||
for (i=strlen(fss->volume_name)-1;i>=0;i--)
|
||||
if (fss->volume_name[i] != ' ')
|
||||
break;
|
||||
|
||||
if (i < 0)
|
||||
strcpy(fss->volume_name, "UNKNOWN");
|
||||
else
|
||||
fss->volume_name[i+1] = 0;
|
||||
|
||||
// File system name
|
||||
strcpy(fss->fsh_name,"iso9660");
|
||||
|
||||
//dprintf("fs_rfsstat - EXIT\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fs_walk - the walk function just "walks" through a directory looking for
|
||||
the specified file. When you find it, call get_vnode on its vnid to init
|
||||
it for the kernel.
|
||||
*/
|
||||
|
||||
int
|
||||
fs_walk(void *_ns, void *base, const char *file, char **newpath,
|
||||
vnode_id *vnid)
|
||||
{
|
||||
/* Starting at the base, find file in the subdir, and return path
|
||||
string and vnode id of file. */
|
||||
nspace* ns = (nspace*)_ns;
|
||||
vnode* baseNode = (vnode*)base;
|
||||
uint32 dataLen = baseNode->dataLen[FS_DATA_FORMAT];
|
||||
vnode* newNode = NULL;
|
||||
int result = ENOENT;
|
||||
bool done = FALSE;
|
||||
uint32 totalRead = 0;
|
||||
off_t block;
|
||||
|
||||
block = baseNode->startLBN[FS_DATA_FORMAT];
|
||||
|
||||
//dprintf("fs_walk - ENTER\n");
|
||||
//dprintf("fs_walk - looking for %s in dir file of length %d\n", file,baseNode->dataLen[FS_DATA_FORMAT]);
|
||||
|
||||
if (strcmp(file,".") == 0)
|
||||
{
|
||||
//dprintf("fs_walk - found \".\" file.\n");
|
||||
*vnid = baseNode->id;
|
||||
if (get_vnode(ns->id,*vnid,(void **)&newNode) != 0)
|
||||
result = EINVAL;
|
||||
else
|
||||
{
|
||||
result = B_NO_ERROR;
|
||||
}
|
||||
}
|
||||
else if (strcmp(file, "..") == 0)
|
||||
{
|
||||
//dprintf("fs_walk - found \"..\" file.\n");
|
||||
*vnid = baseNode->parID;
|
||||
if (get_vnode(ns->id, *vnid, (void**)&newNode) != 0)
|
||||
result = EINVAL;
|
||||
else
|
||||
{
|
||||
result = B_NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
char* blockData;
|
||||
while ((totalRead < dataLen) && !done)
|
||||
{
|
||||
off_t cachedBlock = block;
|
||||
|
||||
blockData = (char*)get_block(ns->fd, block, ns->logicalBlkSize[FS_DATA_FORMAT]);
|
||||
if (blockData != NULL)
|
||||
{
|
||||
int bytesRead = 0;
|
||||
off_t blockBytesRead = 0;
|
||||
vnode node;
|
||||
int initResult;
|
||||
//dprintf("fs_walk - read buffer from disk at LBN %Ld into buffer 0x%x.\n", block, blockData);
|
||||
//kernel_debugger("");
|
||||
// Move to the next 2-block set if necessary
|
||||
// Don't go over end of buffer, if dir record sits on boundary.
|
||||
|
||||
node.fileIDString = NULL;
|
||||
node.attr.slName = NULL;
|
||||
|
||||
while (blockBytesRead < 2*ns->logicalBlkSize[FS_DATA_FORMAT] &&
|
||||
(totalRead + blockBytesRead < dataLen) &&
|
||||
blockData[0] != 0 &&
|
||||
!done)
|
||||
{
|
||||
|
||||
initResult = InitNode(&node, blockData, &bytesRead, ns->joliet_level);
|
||||
//dprintf("fs_walk - InitNode returned %s, filename %s, %d bytes read\n", strerror(initResult), node.fileIDString, bytesRead);
|
||||
|
||||
if (initResult == B_NO_ERROR)
|
||||
{
|
||||
if ((strlen(node.fileIDString) == strlen(file)) &&
|
||||
!strncmp(node.fileIDString, file, strlen(file)))
|
||||
{
|
||||
//dprintf("fs_walk - success, found vnode at block %Ld, pos %Ld\n", block, blockBytesRead);
|
||||
*vnid = (block << 30) + (blockBytesRead & 0xFFFFFFFF);
|
||||
//dprintf("fs_walk - New vnode id is %Ld\n", *vnid);
|
||||
if (get_vnode(ns->id,*vnid,(void **)&newNode) != 0)
|
||||
result = EINVAL;
|
||||
else
|
||||
{
|
||||
newNode->parID = baseNode->id;
|
||||
done = TRUE;
|
||||
result = B_NO_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node.fileIDString != NULL)
|
||||
{
|
||||
free(node.fileIDString);
|
||||
node.fileIDString = NULL;
|
||||
}
|
||||
if (node.attr.slName != NULL)
|
||||
{
|
||||
free(node.attr.slName);
|
||||
node.attr.slName = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = initResult;
|
||||
if (bytesRead == 0) done = TRUE;
|
||||
}
|
||||
blockData += bytesRead;
|
||||
blockBytesRead += bytesRead;
|
||||
//dprintf("fs_walk - Adding %d bytes to blockBytes read (total %Ld/%Ld).\n", bytesRead, blockBytesRead, baseNode->dataLen[FS_DATA_FORMAT]);
|
||||
}
|
||||
totalRead += ns->logicalBlkSize[FS_DATA_FORMAT];
|
||||
block++;
|
||||
//dprintf("fs_walk - moving to next block %Ld, total read %Ld\n", block, totalRead);
|
||||
release_block(ns->fd, cachedBlock);
|
||||
|
||||
}
|
||||
else done = TRUE;
|
||||
}
|
||||
|
||||
// Check to see if vnode is a symbolic link. If so, fill in the newpath variable
|
||||
// with the path to the real file, and call put_vnode.
|
||||
if (newNode != NULL)
|
||||
{
|
||||
if ( S_ISLNK(newNode->attr.stat[FS_DATA_FORMAT].st_mode) && newpath != NULL)
|
||||
{
|
||||
//dprintf ("fs_walk - symbolic link file \'%s\' requested.\n", newNode->attr.slName);
|
||||
result = new_path(newNode->attr.slName, newpath);
|
||||
//dprintf ("fs_walk - putting vnode.\n");
|
||||
put_vnode(ns->id, *vnid);
|
||||
}
|
||||
}
|
||||
}
|
||||
//dprintf("fs_walk - EXIT, result is %s, vnid is %Lu\n", strerror(result), *vnid);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// fs_read_vnode - Using vnode id, read in vnode information into fs-specific struct,
|
||||
// and return it in node. the reenter flag tells you if this function
|
||||
// is being called via some other fs routine, so that things like
|
||||
// double-locking can be avoided.
|
||||
|
||||
int
|
||||
fs_read_vnode(void *_ns, vnode_id vnid, char reenter, void **node)
|
||||
{
|
||||
uint32 block, pos;
|
||||
nspace *ns = (nspace*)_ns;
|
||||
int result = B_NO_ERROR;
|
||||
vnode *newNode = (vnode*)calloc(sizeof(vnode), 1);
|
||||
|
||||
(void)reenter;
|
||||
|
||||
pos = (vnid & 0x3FFFFFFF);
|
||||
block = (vnid >> 30);
|
||||
|
||||
//dprintf("fs_read_vnode - ENTER, block = %ld, pos = %ld, raw = %Lu node 0x%x\n", block, pos, vnid, newNode);
|
||||
|
||||
if (newNode != NULL)
|
||||
{
|
||||
if (vnid == ISO_ROOTNODE_ID)
|
||||
{
|
||||
//dprintf("fs_read_vnode - root node requested.\n");
|
||||
memcpy(newNode, &(ns->rootDirRec), sizeof(vnode));
|
||||
*node = (void*)newNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
char* blockData = (char*)get_block(ns->fd, block, ns->logicalBlkSize[FS_DATA_FORMAT]);
|
||||
if (pos > ns->logicalBlkSize[FS_DATA_FORMAT]) {
|
||||
if(blockData != NULL) release_block(ns->fd, block);
|
||||
result = EINVAL;
|
||||
} else if (blockData != NULL) {
|
||||
result = InitNode(newNode, blockData + pos, NULL, ns->joliet_level);
|
||||
release_block(ns->fd, block);
|
||||
newNode->id = vnid;
|
||||
//dprintf("fs_read_vnode - init result is %s\n", strerror(result));
|
||||
*node = (void*)newNode;
|
||||
//dprintf("fs_read_vnode - new file %s, size %ld\n", newNode->fileIDString, newNode->dataLen[FS_DATA_FORMAT]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else result = ENOMEM;
|
||||
|
||||
//dprintf("fs_read_vnode - EXIT, result is %s\n", strerror(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
fs_write_vnode(void *ns, void *_node, char reenter)
|
||||
{
|
||||
int result = B_NO_ERROR;
|
||||
vnode *node = (vnode*)_node;
|
||||
|
||||
(void)ns;
|
||||
(void)reenter;
|
||||
|
||||
//dprintf("fs_write_vnode - ENTER (0x%x)\n", node);
|
||||
if (node != NULL) {
|
||||
if (node->id != ISO_ROOTNODE_ID) {
|
||||
if (node->fileIDString != NULL)
|
||||
free (node->fileIDString);
|
||||
if (node->attr.slName != NULL)
|
||||
free (node->attr.slName);
|
||||
free(node);
|
||||
}
|
||||
}
|
||||
//dprintf("fs_write_vnode - EXIT\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fs_read_stat(void *_ns, void *_node, struct stat *st)
|
||||
{
|
||||
nspace *ns = (nspace*)_ns;
|
||||
vnode *node = (vnode*)_node;
|
||||
int result = B_NO_ERROR;
|
||||
time_t time;
|
||||
|
||||
//dprintf("fs_rstat - ENTER\n");
|
||||
st->st_dev = ns->id;
|
||||
st->st_ino = node->id;
|
||||
st->st_nlink = node->attr.stat[FS_DATA_FORMAT].st_nlink;
|
||||
st->st_uid = node->attr.stat[FS_DATA_FORMAT].st_uid;
|
||||
st->st_gid = node->attr.stat[FS_DATA_FORMAT].st_gid;
|
||||
st->st_blksize = 65536;
|
||||
st->st_mode = node->attr.stat[FS_DATA_FORMAT].st_mode;
|
||||
|
||||
// Same for file/dir in ISO9660
|
||||
st->st_size = node->dataLen[FS_DATA_FORMAT];
|
||||
if (ConvertRecDate(&(node->recordDate), &time) == B_NO_ERROR)
|
||||
st->st_ctime = st->st_mtime = st->st_atime = time;
|
||||
//dprintf("fs_rstat - EXIT, result is %s\n", strerror(result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// fs_open - Create a vnode cookie, if necessary, to use when
|
||||
// reading/writing a file
|
||||
static int
|
||||
fs_open(void *_ns, void *_node, int omode, void **cookie)
|
||||
{
|
||||
int result = B_NO_ERROR;
|
||||
|
||||
(void)_ns;
|
||||
(void)cookie;
|
||||
|
||||
// Do not allow any of the write-like open modes to get by
|
||||
if ((omode == O_WRONLY) || (omode == O_RDWR))
|
||||
result = EROFS;
|
||||
else if((omode & O_TRUNC) || (omode & O_CREAT))
|
||||
result = EROFS;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// fs_read
|
||||
// Read a file specified by node, using information in cookie
|
||||
// and at offset specified by pos. read len bytes into buffer buf.
|
||||
static int
|
||||
fs_read(void *_ns, void *_node, void *cookie, off_t pos, void *buf,
|
||||
size_t *len)
|
||||
{
|
||||
nspace *ns = (nspace *)_ns; // global stuff
|
||||
vnode *node = (vnode *)_node; // The read file vnode.
|
||||
uint16 blockSize = ns->logicalBlkSize[FS_DATA_FORMAT];
|
||||
uint32 startBlock = node->startLBN[FS_DATA_FORMAT] + (pos / blockSize);
|
||||
off_t blockPos = pos %blockSize;
|
||||
off_t numBlocks = 0;
|
||||
uint32 dataLen = node->dataLen[FS_DATA_FORMAT];
|
||||
int result = B_NO_ERROR;
|
||||
size_t endLen = 0;
|
||||
size_t reqLen = *len;
|
||||
size_t startLen = 0;
|
||||
|
||||
(void)cookie;
|
||||
|
||||
// Allow an open to work on a dir, but no reads
|
||||
if (node->flags & ISO_ISDIR)
|
||||
return EISDIR;
|
||||
|
||||
if (pos < 0)
|
||||
pos = 0;
|
||||
*len = 0;
|
||||
|
||||
// If passed-in requested length is bigger than file size, change it to
|
||||
// file size.
|
||||
if (reqLen + pos > dataLen)
|
||||
reqLen = dataLen - pos;
|
||||
|
||||
// Compute the length of the partial start-block read, if any.
|
||||
|
||||
if (reqLen + blockPos <= blockSize)
|
||||
startLen = reqLen;
|
||||
else if (blockPos > 0)
|
||||
startLen = blockSize - blockPos;
|
||||
|
||||
if (blockPos == 0 && reqLen >= blockSize) {
|
||||
//dprintf("Setting startLen to 0, even block read\n");
|
||||
startLen = 0;
|
||||
}
|
||||
|
||||
// Compute the length of the partial end-block read, if any.
|
||||
if (reqLen + blockPos > blockSize)
|
||||
endLen = (reqLen +blockPos) % blockSize;
|
||||
|
||||
// Compute the number of middle blocks to read.
|
||||
numBlocks = ((reqLen - endLen - startLen) / blockSize);
|
||||
|
||||
//dprintf("fs_read - ENTER, pos is %Ld, len is %lu\n", pos, reqLen);
|
||||
//dprintf("fs_read - filename is %s\n", node->fileIDString);
|
||||
//dprintf("fs_read - total file length is %lu\n", dataLen);
|
||||
//dprintf("fs_read - start block of file is %lu\n", node->startLBN[FS_DATA_FORMAT]);
|
||||
//dprintf("fs_read - block pos is %Lu\n", blockPos);
|
||||
//dprintf("fs_read - read block will be %lu\n", startBlock);
|
||||
//dprintf("fs_read - startLen is %lu\n", startLen);
|
||||
//dprintf("fs_read - endLen is %lu\n", endLen);
|
||||
//dprintf("fs_read - num blocks to read is %Ld\n", numBlocks);
|
||||
|
||||
if (pos >= dataLen) {
|
||||
// If pos >= file length, return length of 0.
|
||||
*len = 0;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Read in the first, potentially partial, block.
|
||||
if (startLen > 0) {
|
||||
off_t cachedBlock = startBlock;
|
||||
char *blockData = (char *)get_block(ns->fd, startBlock, blockSize);
|
||||
if (blockData != NULL) {
|
||||
//dprintf("fs_read - copying first block, len is %d.\n", startLen);
|
||||
memcpy(buf, blockData+blockPos, startLen);
|
||||
*len += startLen;
|
||||
release_block(ns->fd, cachedBlock);
|
||||
startBlock++;
|
||||
}
|
||||
else result = EIO;
|
||||
}
|
||||
|
||||
// Read in the middle blocks.
|
||||
if (numBlocks > 0 && result == B_NO_ERROR) {
|
||||
//dprintf("fs_read - getting middle blocks\n");
|
||||
result = cached_read(ns->fd, startBlock,
|
||||
((char *)buf) + startLen,
|
||||
numBlocks,
|
||||
blockSize);
|
||||
if (result == B_NO_ERROR)
|
||||
*len += blockSize * numBlocks;
|
||||
}
|
||||
|
||||
// Read in the last partial block.
|
||||
if (result == B_NO_ERROR && endLen > 0) {
|
||||
off_t endBlock = startBlock + numBlocks;
|
||||
char *endBlockData = (char*)get_block(ns->fd, endBlock, blockSize);
|
||||
if (endBlockData != NULL) {
|
||||
char *endBuf = ((char *)buf) + (reqLen - endLen);
|
||||
|
||||
memcpy(endBuf, endBlockData, endLen);
|
||||
release_block(ns->fd, endBlock);
|
||||
*len += endLen;
|
||||
} else
|
||||
result = EIO;
|
||||
}
|
||||
|
||||
//dprintf("fs_read - EXIT, result is %s\n", strerror(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// fs_close - Do whatever is necessary to close a file, EXCEPT for freeing
|
||||
// the cookie!
|
||||
static int
|
||||
fs_close(void *ns, void *node, void *cookie)
|
||||
{
|
||||
(void)ns;
|
||||
(void)node;
|
||||
(void)cookie;
|
||||
|
||||
//dprintf("fs_close - ENTER\n");
|
||||
//dprintf("fs_close - EXIT\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fs_free_cookie(void *ns, void *node, void *cookie)
|
||||
{
|
||||
(void)ns;
|
||||
(void)node;
|
||||
(void)cookie;
|
||||
|
||||
// We don't allocate file cookies, so we do nothing here.
|
||||
//dprintf("fs_free_cookie - ENTER\n");
|
||||
//if (cookie != NULL) free (cookie);
|
||||
//dprintf("fs_free_cookie - EXIT\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// fs_access - checks permissions for access.
|
||||
static int
|
||||
fs_access(void *ns, void *node, int mode)
|
||||
{
|
||||
(void)ns;
|
||||
(void)node;
|
||||
(void)mode;
|
||||
|
||||
// ns - global, fs-specific struct for device
|
||||
// node - node to check permissions for
|
||||
// mode - requested permissions on node.
|
||||
//dprintf("fs_access - ENTER\n");
|
||||
//dprintf("fs_access - EXIT\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fs_read_link(void *_ns, void *_node, char *buffer, size_t *_bufferSize)
|
||||
{
|
||||
vnode *node = (vnode *)_node;
|
||||
int result = EINVAL;
|
||||
|
||||
(void)_ns;
|
||||
|
||||
if (S_ISLNK(node->attr.stat[FS_DATA_FORMAT].st_mode)) {
|
||||
size_t length = strlen(node->attr.slName);
|
||||
if (length > *_bufferSize)
|
||||
memcpy(buffer, node->attr.slName, length);
|
||||
else
|
||||
memcpy(buffer, node->attr.slName, length);
|
||||
|
||||
result = B_NO_ERROR;
|
||||
*_bufferSize = length;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fs_open_dir(void *_ns, void *_node, void **cookie)
|
||||
{
|
||||
// creates fs-specific "cookie" struct that keeps track of where
|
||||
// you are at in reading through directory entries in fs_readdir.
|
||||
|
||||
vnode *node = (vnode *)_node;
|
||||
int result = B_NO_ERROR;
|
||||
dircookie *dirCookie = (dircookie *)malloc(sizeof(dircookie));
|
||||
|
||||
(void)_ns;
|
||||
|
||||
//dprintf("fs_opendir - ENTER, node is 0x%x\n", _node);
|
||||
if (!(node->flags & ISO_ISDIR))
|
||||
result = EMFILE;
|
||||
|
||||
if (dirCookie != NULL) {
|
||||
dirCookie->startBlock = node->startLBN[FS_DATA_FORMAT];
|
||||
dirCookie->block = node->startLBN[FS_DATA_FORMAT];
|
||||
dirCookie->totalSize = node->dataLen[FS_DATA_FORMAT];
|
||||
dirCookie->pos = 0;
|
||||
dirCookie->id = node->id;
|
||||
*cookie = (void *)dirCookie;
|
||||
} else
|
||||
result = ENOMEM;
|
||||
|
||||
//dprintf("fs_opendir - EXIT\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fs_read_dir(void *_ns, void *_node, void *_cookie, long *num,
|
||||
struct dirent *buffer, size_t bufferSize)
|
||||
{
|
||||
int result = B_NO_ERROR;
|
||||
nspace *ns = (nspace *)_ns;
|
||||
dircookie *dirCookie = (dircookie *)_cookie;
|
||||
|
||||
(void)_node;
|
||||
|
||||
//dprintf("fs_readdir - ENTER\n");
|
||||
result = ISOReadDirEnt(ns, dirCookie, buffer, bufferSize);
|
||||
|
||||
// If we succeeded, return 1, the number of dirents we read.
|
||||
if (result == B_NO_ERROR)
|
||||
*num = 1;
|
||||
else
|
||||
*num = 0;
|
||||
|
||||
// When you get to the end, don't return an error, just return
|
||||
// a zero in *num.
|
||||
|
||||
if (result == ENOENT)
|
||||
result = B_NO_ERROR;
|
||||
|
||||
//dprintf("fs_readdir - EXIT, result is %s\n", strerror(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fs_rewind_dir(void *ns, void *node, void* _cookie)
|
||||
{
|
||||
int result = EINVAL;
|
||||
dircookie *cookie = (dircookie*)_cookie;
|
||||
|
||||
(void)ns;
|
||||
(void)node;
|
||||
|
||||
//dprintf("fs_rewinddir - ENTER\n");
|
||||
if (cookie != NULL) {
|
||||
cookie->block = cookie->startBlock;
|
||||
cookie->pos = 0;
|
||||
result = B_NO_ERROR;
|
||||
}
|
||||
//dprintf("fs_rewinddir - EXIT, result is %s\n", strerror(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fs_close_dir(void *ns, void *node, void *cookie)
|
||||
{
|
||||
(void)ns;
|
||||
(void)node;
|
||||
(void)cookie;
|
||||
|
||||
// ns - global, fs-specific struct for device
|
||||
// node - directory to close
|
||||
// cookie - current cookie for directory.
|
||||
//dprintf("fs_closedir - ENTER\n");
|
||||
//dprintf("fs_closedir - EXIT\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fs_free_dir_cookie(void *ns, void *node, void *cookie)
|
||||
{
|
||||
(void)ns;
|
||||
(void)node;
|
||||
|
||||
// ns - global, fs-specific struct for device
|
||||
// node - directory related to cookie
|
||||
// cookie - current cookie for directory, to free.
|
||||
//dprintf("fs_free_dircookie - ENTER\n");
|
||||
if (cookie != NULL)
|
||||
free(cookie);
|
||||
|
||||
//dprintf("fs_free_dircookie - EXIT\n");
|
||||
return 0;
|
||||
}
|
32
src/add-ons/kernel/file_systems/iso9660/lock.h
Normal file
32
src/add-ons/kernel/file_systems/iso9660/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/add-ons/kernel/file_systems/iso9660/rock.h
Normal file
32
src/add-ons/kernel/file_systems/iso9660/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…
Reference in New Issue
Block a user