* ISOReadDirEnt() did not set the dirent::d_dev field, thus causing bug #2734.

* Moved the rock ridge attribute parsing code to a separate function.
* Removed superfluous malloc() vs. realloc() code.
* Checked allocations in the rock ridge parsing code.
* Cleanup, renamed some variables, structures, functions, etc.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27569 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2008-09-15 14:42:48 +00:00
parent 3cdff7414f
commit eb0974311f
5 changed files with 1020 additions and 1071 deletions

View File

@ -7,7 +7,7 @@ SubDirCcFlags -Wall -Wno-multichar ;
SubDirC++Flags -Wall -Wno-multichar -fno-rtti ;
KernelAddon iso9660 :
iso9660.c
iso9660.cpp
iso9660_identify.cpp
kernel_interface.cpp
;

View File

@ -1,951 +0,0 @@
/*
* 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.
*/
#include "iso9660.h"
#include <ByteOrder.h>
#include <Drivers.h>
#include <KernelExport.h>
#include <OS.h>
#include <SupportDefs.h>
#include <fs_cache.h>
#include <dirent.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include "rock_ridge.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);
// 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));
vol->fBlockCache = block_cache_create(vol->fd, maxBlocks,
vol->logicalBlkSize[FS_DATA_FORMAT], true);
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.
*/
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;
TRACE(("ISOReadDirEnt - ENTER\n"));
// If we're at the end of the data in a block, move to the next block.
while (true) {
blockData = (char *)block_cache_get_etc(ns->fBlockCache, cookie->block,
0, ns->logicalBlkSize[FS_DATA_FORMAT]);
if (blockData != NULL && *(blockData + cookie->pos) == 0) {
// NULL data, move to next block.
block_cache_put(ns->fBlockCache, cookie->block);
blockData = NULL;
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;
result = InitNode(&node, blockData + cookie->pos, &bytesRead,
ns->joliet_level);
if (result == 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 = sizeof(struct dirent) + node.fileIDLen + 1;
if (node.fileIDLen <= nameBufSize) {
// need to do some size checking here.
strlcpy(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 (blockData != NULL)
block_cache_put(ns->fBlockCache, 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));
rec->cache = NULL;
if (recLen > 0) {
rec->extAttrRecLen = *(uint8 *)buffer++;
rec->startLBN[LSB_DATA] = *(uint32 *)buffer;
buffer += 4;
rec->startLBN[MSB_DATA] = *(uint32 *)buffer;
buffer += 4;
TRACE(("InitNode - data start LBN is %ld\n", rec->startLBN[FS_DATA_FORMAT]));
rec->dataLen[LSB_DATA] = *(uint32 *)buffer;
buffer += 4;
rec->dataLen[MSB_DATA] = *(uint32 *)buffer;
buffer += 4;
TRACE(("InitNode - data length is %ld\n", rec->dataLen[FS_DATA_FORMAT]));
InitRecDate(&(rec->recordDate), buffer);
buffer += 7;
rec->flags = *(uint8 *)buffer;
buffer++;
TRACE(("InitNode - flags are %d\n", rec->flags));
rec->fileUnitSize = *(uint8 *)buffer;
buffer++;
TRACE(("InitNode - fileUnitSize is %d\n", rec->fileUnitSize));
rec->interleaveGapSize = *(uint8 *)buffer;
buffer++;
TRACE(("InitNode - interleave gap size = %d\n", rec->interleaveGapSize));
rec->volSeqNum = *(uint32 *)buffer;
buffer += 4;
TRACE(("InitNode - volume seq num is %ld\n", rec->volSeqNum));
rec->fileIDLen = *(uint8*)buffer;
buffer++;
TRACE(("InitNode - file id length is %d\n", rec->fileIDLen));
if (rec->fileIDLen > 0) {
// JOLIET extension:
// on joliet discs, buffer[0] can be 0 for Unicoded filenames,
// so I've added a check here to test explicitely for
// directories (which have length 1)
if (rec->fileIDLen == 1) {
// Take care of "." and "..", the first two dirents are
// these in iso.
if (buffer[0] == 0) {
rec->fileIDString = strdup(".");
rec->fileIDLen = 1;
} else if (buffer[0] == 1) {
rec->fileIDString = strdup("..");
rec->fileIDLen = 2;
}
} else {
// JOLIET extension:
// convert Unicode16 string to UTF8
if (joliet_level > 0) {
// Assume that the unicode->utf8 conversion produces 4 byte
// utf8 characters, and allocate that much space
rec->fileIDString = (char *)malloc(rec->fileIDLen * 2 + 1);
if (rec->fileIDString != NULL) {
status_t err;
int32 srcLen = rec->fileIDLen;
int32 dstLen = rec->fileIDLen * 2;
err = unicode_to_utf8(buffer, &srcLen, rec->fileIDString, &dstLen);
if (err < B_NO_ERROR) {
dprintf("iso9660: error converting unicode->utf8\n");
result = err;
} else {
rec->fileIDString[dstLen] = '\0';
rec->fileIDLen = dstLen;
}
} else {
// Error
result = ENOMEM;
TRACE(("InitNode - unable to allocate memory!\n"));
}
} else {
rec->fileIDString = (char *)malloc((rec->fileIDLen) + 1);
if (rec->fileIDString != NULL) {
strncpy(rec->fileIDString, buffer, rec->fileIDLen);
rec->fileIDString[rec->fileIDLen] = '\0';
} else {
// Error
result = ENOMEM;
TRACE(("InitNode - unable to allocate memory!\n"));
}
}
}
// Get rid of semicolons, which are used to delineate file versions.q
{
char *semi = NULL;
while ((semi = strchr(rec->fileIDString, ';')) != NULL)
semi[0] = '\0';
}
TRACE(("DirRec ID String is: %s\n", rec->fileIDString));
if (result == B_NO_ERROR) {
buffer += rec->fileIDLen;
if (!(rec->fileIDLen % 2))
buffer++;
// Now we're at the start of the rock ridge stuff
{
char *altName = NULL;
char *slName = NULL;
uint16 altNameSize = 0;
uint16 slNameSize = 0;
uint8 slFlags = 0;
uint8 length = 0;
bool done = FALSE;
TRACE(("RR: Start of extensions, but at %p\n", buffer));
memset(&(rec->attr.stat), 0, 2 * sizeof(struct stat));
// Set defaults, in case there is no RR stuff.
rec->attr.stat[FS_DATA_FORMAT].st_mode = (S_IRUSR | S_IRGRP | S_IROTH);
while (!done)
{
buffer += length;
length = *(uint8 *)(buffer + 2);
switch (0x100 * buffer[0] + buffer[1])
{
// Stat structure stuff
case 'PX':
{
uint8 bytePos = 3;
TRACE(("RR: found PX, length %u\n", length));
rec->attr.pxVer = *(uint8*)(buffer + bytePos++);
no_rock_ridge_stat_struct = FALSE;
// st_mode
rec->attr.stat[LSB_DATA].st_mode = *(mode_t*)(buffer + bytePos);
bytePos += 4;
rec->attr.stat[MSB_DATA].st_mode = *(mode_t*)(buffer + bytePos);
bytePos += 4;
// st_nlink
rec->attr.stat[LSB_DATA].st_nlink = *(nlink_t*)(buffer+bytePos);
bytePos += 4;
rec->attr.stat[MSB_DATA].st_nlink = *(nlink_t*)(buffer + bytePos);
bytePos += 4;
// st_uid
rec->attr.stat[LSB_DATA].st_uid = *(uid_t*)(buffer+bytePos);
bytePos += 4;
rec->attr.stat[MSB_DATA].st_uid = *(uid_t*)(buffer+bytePos);
bytePos += 4;
// st_gid
rec->attr.stat[LSB_DATA].st_gid = *(gid_t*)(buffer+bytePos);
bytePos += 4;
rec->attr.stat[MSB_DATA].st_gid = *(gid_t*)(buffer+bytePos);
bytePos += 4;
break;
}
case 'PN':
TRACE(("RR: found PN, length %u\n", length));
break;
// Symbolic link info
case 'SL':
{
uint8 bytePos = 3;
uint8 lastCompFlag = 0;
uint8 addPos = 0;
bool slDone = FALSE;
bool useSeparator = TRUE;
TRACE(("RR: found SL, length %u\n", length));
TRACE(("Buffer is at %p\n", buffer));
TRACE(("Current length is %u\n", slNameSize));
//kernel_debugger("");
rec->attr.slVer = *(uint8*)(buffer + bytePos++);
slFlags = *(uint8*)(buffer + bytePos++);
TRACE(("sl flags are %u\n", slFlags));
while (!slDone && bytePos < length)
{
uint8 compFlag = *(uint8*)(buffer + bytePos++);
uint8 compLen = *(uint8*)(buffer + bytePos++);
if (slName == NULL) useSeparator = FALSE;
addPos = slNameSize;
TRACE(("sl comp flags are %u, length is %u\n", compFlag, compLen));
TRACE(("Current name size is %u\n", slNameSize));
switch (compFlag)
{
case SLCP_CONTINUE:
useSeparator = FALSE;
default:
// Add the component to the total path.
slNameSize += compLen;
if ( useSeparator ) slNameSize++;
if (slName == NULL)
slName = (char*)malloc(slNameSize + 1);
else
slName = (char*)realloc(slName, slNameSize + 1);
if (useSeparator)
{
TRACE(("Adding separator\n"));
slName[addPos++] = '/';
}
TRACE(("doing memcopy of %u bytes at offset %d\n", compLen, addPos));
memcpy((slName + addPos), (buffer + bytePos), compLen);
addPos += compLen;
useSeparator = TRUE;
break;
case SLCP_CURRENT:
TRACE(("InitNode - found link to current directory\n"));
slNameSize += 2;
if (slName == NULL)
slName = (char*)malloc(slNameSize + 1);
else
slName = (char*)realloc(slName, slNameSize + 1);
memcpy(slName + addPos, "./", 2);
useSeparator = FALSE;
break;
case SLCP_PARENT:
slNameSize += 3;
if (slName == NULL)
slName = (char*)malloc(slNameSize + 1);
else
slName = (char*)realloc(slName, slNameSize + 1);
memcpy(slName + addPos, "../", 3);
useSeparator = FALSE;
break;
case SLCP_ROOT:
TRACE(("InitNode - found link to root directory\n"));
slNameSize += 1;
if (slName == NULL)
slName = (char*)malloc(slNameSize + 1);
else
slName = (char*)realloc(slName, slNameSize + 1);
memcpy(slName + addPos, "/", 1);
useSeparator = FALSE;
break;
case SLCP_VOLROOT:
slDone = TRUE;
break;
case SLCP_HOST:
slDone = TRUE;
break;
}
slName[slNameSize] = '\0';
lastCompFlag = compFlag;
bytePos += compLen;
TRACE(("Current sl name is \'%s\'\n", slName));
}
rec->attr.slName = slName;
TRACE(("InitNode = symlink name is \'%s\'\n", slName));
break;
}
// Altername name
case 'NM':
{
uint8 bytePos = 3;
uint8 flags = 0;
uint16 oldEnd = altNameSize;
altNameSize += length - 5;
if (altName == NULL)
altName = (char *)malloc(altNameSize + 1);
else
altName = (char *)realloc(altName, altNameSize + 1);
TRACE(("RR: found NM, length %u\n", length));
// Read flag and version.
rec->attr.nmVer = *(uint8 *)(buffer + bytePos++);
flags = *(uint8 *)(buffer + bytePos++);
TRACE(("RR: nm buffer is %s, start at %p\n", (buffer + bytePos), buffer + bytePos));
// Build the file name.
memcpy(altName + oldEnd, buffer + bytePos, length - 5);
altName[altNameSize] = '\0';
TRACE(("RR: alt name is %s\n", altName));
// If the name is not continued in another record, update
// the record name.
if (!(flags & NM_CONTINUE))
{
// Get rid of the ISO name, replace with RR name.
if (rec->fileIDString != NULL)
free(rec->fileIDString);
rec->fileIDString = altName;
rec->fileIDLen = altNameSize;
}
break;
}
// Deep directory record masquerading as a file.
case 'CL':
TRACE(("RR: found CL, length %u\n", length));
rec->flags |= ISO_ISDIR;
rec->startLBN[LSB_DATA] = *(uint32*)(buffer+4);
rec->startLBN[MSB_DATA] = *(uint32*)(buffer+8);
break;
case 'PL':
TRACE(("RR: found PL, length %u\n", length));
break;
// Relocated directory, we should skip.
case 'RE':
result = EINVAL;
TRACE(("RR: found RE, length %u\n", length));
break;
case 'TF':
TRACE(("RR: found TF, length %u\n", length));
break;
case 'RR':
TRACE(("RR: found RR, length %u\n", length));
break;
default:
TRACE(("RR: %c%c (%d, %d)\n",buffer[0],buffer[1],buffer[0],buffer[1]));
TRACE(("RR: End of extensions.\n"));
done = TRUE;
break;
}
}
}
}
} else {
TRACE(("InitNode - File ID String is 0 length\n"));
result = ENOENT;
}
} else
result = ENOENT;
TRACE(("InitNode - EXIT, result is %s name is \'%s\'\n", strerror(result), rec->fileIDString));
if (no_rock_ridge_stat_struct) {
if (rec->flags & ISO_ISDIR)
rec->attr.stat[FS_DATA_FORMAT].st_mode |= (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH);
else
rec->attr.stat[FS_DATA_FORMAT].st_mode |= (S_IFREG);
}
return result;
}
static int
InitVolDate(ISOVolDate *date, char *buffer)
{
memcpy(date, buffer, 17);
return 0;
}
static int
InitRecDate(ISORecDate *date, char *buffer)
{
memcpy(date, buffer, 7);
return 0;
}
int
ConvertRecDate(ISORecDate* inDate, time_t* outDate)
{
time_t time;
int days, i, year, tz;
year = inDate->year -70;
tz = inDate->offsetGMT;
if (year < 0) {
time = 0;
} else {
const int monlen[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
days = (year * 365);
if (year > 2)
days += (year + 1)/ 4;
for (i = 1; (i < inDate->month) && (i < 12); i++) {
days += monlen[i-1];
}
if (((year + 2) % 4) == 0 && inDate->month > 2)
days++;
days += inDate->date - 1;
time = ((((days*24) + inDate->hour) * 60 + inDate->minute) * 60)
+ inDate->second;
if (tz & 0x80)
tz |= (-1 << 8);
if (-48 <= tz && tz <= 52)
time += tz *15 * 60;
}
*outDate = time;
return 0;
}

View File

@ -0,0 +1,930 @@
/*
* 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.
*/
#include "iso9660.h"
#include <ctype.h>
#include <dirent.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include <ByteOrder.h>
#include <Drivers.h>
#include <KernelExport.h>
#include <fs_cache.h>
#include "rock_ridge.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);
// ISO9660 should start with this string
const char *kISO9660IDString = "CD001";
static int
get_device_block_size(int fd)
{
device_geometry geometry;
if (ioctl(fd, B_GET_GEOMETRY, &geometry) < 0) {
struct stat st;
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 geometry.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;
}
static void
sanitize_iso_name(iso9660_inode* node, bool removeTrailingPoints)
{
// Get rid of semicolons, which are used to delineate file versions.
if (char* semi = strchr(node->name, ';')) {
semi[0] = '\0';
node->name_length = semi - node->name;
}
if (removeTrailingPoints) {
// Get rid of trailing points
if (node->name_length > 2 && node->name[node->name_length - 1] == '.')
node->name[--node->name_length] = '\0';
}
}
static int
init_volume_date(ISOVolDate *date, char *buffer)
{
memcpy(date, buffer, 17);
return 0;
}
static int
init_node_date(ISORecDate *date, char *buffer)
{
memcpy(date, buffer, 7);
return 0;
}
static status_t
InitVolDesc(iso9660_volume *volume, char *buffer)
{
TRACE(("InitVolDesc - ENTER\n"));
volume->volDescType = *(uint8 *)buffer++;
volume->stdIDString[5] = '\0';
strncpy(volume->stdIDString, buffer, 5);
buffer += 5;
volume->volDescVersion = *(uint8 *)buffer;
buffer += 2; // 8th byte unused
volume->systemIDString[32] = '\0';
strncpy(volume->systemIDString, buffer, 32);
buffer += 32;
TRACE(("InitVolDesc - system id string is %s\n", volume->systemIDString));
volume->volIDString[32] = '\0';
strncpy(volume->volIDString, buffer, 32);
buffer += (32 + 80-73 + 1); // bytes 80-73 unused
TRACE(("InitVolDesc - volume id string is %s\n", volume->volIDString));
volume->volSpaceSize[LSB_DATA] = *(uint32 *)buffer;
buffer += 4;
volume->volSpaceSize[MSB_DATA] = *(uint32 *)buffer;
buffer+= (4 + 120-89 + 1); // bytes 120-89 unused
volume->volSetSize[LSB_DATA] = *(uint16*)buffer;
buffer += 2;
volume->volSetSize[MSB_DATA] = *(uint16*)buffer;
buffer += 2;
volume->volSeqNum[LSB_DATA] = *(uint16*)buffer;
buffer += 2;
volume->volSeqNum[MSB_DATA] = *(uint16*)buffer;
buffer += 2;
volume->logicalBlkSize[LSB_DATA] = *(uint16*)buffer;
buffer += 2;
volume->logicalBlkSize[MSB_DATA] = *(uint16*)buffer;
buffer += 2;
volume->pathTblSize[LSB_DATA] = *(uint32*)buffer;
buffer += 4;
volume->pathTblSize[MSB_DATA] = *(uint32*)buffer;
buffer += 4;
volume->lPathTblLoc[LSB_DATA] = *(uint16*)buffer;
buffer += 2;
volume->lPathTblLoc[MSB_DATA] = *(uint16*)buffer;
buffer += 2;
volume->optLPathTblLoc[LSB_DATA] = *(uint16*)buffer;
buffer += 2;
volume->optLPathTblLoc[MSB_DATA] = *(uint16*)buffer;
buffer += 2;
volume->mPathTblLoc[LSB_DATA] = *(uint16*)buffer;
buffer += 2;
volume->mPathTblLoc[MSB_DATA] = *(uint16*)buffer;
buffer += 2;
volume->optMPathTblLoc[LSB_DATA] = *(uint16*)buffer;
buffer += 2;
volume->optMPathTblLoc[MSB_DATA] = *(uint16*)buffer;
buffer += 2;
// Fill in directory record.
InitNode(&volume->rootDirRec, buffer, NULL, 0);
volume->rootDirRec.id = ISO_ROOTNODE_ID;
buffer += 34;
volume->volSetIDString[128] = '\0';
strncpy(volume->volSetIDString, buffer, 128);
buffer += 128;
TRACE(("InitVolDesc - volume set id string is %s\n", volume->volSetIDString));
volume->pubIDString[128] = '\0';
strncpy(volume->pubIDString, buffer, 128);
buffer += 128;
TRACE(("InitVolDesc - volume pub id string is %s\n", volume->pubIDString));
volume->dataPreparer[128] = '\0';
strncpy(volume->dataPreparer, buffer, 128);
buffer += 128;
TRACE(("InitVolDesc - volume dataPreparer string is %s\n", volume->dataPreparer));
volume->appIDString[128] = '\0';
strncpy(volume->appIDString, buffer, 128);
buffer += 128;
TRACE(("InitVolDesc - volume app id string is %s\n", volume->appIDString));
volume->copyright[38] = '\0';
strncpy(volume->copyright, buffer, 38);
buffer += 38;
TRACE(("InitVolDesc - copyright is %s\n", volume->copyright));
volume->abstractFName[38] = '\0';
strncpy(volume->abstractFName, buffer, 38);
buffer += 38;
volume->biblioFName[38] = '\0';
strncpy(volume->biblioFName, buffer, 38);
buffer += 38;
init_volume_date(&volume->createDate, buffer);
buffer += 17;
init_volume_date(&volume->modDate, buffer);
buffer += 17;
init_volume_date(&volume->expireDate, buffer);
buffer += 17;
init_volume_date(&volume->effectiveDate, buffer);
buffer += 17;
volume->fileStructVers = *(uint8*)buffer;
return B_OK;
}
static status_t
parse_rock_ridge(iso9660_inode* node, char* buffer, char* end)
{
// 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 at %p\n", buffer));
while (!done) {
buffer += length;
if (buffer + 2 >= end)
break;
length = *(uint8*)(buffer + 2);
if (buffer + length > end)
break;
switch (((int)buffer[0] << 8) + buffer[1]) {
// Stat structure stuff
case 'PX':
{
uint8 bytePos = 3;
TRACE(("RR: found PX, length %u\n", length));
node->attr.pxVer = *(uint8*)(buffer + bytePos++);
// st_mode
node->attr.stat[LSB_DATA].st_mode
= *(mode_t*)(buffer + bytePos);
bytePos += 4;
node->attr.stat[MSB_DATA].st_mode
= *(mode_t*)(buffer + bytePos);
bytePos += 4;
// st_nlink
node->attr.stat[LSB_DATA].st_nlink
= *(nlink_t*)(buffer+bytePos);
bytePos += 4;
node->attr.stat[MSB_DATA].st_nlink
= *(nlink_t*)(buffer + bytePos);
bytePos += 4;
// st_uid
node->attr.stat[LSB_DATA].st_uid
= *(uid_t*)(buffer + bytePos);
bytePos += 4;
node->attr.stat[MSB_DATA].st_uid
= *(uid_t*)(buffer + bytePos);
bytePos += 4;
// st_gid
node->attr.stat[LSB_DATA].st_gid
= *(gid_t*)(buffer + bytePos);
bytePos += 4;
node->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("");
node->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++;
slName = (char*)realloc(slName,
slNameSize + 1);
if (slName == NULL)
return B_NO_MEMORY;
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;
slName = (char*)realloc(slName,
slNameSize + 1);
if (slName == NULL)
return B_NO_MEMORY;
memcpy(slName + addPos, "./", 2);
useSeparator = false;
break;
case SLCP_PARENT:
slNameSize += 3;
slName = (char*)realloc(slName,
slNameSize + 1);
if (slName == NULL)
return B_NO_MEMORY;
memcpy(slName + addPos, "../", 3);
useSeparator = false;
break;
case SLCP_ROOT:
TRACE(("InitNode - found link to root directory\n"));
slNameSize += 1;
slName = (char*)realloc(slName,
slNameSize + 1);
if (slName == NULL)
return B_NO_MEMORY;
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));
}
node->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;
altName = (char*)realloc(altName, altNameSize + 1);
if (altName == NULL)
return B_NO_MEMORY;
TRACE(("RR: found NM, length %u\n", length));
// Read flag and version.
node->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 (node->name != NULL)
free(node->name);
node->name = altName;
node->name_length = altNameSize;
}
break;
}
// Deep directory record masquerading as a file.
case 'CL':
TRACE(("RR: found CL, length %u\n", length));
node->flags |= ISO_ISDIR;
node->startLBN[LSB_DATA] = *(uint32*)(buffer+4);
node->startLBN[MSB_DATA] = *(uint32*)(buffer+8);
break;
case 'PL':
TRACE(("RR: found PL, length %u\n", length));
break;
case 'RE':
// Relocated directory, we should skip.
TRACE(("RR: found RE, length %u\n", length));
return B_BAD_VALUE;
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: %x, %x, end of extensions.\n",
buffer[0], buffer[1]));
done = true;
break;
}
}
return B_OK;
}
// #pragma mark - ISO-9660 specific exported functions
status_t
ISOMount(const char *path, uint32 flags, iso9660_volume **_newVolume,
bool allowJoliet)
{
// 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 isISO = false;
off_t offset = 0x8000;
ssize_t retval;
partition_info partitionInfo;
int deviceBlockSize, multiplier;
iso9660_volume *volume;
(void)flags;
TRACE(("ISOMount - ENTER\n"));
volume = (iso9660_volume *)calloc(sizeof(iso9660_volume), 1);
if (volume == NULL) {
TRACE(("ISOMount - mem error \n"));
return B_NO_MEMORY;
}
memset(&partitionInfo, 0, sizeof(partition_info));
/* open and lock the device */
volume->fdOfSession = open(path, O_RDONLY);
/* try to open the raw device to get access to the other sessions as well */
if (volume->fdOfSession >= 0) {
if (ioctl(volume->fdOfSession, B_GET_PARTITION_INFO, &partitionInfo) < 0) {
TRACE(("B_GET_PARTITION_INFO: ioctl returned error\n"));
strcpy(partitionInfo.device, path);
}
TRACE(("ISOMount: open device/file \"%s\"\n", partitionInfo.device));
volume->fd = open(partitionInfo.device, O_RDONLY);
}
if (volume->fdOfSession < 0 || volume->fd < 0) {
close(volume->fd);
close(volume->fdOfSession);
TRACE(("ISO9660 ERROR - Unable to open <%s>\n", path));
free(volume);
return B_BAD_VALUE;
}
deviceBlockSize = get_device_block_size(volume->fdOfSession);
if (deviceBlockSize < 0) {
TRACE(("ISO9660 ERROR - device block size is 0\n"));
close(volume->fd);
close(volume->fdOfSession);
free(volume);
return B_BAD_VALUE;
}
volume->joliet_level = 0;
while (!done && offset < 0x10000) {
retval = read_pos(volume->fdOfSession, offset, (void*)buffer,
ISO_PVD_SIZE);
if (retval < ISO_PVD_SIZE) {
isISO = false;
break;
}
if (strncmp(buffer + 1, kISO9660IDString, 5) == 0) {
if (*buffer == 0x01 && !isISO) {
// ISO_VD_PRIMARY
off_t maxBlocks;
TRACE(("ISOMount: Is an ISO9660 volume, initting rec\n"));
InitVolDesc(volume, buffer);
strncpy(volume->devicePath,path,127);
volume->id = ISO_ROOTNODE_ID;
TRACE(("ISO9660: volume->blockSize = %d\n", volume->logicalBlkSize[FS_DATA_FORMAT]));
multiplier = deviceBlockSize / volume->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)
/ volume->logicalBlkSize[FS_DATA_FORMAT];
} else
maxBlocks = volume->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", volume->fd, maxBlocks));
volume->fBlockCache = block_cache_create(volume->fd, maxBlocks,
volume->logicalBlkSize[FS_DATA_FORMAT], true);
isISO = true;
} else if (*buffer == 0x02 && isISO && allowJoliet) {
// 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: volume->joliet_level = 1; break;
case 0x43: volume->joliet_level = 2; break;
case 0x45: volume->joliet_level = 3; break;
}
TRACE(("ISO9660 Extensions: Microsoft Joliet Level %d\n", volume->joliet_level));
// Because Joliet-stuff starts at other sector,
// update root directory record.
if (volume->joliet_level > 0)
InitNode(&volume->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 (!isISO) {
// It isn't an ISO disk.
close(volume->fdOfSession);
close(volume->fd);
free(volume);
TRACE(("ISOMount: Not an ISO9660 volume!\n"));
return B_BAD_VALUE;
}
TRACE(("ISOMount - EXIT, returning %p\n", volume));
*_newVolume = volume;
return B_OK;
}
/*! 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.
*/
status_t
ISOReadDirEnt(iso9660_volume *volume, dircookie *cookie, struct dirent *dirent,
size_t bufferSize)
{
off_t totalRead = cookie->pos + (cookie->block - cookie->startBlock)
* volume->logicalBlkSize[FS_DATA_FORMAT];
off_t cacheBlock;
char *blockData;
int result = B_NO_ERROR;
size_t bytesRead = 0;
TRACE(("ISOReadDirEnt - ENTER\n"));
// If we're at the end of the data in a block, move to the next block.
while (true) {
blockData = (char*)block_cache_get(volume->fBlockCache, cookie->block);
if (blockData != NULL && *(blockData + cookie->pos) == 0) {
// NULL data, move to next block.
block_cache_put(volume->fBlockCache, cookie->block);
blockData = NULL;
totalRead += volume->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) {
iso9660_inode node;
result = InitNode(&node, blockData + cookie->pos, &bytesRead,
volume->joliet_level);
if (result == B_OK) {
size_t nameBufferSize = bufferSize - sizeof(struct dirent);
dirent->d_dev = volume->id;
dirent->d_ino = ((ino_t)cookie->block << 30)
+ (cookie->pos & 0x3fffffff);
dirent->d_reclen = sizeof(struct dirent) + node.name_length + 1;
if (node.name_length <= nameBufferSize) {
// need to do some size checking here.
strlcpy(dirent->d_name, node.name, node.name_length + 1);
TRACE(("ISOReadDirEnt - success, name is %s, block %Ld, pos "
"%Ld, inode id %Ld\n", dirent->d_name, cookie->block,
cookie->pos, dirent->d_ino));
} else {
// TODO: this can be just normal if we support reading more
// than one entry.
TRACE(("ISOReadDirEnt - ERROR, name %s does not fit in buffer "
"of size %lu\n", node.name, nameBufferSize));
result = B_BAD_VALUE;
}
cookie->pos += bytesRead;
}
} else {
if (totalRead >= cookie->totalSize)
result = B_ENTRY_NOT_FOUND;
else
result = B_NO_MEMORY;
}
if (blockData != NULL)
block_cache_put(volume->fBlockCache, cacheBlock);
TRACE(("ISOReadDirEnt - EXIT, result is %s, vnid is %Lu\n",
strerror(result), dirent->d_ino));
return result;
}
status_t
InitNode(iso9660_inode* node, char* buffer, size_t* _bytesRead,
uint8 jolietLevel)
{
uint8 recordLength = *(uint8*)buffer++;
size_t nameLength;
TRACE(("InitNode - ENTER, bufstart is %p, record length is %d bytes\n",
buffer, recordLength));
if (_bytesRead != NULL)
*_bytesRead = recordLength;
if (recordLength == 0)
return B_ENTRY_NOT_FOUND;
char* end = buffer + recordLength;
node->cache = NULL;
node->name = NULL;
node->attr.slName = NULL;
memset(node->attr.stat, 0, sizeof(node->attr.stat));
node->extAttrRecLen = *(uint8*)buffer++;
node->startLBN[LSB_DATA] = *(uint32*)buffer;
buffer += 4;
node->startLBN[MSB_DATA] = *(uint32*)buffer;
buffer += 4;
TRACE(("InitNode - data start LBN is %ld\n", node->startLBN[FS_DATA_FORMAT]));
node->dataLen[LSB_DATA] = *(uint32*)buffer;
buffer += 4;
node->dataLen[MSB_DATA] = *(uint32*)buffer;
buffer += 4;
TRACE(("InitNode - data length is %ld\n", node->dataLen[FS_DATA_FORMAT]));
init_node_date(&node->recordDate, buffer);
buffer += 7;
node->flags = *(uint8*)buffer;
buffer++;
TRACE(("InitNode - flags are %d\n", node->flags));
node->fileUnitSize = *(uint8*)buffer;
buffer++;
TRACE(("InitNode - fileUnitSize is %d\n", node->fileUnitSize));
node->interleaveGapSize = *(uint8*)buffer;
buffer++;
TRACE(("InitNode - interleave gap size = %d\n", node->interleaveGapSize));
node->volSeqNum = *(uint32*)buffer;
buffer += 4;
TRACE(("InitNode - volume seq num is %ld\n", node->volSeqNum));
node->name_length = *(uint8*)buffer;
buffer++;
TRACE(("InitNode - file id length is %lu\n", node->name_length));
// Set defaults, in case there is no RockRidge stuff.
node->attr.stat[FS_DATA_FORMAT].st_mode |= (node->flags & ISO_ISDIR) != 0
? S_IFDIR | S_IXUSR | S_IRUSR | S_IXGRP | S_IRGRP | S_IXOTH | S_IROTH
: S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
if (node->name_length == 0) {
TRACE(("InitNode - File ID String is 0 length\n"));
return B_ENTRY_NOT_FOUND;
}
nameLength = node->name_length;
// 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 (node->name_length == 1) {
// Take care of "." and "..", the first two dirents are
// these in iso.
if (buffer[0] == 0) {
node->name = strdup(".");
node->name_length = 1;
} else if (buffer[0] == 1) {
node->name = strdup("..");
node->name_length = 2;
}
} else {
if (jolietLevel > 0) {
// JOLIET extension: convert Unicode16 string to UTF8
// Assume that the unicode->utf8 conversion produces 4 byte
// utf8 characters, and allocate that much space
node->name = (char*)malloc(node->name_length * 2 + 1);
if (node->name == NULL)
return B_NO_MEMORY;
int32 sourceLength = node->name_length;
int32 destLength = node->name_length * 2;
status_t status = unicode_to_utf8(buffer, &sourceLength,
node->name, &destLength);
if (status < B_OK) {
dprintf("iso9660: error converting unicode->utf8\n");
return status;
}
node->name[destLength] = '\0';
node->name_length = destLength;
sanitize_iso_name(node, false);
} else {
node->name = (char*)malloc(node->name_length + 1);
if (node->name == NULL)
return B_NO_MEMORY;
// convert all characters to lower case
for (uint32 i = 0; i < node->name_length; i++) {
node->name[i] = tolower(buffer[i]);
}
node->name[node->name_length] = '\0';
sanitize_iso_name(node, true);
}
}
if (node->name == NULL) {
TRACE(("InitNode - unable to allocate memory!\n"));
return B_NO_MEMORY;
}
buffer += nameLength;
if (nameLength % 2 == 0)
buffer++;
TRACE(("DirRec ID String is: %s\n", node->name));
return parse_rock_ridge(node, buffer, end);
}
status_t
ConvertRecDate(ISORecDate* inDate, time_t* outDate)
{
time_t time;
int days, i, year, tz;
year = inDate->year -70;
tz = inDate->offsetGMT;
if (year < 0) {
time = 0;
} else {
const int monlen[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
days = (year * 365);
if (year > 2)
days += (year + 1)/ 4;
for (i = 1; (i < inDate->month) && (i < 12); i++) {
days += monlen[i-1];
}
if (((year + 2) % 4) == 0 && inDate->month > 2)
days++;
days += inDate->date - 1;
time = ((((days*24) + inDate->hour) * 60 + inDate->minute) * 60)
+ inDate->second;
if (tz & 0x80)
tz |= (-1 << 8);
if (-48 <= tz && tz <= 52)
time += tz *15 * 60;
}
*outDate = time;
return 0;
}

View File

@ -22,7 +22,7 @@
// Size of primary volume descriptor for ISO9660
#define ISO_PVD_SIZE 882
// ISO structure has both msb and lsb first data. These let you do a
// ISO structure has both msb and lsb first data. These let you do a
// compile-time switch for different platforms.
enum {
@ -62,34 +62,24 @@ typedef struct ISORecDate {
int8 offsetGMT;
} ISORecDate;
/* This next section is data structure to hold the data found in the rock ridge extensions. */
typedef struct RRAttr {
// This next section is data structure to hold the data found in the
// rock ridge extensions.
struct rock_ridge_attributes {
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 {
struct iso9660_inode {
/* Most drivers will probably want the first things defined here. */
ino_t id;
ino_t id;
ino_t parID; // parent vnode ID.
void *cache; // for file cache
// 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.
*/
@ -97,7 +87,7 @@ typedef struct vnode {
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
@ -109,25 +99,25 @@ typedef struct vnode {
// 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)
char* name;
uint32 name_length;
// The rest is Rock Ridge extensions. I suggest www.leo.org for spec info.
RRAttr attr;
} vnode;
rock_ridge_attributes attr;
};
// These go with the flags member of the nspace struct.
// These go with the flags member of the iso9660_volume struct.
enum {
ISO_ISHIDDEN = 0,
ISO_ISHIDDEN = 0,
ISO_ISDIR = 2,
ISO_ISASSOCFILE = 4,
ISO_EXTATTR = 8,
ISO_EXTPERM = 16,
ISO_MOREDIRS = 128
ISO_ISASSOCFILE = 4,
ISO_EXTATTR = 8,
ISO_EXTPERM = 16,
ISO_MOREDIRS = 128
};
@ -137,7 +127,7 @@ enum {
/* 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
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 {
@ -147,8 +137,8 @@ typedef struct dircookie {
off_t totalSize; // Size of directory file
off_t id;
} dircookie;
/* You may also need to define a cookie for files, which again is
/* 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.
*/
@ -158,12 +148,8 @@ typedef struct attrfilemap {
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 {
// This is the global volume iso9660_volume struct.
struct iso9660_volume {
// Start of members other drivers will definitely want.
fs_volume *volume; // volume passed fo fs_mount
dev_t id;
@ -171,10 +157,10 @@ typedef struct nspace {
int fdOfSession; // File descriptor of the (mounted) session
//unsigned int blockSize; // usually need this, but it's part of ISO
void *fBlockCache;
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
@ -204,7 +190,7 @@ typedef struct nspace {
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
iso9660_inode 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
@ -217,23 +203,17 @@ typedef struct nspace {
ISOVolDate modDate; // Modification date
ISOVolDate expireDate; // Data expiration date
ISOVolDate effectiveDate; // Data effective data
uint8 fileStructVers; // File structure version byte882
} nspace;
};
#ifdef __cplusplus
extern "C" {
#endif
int ISOMount(const char *path, const int flags, nspace** newVolume,
status_t ISOMount(const char *path, uint32 flags, iso9660_volume** _newVolume,
bool allowJoliet);
int ISOReadDirEnt(nspace* ns, dircookie* cookie, struct dirent* buffer,
size_t bufferSize);
int InitNode(vnode* rec, char* buf, int* bytesRead, uint8 jolietLevel);
int ConvertRecDate(ISORecDate* inDate, time_t* outDate);
#ifdef __cplusplus
}
#endif
status_t ISOReadDirEnt(iso9660_volume* ns, dircookie* cookie,
struct dirent* buffer, size_t bufferSize);
status_t InitNode(iso9660_inode* rec, char* buf, size_t* bytesRead,
uint8 jolietLevel);
status_t ConvertRecDate(ISORecDate* inDate, time_t* outDate);
#endif /* ISO_9660_H */

View File

@ -104,7 +104,7 @@ fs_mount(fs_volume *_volume, const char *device, uint32 flags,
const char *args, ino_t *_rootID)
{
bool allowJoliet = true;
nspace *volume;
iso9660_volume *volume;
// Check for a 'nojoliet' parm
// all we check for is the existance of 'nojoliet' in the parms.
@ -152,7 +152,7 @@ static status_t
fs_unmount(fs_volume *_vol)
{
status_t result = B_NO_ERROR;
nspace *ns = (nspace *)_vol->private_volume;
iso9660_volume *ns = (iso9660_volume *)_vol->private_volume;
TRACE(("fs_unmount - ENTER\n"));
@ -173,7 +173,7 @@ fs_unmount(fs_volume *_vol)
static status_t
fs_read_fs_stat(fs_volume *_vol, struct fs_info *fss)
{
nspace *ns = (nspace *)_vol->private_volume;
iso9660_volume *ns = (iso9660_volume *)_vol->private_volume;
int i;
fss->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY;
@ -203,9 +203,9 @@ fs_read_fs_stat(fs_volume *_vol, struct fs_info *fss)
static status_t
fs_get_vnode_name(fs_volume *_vol, fs_vnode *_node, char *buffer, size_t bufferSize)
{
vnode *node = (vnode*)_node->private_node;
iso9660_inode *node = (iso9660_inode*)_node->private_node;
strlcpy(buffer, node->fileIDString, bufferSize);
strlcpy(buffer, node->name, bufferSize);
return B_OK;
}
@ -213,11 +213,11 @@ fs_get_vnode_name(fs_volume *_vol, fs_vnode *_node, char *buffer, size_t bufferS
static status_t
fs_walk(fs_volume *_vol, fs_vnode *_base, const char *file, ino_t *_vnodeID)
{
nspace *ns = (nspace *)_vol->private_volume;
vnode *baseNode = (vnode*)_base->private_node;
vnode *newNode = NULL;
iso9660_volume *ns = (iso9660_volume *)_vol->private_volume;
iso9660_inode *baseNode = (iso9660_inode*)_base->private_node;
iso9660_inode *newNode = NULL;
TRACE(("fs_walk - looking for %s in dir file of length %d\n", file,
TRACE(("fs_walk - looking for %s in dir file of length %ld\n", file,
baseNode->dataLen[FS_DATA_FORMAT]));
if (strcmp(file, ".") == 0) {
@ -235,39 +235,37 @@ fs_walk(fs_volume *_vol, fs_vnode *_base, const char *file, ino_t *_vnodeID)
// look up file in the directory
uint32 dataLength = baseNode->dataLen[FS_DATA_FORMAT];
status_t result = ENOENT;
uint32 totalRead = 0;
size_t totalRead = 0;
off_t block = baseNode->startLBN[FS_DATA_FORMAT];
bool done = false;
while (totalRead < dataLength && !done) {
off_t cachedBlock = block;
char *blockData = (char *)block_cache_get_etc(ns->fBlockCache, block, 0,
ns->logicalBlkSize[FS_DATA_FORMAT]);
char* blockData = (char*)block_cache_get(ns->fBlockCache, block);
if (blockData != NULL) {
int bytesRead = 0;
size_t bytesRead = 0;
off_t blockBytesRead = 0;
vnode node;
iso9660_inode node;
int initResult;
TRACE(("fs_walk - read buffer from disk at LBN %Ld into buffer 0x%x.\n",
block, blockData));
TRACE(("fs_walk - read buffer from disk at LBN %Ld into buffer "
"%p.\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 < dataLength
&& 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));
TRACE(("fs_walk - InitNode returned %s, filename %s, %lu bytes "
"read\n", strerror(initResult), node.name,
bytesRead));
if (initResult == B_OK) {
if (!strcmp(node.fileIDString, file)) {
if (!strcmp(node.name, file)) {
TRACE(("fs_walk - success, found vnode at block %Ld, pos %Ld\n", block, blockBytesRead));
*_vnodeID = (block << 30)
+ (blockBytesRead & 0xffffffff);
@ -280,10 +278,8 @@ fs_walk(fs_volume *_vol, fs_vnode *_base, const char *file, ino_t *_vnodeID)
done = true;
}
} else {
free(node.fileIDString);
node.fileIDString = NULL;
free(node.name);
free(node.attr.slName);
node.attr.slName = NULL;
}
} else {
result = initResult;
@ -293,13 +289,15 @@ fs_walk(fs_volume *_vol, fs_vnode *_base, const char *file, ino_t *_vnodeID)
blockData += bytesRead;
blockBytesRead += bytesRead;
TRACE(("fs_walk - Adding %d bytes to blockBytes read (total %Ld/%Ld).\n",
bytesRead, blockBytesRead, baseNode->dataLen[FS_DATA_FORMAT]));
TRACE(("fs_walk - Adding %lu bytes to blockBytes read (total "
"%Ld/%lu).\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));
TRACE(("fs_walk - moving to next block %Ld, total read %lu\n",
block, totalRead));
block_cache_put(ns->fBlockCache, cachedBlock);
} else
@ -316,16 +314,16 @@ static status_t
fs_read_vnode(fs_volume *_vol, ino_t vnodeID, fs_vnode *_node,
int *_type, uint32 *_flags, bool reenter)
{
nspace *ns = (nspace*)_vol->private_volume;
iso9660_volume *ns = (iso9660_volume*)_vol->private_volume;
vnode *newNode = (vnode*)calloc(sizeof(vnode), 1);
iso9660_inode *newNode = (iso9660_inode*)calloc(sizeof(iso9660_inode), 1);
if (newNode == NULL)
return B_NO_MEMORY;
uint32 pos = vnodeID & 0x3fffffff;
uint32 block = vnodeID >> 30;
TRACE(("fs_read_vnode - block = %ld, pos = %ld, raw = %Lu node 0x%x\n",
TRACE(("fs_read_vnode - block = %ld, pos = %ld, raw = %Lu node %p\n",
block, pos, vnodeID, newNode));
if (pos > ns->logicalBlkSize[FS_DATA_FORMAT]) {
@ -333,8 +331,7 @@ fs_read_vnode(fs_volume *_vol, ino_t vnodeID, fs_vnode *_node,
return B_BAD_VALUE;
}
char *data = (char *)block_cache_get_etc(ns->fBlockCache,
block, 0, ns->logicalBlkSize[FS_DATA_FORMAT]);
char *data = (char *)block_cache_get(ns->fBlockCache, block);
if (data == NULL) {
free(newNode);
return B_IO_ERROR;
@ -364,31 +361,24 @@ fs_read_vnode(fs_volume *_vol, ino_t vnodeID, fs_vnode *_node,
static status_t
fs_release_vnode(fs_volume *_vol, fs_vnode *_node, bool reenter)
fs_release_vnode(fs_volume* /*_volume*/, fs_vnode* _node, bool /*reenter*/)
{
status_t result = B_NO_ERROR;
vnode *node = (vnode*)_node->private_node;
iso9660_inode* node = (iso9660_inode*)_node->private_node;
(void)_vol;
(void)reenter;
TRACE(("fs_release_vnode - ENTER (%p)\n", node));
TRACE(("fs_release_vnode - ENTER (0x%x)\n", node));
if (node->id != ISO_ROOTNODE_ID) {
free(node->name);
free(node->attr.slName);
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);
if (node->cache != NULL)
file_cache_delete(node->cache);
free(node);
}
free(node);
}
TRACE(("fs_release_vnode - EXIT\n"));
return result;
return B_OK;
}
@ -396,8 +386,8 @@ static status_t
fs_read_pages(fs_volume *_vol, fs_vnode *_node, void * _cookie, off_t pos,
const iovec *vecs, size_t count, size_t *_numBytes)
{
nspace *ns = (nspace *)_vol->private_volume;
vnode *node = (vnode *)_node->private_node;
iso9660_volume *ns = (iso9660_volume *)_vol->private_volume;
iso9660_inode *node = (iso9660_inode *)_node->private_node;
uint32 fileSize = node->dataLen[FS_DATA_FORMAT];
size_t bytesLeft = *_numBytes;
@ -426,8 +416,8 @@ fs_read_pages(fs_volume *_vol, fs_vnode *_node, void * _cookie, off_t pos,
static status_t
fs_read_stat(fs_volume *_vol, fs_vnode *_node, struct stat *st)
{
nspace *ns = (nspace*)_vol->private_volume;
vnode *node = (vnode*)_node->private_node;
iso9660_volume *ns = (iso9660_volume*)_vol->private_volume;
iso9660_inode *node = (iso9660_inode*)_node->private_node;
status_t result = B_NO_ERROR;
time_t time;
@ -474,7 +464,7 @@ static status_t
fs_read(fs_volume *_vol, fs_vnode *_node, void *cookie, off_t pos, void *buffer,
size_t *_length)
{
vnode *node = (vnode *)_node->private_node;
iso9660_inode *node = (iso9660_inode *)_node->private_node;
if (node->flags & ISO_ISDIR)
return EISDIR;
@ -529,7 +519,7 @@ fs_access(fs_volume *_vol, fs_vnode *_node, int mode)
static status_t
fs_read_link(fs_volume *_vol, fs_vnode *_node, char *buffer, size_t *_bufferSize)
{
vnode *node = (vnode *)_node->private_node;
iso9660_inode *node = (iso9660_inode *)_node->private_node;
if (!S_ISLNK(node->attr.stat[FS_DATA_FORMAT].st_mode))
return B_BAD_VALUE;
@ -547,16 +537,16 @@ fs_read_link(fs_volume *_vol, fs_vnode *_node, char *buffer, size_t *_bufferSize
static status_t
fs_open_dir(fs_volume *_vol, fs_vnode *_node, void **cookie)
fs_open_dir(fs_volume* /*_volume*/, fs_vnode* _node, void** _cookie)
{
vnode *node = (vnode *)_node->private_node;
iso9660_inode *node = (iso9660_inode *)_node->private_node;
TRACE(("fs_open_dir - node is 0x%x\n", _node));
TRACE(("fs_open_dir - node is %p\n", node));
if (!(node->flags & ISO_ISDIR))
return B_NOT_A_DIRECTORY;
dircookie *dirCookie = (dircookie *)malloc(sizeof(dircookie));
dircookie* dirCookie = (dircookie*)malloc(sizeof(dircookie));
if (dirCookie == NULL)
return B_NO_MEMORY;
@ -565,7 +555,7 @@ fs_open_dir(fs_volume *_vol, fs_vnode *_node, void **cookie)
dirCookie->totalSize = node->dataLen[FS_DATA_FORMAT];
dirCookie->pos = 0;
dirCookie->id = node->id;
*cookie = (void *)dirCookie;
*_cookie = (void*)dirCookie;
return B_OK;
}
@ -575,7 +565,7 @@ static status_t
fs_read_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie,
struct dirent *buffer, size_t bufferSize, uint32 *num)
{
nspace *ns = (nspace *)_vol->private_volume;
iso9660_volume *ns = (iso9660_volume *)_vol->private_volume;
dircookie *dirCookie = (dircookie *)_cookie;
TRACE(("fs_read_dir - ENTER\n"));
@ -591,7 +581,7 @@ fs_read_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie,
// When you get to the end, don't return an error, just return
// a zero in *num.
if (result == ENOENT)
if (result == B_ENTRY_NOT_FOUND)
result = B_OK;
TRACE(("fs_read_dir - EXIT, result is %s\n", strerror(result)));