* 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:
parent
3cdff7414f
commit
eb0974311f
@ -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
|
||||
;
|
||||
|
@ -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;
|
||||
}
|
||||
|
930
src/add-ons/kernel/file_systems/iso9660/iso9660.cpp
Normal file
930
src/add-ons/kernel/file_systems/iso9660/iso9660.cpp
Normal 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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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)));
|
||||
|
Loading…
x
Reference in New Issue
Block a user