Files
haiku-beta6/src/add-ons/kernel/file_systems/iso9660/kernel_interface.cpp
T
Ingo Weinhold 12d359b85a * Removed write_link from the FS module interface. Adjusted all FS
add-ons accordingly and removed the syscall.
* Removed send_notification().
* Reimplemented notify_listener(). It used the unimplemented
  send_notification(). Now it has a chance to work. Note that
  notify_listener() is obsolete. I would already have removed it, if
  there weren't lots of FS implementations still using it (Hint!).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20329 a95241bf-73f2-0310-859d-f6bbb57e9c96
2007-03-05 00:46:57 +00:00

1080 lines
27 KiB
C++

/*
** 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 <ctype.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <time.h>
#include <malloc.h>
#include <KernelExport.h>
#include <NodeMonitor.h>
#include <fs_interface.h>
#include <fs_cache.h>
#include <fs_attr.h>
#include <fs_info.h>
#include <fs_index.h>
#include <fs_query.h>
#include <fs_volume.h>
#include <util/kernel_cpp.h>
#include "iso.h"
#include "iso9660.h"
//#define TRACE_ISO9660 1
#if TRACE_ISO9660
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
/* Start of fundamental (read-only) required functions */
static status_t fs_mount(mount_id mountID, const char *device, uint32 flags,
const char *args, void **_data, vnode_id *_rootID);
static status_t fs_unmount(void *ns);
static status_t fs_get_vnode_name(void *_ns, void *_node,
char *buffer, size_t bufferSize);
static status_t fs_walk(void *_ns, void *_base, const char *file,
vnode_id *_vnodeID, int *_type);
static status_t fs_read_vnode(void *_ns, vnode_id vnid, void **node, bool reenter);
static status_t fs_release_vnode(void *_ns, void *_node, bool reenter);
static status_t fs_get_file_map(fs_volume _fs, fs_vnode _node, off_t offset, size_t size,
struct file_io_vec *vecs, size_t *_count);
static status_t fs_read_stat(void *_ns, void *_node, struct stat *st);
static status_t fs_open(void *_ns, void *_node, int omode, void **cookie);
static status_t fs_read(void *_ns, void *_node, void *cookie, off_t pos,
void *buf, size_t *len);
/// fs_free_cookie - free cookie for file created in open.
static status_t fs_free_cookie(void *ns, void *node, void *cookie);
static status_t fs_close(void *ns, void *node, void *cookie);
// fs_access - checks permissions for access.
static status_t fs_access(void *_ns, void *_node, int mode);
// fs_opendir - creates fs-specific "cookie" struct that can tell where
// we are at in the directory list.
static status_t fs_open_dir(void* _ns, void* _node, void** cookie);
// fs_readdir - read 1 or more dirents, keep state in cookie, return
// 0 when no more entries.
static status_t fs_read_dir(void *_ns, void *_node, void *cookie, struct dirent *buf,
size_t bufsize, uint32 *_num);
// fs_rewinddir - set cookie to represent beginning of directory, so
// later fs_readdir calls start at beginning.
static status_t fs_rewind_dir(void *_ns, void *_node, void *cookie);
// fs_closedir - Do whatever you need to to close a directory (sometimes
// nothing), but DON'T free the cookie!
static status_t fs_close_dir(void *_ns, void *_node, void *cookie);
// fs_free_dircookie - Free the fs-specific cookie struct
static status_t fs_free_dir_cookie(void *_ns, void *_node, void *cookie);
// fs_rfsstat - Fill in fs_info struct for device.
static status_t fs_read_fs_stat(void *_ns, struct fs_info *);
// fs_readlink - Read in the name of a symbolic link.
static status_t fs_read_link(void *_ns, void *_node, char *buf, size_t *bufsize);
// #pragma mark - Scanning
struct identify_cookie {
iso9660_info info;
};
static float
fs_identify_partition(int fd, partition_data *partition, void **_cookie)
{
iso9660_info info;
status_t status = iso9660_fs_identify(fd, &info);
if (status != B_OK)
return status;
identify_cookie *cookie = new identify_cookie;
memcpy(&cookie->info, &info, sizeof(info));
*_cookie = cookie;
return 0.8f;
}
static status_t
fs_scan_partition(int fd, partition_data *partition, void *_cookie)
{
identify_cookie *cookie = (identify_cookie *)_cookie;
partition->status = B_PARTITION_VALID;
partition->flags |= B_PARTITION_FILE_SYSTEM | B_PARTITION_READ_ONLY ;
partition->block_size = ISO_PVD_SIZE;
partition->content_size = ISO_PVD_SIZE * cookie->info.maxBlocks;
partition->content_name = strdup(cookie->info.get_preferred_volume_name());
if (partition->content_name == NULL)
return B_NO_MEMORY;
return B_OK;
}
static void
fs_free_identify_partition_cookie(partition_data *partition, void *_cookie)
{
identify_cookie *cookie = (identify_cookie *)_cookie;
delete cookie;
}
static status_t
fs_mount(mount_id mountID, const char *device, uint32 flags,
const char *args, void **_data, vnode_id *_rootID)
{
/*
Kernel passes in nspace_id, (representing a disk or partition?)
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.
*/
status_t 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 (args != NULL) {
uint32 i;
char *spot;
char *buf = strdup(args);
uint32 len = strlen(buf);
// 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;
*_rootID = ISO_ROOTNODE_ID;
*_data = (void*)vol;
vol->id = mountID;
// You MUST do this. Create the vnode for the root.
result = publish_vnode(mountID, *_rootID, (void*)&(vol->rootDirRec));
if (result != B_NO_ERROR) {
block_cache_delete(vol->fBlockCache, false);
free(vol);
result = EINVAL;
} else
result = B_NO_ERROR;
}
return result;
}
static status_t
fs_unmount(void *_ns)
{
status_t result = B_NO_ERROR;
nspace *ns = (nspace *)_ns;
TRACE(("fs_unmount - ENTER\n"));
// Unlike in BeOS, we need to put the reference to our root node ourselves
put_vnode(ns->id, ISO_ROOTNODE_ID);
block_cache_delete(ns->fBlockCache, false);
close(ns->fdOfSession);
result = close(ns->fd);
free(ns);
TRACE(("fs_unmount - EXIT, result is %s\n", strerror(result)));
return result;
}
static status_t
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_read_fs_stat - 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_read_fs_stat - EXIT\n"));
return 0;
}
static status_t
fs_get_vnode_name(void *ns, void *_node, char *buffer, size_t bufferSize)
{
vnode *node = (vnode*)_node;
strlcpy(buffer, node->fileIDString, bufferSize);
return B_OK;
}
/* 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.
*/
static status_t
fs_walk(void *_ns, void *base, const char *file, vnode_id *_vnodeID, int *_type)
{
/* Starting at the base, find file in the subdir, and return path
string and vnode id of file. */
nspace *ns = (nspace *)_ns;
vnode *baseNode = (vnode*)base;
uint32 dataLen = baseNode->dataLen[FS_DATA_FORMAT];
vnode *newNode = NULL;
status_t 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"));
*_vnodeID = baseNode->id;
*_type = S_IFDIR;
if (get_vnode(ns->id, *_vnodeID, (void **)&newNode) != 0)
result = EINVAL;
else
result = B_NO_ERROR;
} else if (strcmp(file, "..") == 0) {
// parent directory
TRACE(("fs_walk - found \"..\" file.\n"));
*_vnodeID = baseNode->parID;
*_type = S_IFDIR;
if (get_vnode(ns->id, *_vnodeID, (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 *)block_cache_get_etc(ns->fBlockCache, block, 0, 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));
*_vnodeID = (block << 30) + (blockBytesRead & 0xFFFFFFFF);
TRACE(("fs_walk - New vnode id is %Ld\n", *_vnodeID));
if (get_vnode(ns->id, *_vnodeID, (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));
block_cache_put(ns->fBlockCache, cachedBlock);
} else
done = TRUE;
}
if (newNode)
*_type = newNode->attr.stat[FS_DATA_FORMAT].st_mode;
}
TRACE(("fs_walk - EXIT, result is %s, vnid is %Lu\n", strerror(result), *_vnodeID));
return result;
}
static status_t
fs_read_vnode(void *_ns, vnode_id vnid, void **node, bool reenter)
{
uint32 block, pos;
nspace *ns = (nspace*)_ns;
status_t 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 *)block_cache_get_etc(ns->fBlockCache, block, 0, ns->logicalBlkSize[FS_DATA_FORMAT]);
if (pos > ns->logicalBlkSize[FS_DATA_FORMAT]) {
if (blockData != NULL)
block_cache_put(ns->fBlockCache, block);
result = EINVAL;
} else if (blockData != NULL) {
result = InitNode(newNode, blockData + pos, NULL, ns->joliet_level);
block_cache_put(ns->fBlockCache, 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;
if (result == B_OK && !(newNode->flags & ISO_ISDIR)) {
newNode->cache = file_cache_create(ns->id, vnid, newNode->dataLen[FS_DATA_FORMAT], ns->fdOfSession);
}
TRACE(("fs_read_vnode - EXIT, result is %s\n", strerror(result)));
return result;
}
static status_t
fs_release_vnode(void *ns, void *_node, bool reenter)
{
status_t result = B_NO_ERROR;
vnode *node = (vnode*)_node;
(void)ns;
(void)reenter;
TRACE(("fs_release_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);
if (node->cache != NULL)
file_cache_delete(node->cache);
free(node);
}
}
TRACE(("fs_release_vnode - EXIT\n"));
return result;
}
static status_t
fs_get_file_map(fs_volume _fs, fs_vnode _node, off_t pos, size_t reqLen,
struct file_io_vec *vecs, size_t *_count)
{
nspace *ns = (nspace *)_fs; // 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];
size_t endLen = 0;
size_t startLen = 0;
size_t index = 0, max = *_count;
TRACE(("fs_get_file_map - ENTER (0x%x)\n", node));
// Allow an open to work on a dir, but no reads
if (node->flags & ISO_ISDIR)
return EISDIR;
if (pos < 0)
pos = 0;
*_count = 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\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);
if (pos >= dataLen) {
// If pos >= file length, return
return B_OK;
}
// Read in the first, potentially partial, block.
if (startLen > 0) {
vecs[index].offset = startBlock * blockSize + blockPos;
vecs[index].length = startLen;
startBlock++;
index++;
if (index >= max) {
// we're out of file_io_vecs; let's bail out
*_count = index;
return B_BUFFER_OVERFLOW;
}
}
// Read in the middle blocks.
if (numBlocks > 0) {
for (int32 i=startBlock; i<startBlock+numBlocks; i++) {
vecs[index].offset = i * blockSize;
vecs[index].length = blockSize;
index++;
if (index >= max) {
// we're out of file_io_vecs; let's bail out
*_count = index;
return B_BUFFER_OVERFLOW;
}
}
}
// Read in the last partial block.
if (endLen > 0) {
off_t endBlock = startBlock + numBlocks;
vecs[index].offset = endBlock * blockSize;
vecs[index].length = endLen;
index++;
}
*_count = index;
TRACE(("fs_get_file_map - EXIT\n"));
return B_OK;
}
static status_t
fs_read_stat(void *_ns, void *_node, struct stat *st)
{
nspace *ns = (nspace*)_ns;
vnode *node = (vnode*)_node;
status_t result = B_NO_ERROR;
time_t time;
TRACE(("fs_read_stat - 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_read_stat - EXIT, result is %s\n", strerror(result)));
return result;
}
static status_t
fs_open(void *_ns, void *_node, int omode, void **cookie)
{
status_t 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 status_t
fs_read(void *_ns, void *_node, void *cookie, off_t pos, void *buf, size_t *len)
{
#if 0
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];
status_t 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 *)block_cache_get_etc(ns->fBlockCache, startBlock, 0, blockSize);
if (blockData != NULL) {
//dprintf("fs_read - copying first block, len is %d.\n", startLen);
memcpy(buf, blockData+blockPos, startLen);
*len += startLen;
block_cache_put(ns->fBlockCache, cachedBlock);
startBlock++;
} else
result = EIO;
}
// Read in the middle blocks.
if (numBlocks > 0 && result == B_NO_ERROR) {
TRACE(("fs_read - getting middle blocks\n"));
char *endBuf = ((char *)buf) + startLen;
for (int32 i=startBlock; i<startBlock+numBlocks; i++) {
char *blockData = (char *)block_cache_get_etc(ns->fBlockCache, i, 0, blockSize);
memcpy(endBuf, blockData, blockSize);
*len += blockSize;
endBuf += blockSize;
block_cache_put(ns->fBlockCache, i);
}
}
// Read in the last partial block.
if (result == B_NO_ERROR && endLen > 0) {
off_t endBlock = startBlock + numBlocks;
char *endBlockData = (char*)block_cache_get_etc(ns->fBlockCache, endBlock, 0, blockSize);
if (endBlockData != NULL) {
char *endBuf = ((char *)buf) + (reqLen - endLen);
memcpy(endBuf, endBlockData, endLen);
block_cache_put(ns->fBlockCache, endBlock);
*len += endLen;
} else
result = EIO;
}
TRACE(("fs_read - EXIT, result is %s\n", strerror(result)));
return result;
#else
vnode *node = (vnode *)_node; // The read file vnode.
uint32 dataLen = node->dataLen[FS_DATA_FORMAT];
// set/check boundaries for pos/length
if (pos < 0) {
return B_BAD_VALUE;
}
if (pos >= dataLen) {
// If pos >= file length, return length of 0.
*len = 0;
return B_OK;
}
return file_cache_read(node->cache, pos, buf, len);
#endif
}
static status_t
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 B_OK;
}
static status_t
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 B_OK;
}
// fs_access - checks permissions for access.
static status_t
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 B_OK;
}
static status_t
fs_read_link(void *_ns, void *_node, char *buffer, size_t *_bufferSize)
{
vnode *node = (vnode *)_node;
status_t 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, *_bufferSize);
else {
memcpy(buffer, node->attr.slName, length);
*_bufferSize = length;
}
result = B_NO_ERROR;
}
return result;
}
static status_t
fs_open_dir(void *_ns, void *_node, void **cookie)
{
vnode *node = (vnode *)_node;
status_t result = B_NO_ERROR;
dircookie *dirCookie = (dircookie *)malloc(sizeof(dircookie));
(void)_ns;
TRACE(("fs_open_dir - 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_open_dir - EXIT\n"));
return result;
}
static status_t
fs_read_dir(void *_ns, void *_node, void *_cookie, struct dirent *buffer,
size_t bufferSize, uint32 *num)
{
status_t result = B_NO_ERROR;
nspace *ns = (nspace *)_ns;
dircookie *dirCookie = (dircookie *)_cookie;
(void)_node;
TRACE(("fs_read_dir - 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_read_dir - EXIT, result is %s\n", strerror(result)));
return result;
}
static status_t
fs_rewind_dir(void *ns, void *node, void* _cookie)
{
status_t result = EINVAL;
dircookie *cookie = (dircookie*)_cookie;
(void)ns;
(void)node;
//dprintf("fs_rewind_dir - ENTER\n");
if (cookie != NULL) {
cookie->block = cookie->startBlock;
cookie->pos = 0;
result = B_NO_ERROR;
}
//dprintf("fs_rewind_dir - EXIT, result is %s\n", strerror(result));
return result;
}
static status_t
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_close_dir - ENTER\n");
//dprintf("fs_close_dir - EXIT\n");
return B_OK;
}
static status_t
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_dir_cookie - ENTER\n");
if (cookie != NULL)
free(cookie);
//dprintf("fs_free_dir_cookie - EXIT\n");
return B_OK;
}
// #pragma mark -
static status_t
iso_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
return B_OK;
case B_MODULE_UNINIT:
return B_OK;
default:
return B_ERROR;
}
}
static file_system_module_info sISO660FileSystem = {
{
"file_systems/iso9660" B_CURRENT_FS_API_VERSION,
0,
iso_std_ops,
},
"ISO9660 File System",
// scanning
fs_identify_partition,
fs_scan_partition,
fs_free_identify_partition_cookie,
NULL, // free_partition_content_cookie()
&fs_mount,
&fs_unmount,
&fs_read_fs_stat,
NULL,
NULL,
/* vnode operations */
&fs_walk,
&fs_get_vnode_name,
&fs_read_vnode,
&fs_release_vnode,
NULL, // &fs_remove_vnode()
/* VM file access */
NULL, // &fs_can_page
NULL, // &fs_read_pages
NULL, // &fs_write_pages
&fs_get_file_map,
NULL, // &fs_ioctl
NULL, // &fs_set_flags
NULL, // &fs_select
NULL, // &fs_deselect
NULL, // &fs_fsync
&fs_read_link,
NULL, // &fs_create_symlink,
NULL, // &fs_link,
NULL, // &fs_unlink
NULL, // &fs_rename
&fs_access,
&fs_read_stat,
NULL, // &fs_write_stat
/* file operations */
NULL, // &fs_create
&fs_open,
&fs_close,
&fs_free_cookie,
&fs_read,
NULL, // &fs_write
/* directory operations */
NULL, // &fs_create_dir
NULL, // &fs_remove_dir
&fs_open_dir,
&fs_close_dir,
&fs_free_dir_cookie,
&fs_read_dir,
&fs_rewind_dir,
/* attribute directory operations */
NULL, // &fs_open_attr_dir
NULL, // &fs_close_attr_dir
NULL, // &fs_free_attr_dir_cookie
NULL, // &fs_read_attr_dir
NULL, // &fs_rewind_attr_dir
/* attribute operations */
NULL, // &fs_create_attr
NULL, // &fs_open_attr
NULL, // &fs_close_attr
NULL, // &fs_free_attr_cookie
NULL, // &fs_read_attr
NULL, // &fs_write_attr
NULL, // &fs_read_attr_stat
NULL, // &fs_write_attr_stat
NULL, // &fs_rename_attr
NULL, // &fs_remove_attr
/* index directory & index operations */
NULL, // &fs_open_index_dir
NULL, // &fs_close_index_dir
NULL, // &fs_free_index_dir_cookie
NULL, // &fs_read_index_dir
NULL, // &fs_rewind_index_dir
NULL, // &fs_create_index
NULL, // &fs_remove_index
NULL, // &fs_stat_index
/* query operations */
NULL, // &fs_open_query
NULL, // &fs_close_query
NULL, // &fs_free_query_cookie
NULL, // &fs_read_query
NULL, // &fs_rewind_query
};
module_info *modules[] = {
(module_info *)&sISO660FileSystem,
NULL,
};