#include "iso9660.h"
#include <ctype.h>
#ifndef FS_SHELL
# 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>
#endif
#include "rock_ridge.h"
#if TRACE_ISO9660
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
static status_t unicode_to_utf8(const char *src, int32 *srcLen, char *dst,
int32 *dstLen);
const char *kISO9660IDString = "CD001";
static int
get_device_block_size(int fd)
{
device_geometry geometry;
if (ioctl(fd, B_GET_GEOMETRY, &geometry, sizeof(device_geometry)) < 0) {
struct stat st;
if (fstat(fd, &st) < 0 || S_ISDIR(st.st_mode))
return 0;
return 512;
}
return geometry.bytes_per_sector;
}
#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];
uint8 utf8[4];
uint8 *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)
{
if (char* semi = strchr(node->name, ';')) {
semi[0] = '\0';
node->name_length = semi - node->name;
}
if (removeTrailingPoints) {
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, ISO_VOL_DATE_SIZE);
return 0;
}
static int
init_node_date(ISORecDate *date, char *buffer)
{
memcpy(date, buffer, sizeof(struct ISORecDate));
return 0;
}
static status_t
InitVolDesc(iso9660_volume *volume, char *buffer)
{
TRACE(("InitVolDesc - ENTER\n"));
volume->volDescType = *(uint8 *)buffer;
buffer += sizeof(volume->volDescType);
const size_t kStdIDStringLen = sizeof(volume->stdIDString) - 1;
volume->stdIDString[kStdIDStringLen] = '\0';
strncpy(volume->stdIDString, buffer, kStdIDStringLen);
buffer += kStdIDStringLen;
volume->volDescVersion = *(uint8 *)buffer;
buffer += sizeof(volume->volDescVersion);
buffer += sizeof(volume->unused1);
const size_t kSystemIDStringLen = sizeof(volume->systemIDString) - 1;
volume->systemIDString[kSystemIDStringLen] = '\0';
strncpy(volume->systemIDString, buffer, kSystemIDStringLen);
buffer += kSystemIDStringLen;
TRACE(("InitVolDesc - system id string is %s\n", volume->systemIDString));
const size_t kVolIDStringLen = sizeof(volume->volIDString) - 1;
volume->volIDString[kVolIDStringLen] = '\0';
strncpy(volume->volIDString, buffer, kVolIDStringLen);
buffer += kVolIDStringLen;
TRACE(("InitVolDesc - volume id string is %s\n", volume->volIDString));
buffer += sizeof(volume->unused2) - 1;
volume->volSpaceSize[LSB_DATA] = *(uint32 *)buffer;
buffer += sizeof(volume->volSpaceSize[LSB_DATA]);
volume->volSpaceSize[MSB_DATA] = *(uint32 *)buffer;
buffer += sizeof(volume->volSpaceSize[MSB_DATA]);
buffer += sizeof(volume->unused3) - 1;
volume->volSetSize[LSB_DATA] = *(uint16*)buffer;
buffer += sizeof(volume->volSetSize[LSB_DATA]);
volume->volSetSize[MSB_DATA] = *(uint16*)buffer;
buffer += sizeof(volume->volSetSize[MSB_DATA]);
volume->volSeqNum[LSB_DATA] = *(uint16*)buffer;
buffer += sizeof(volume->volSeqNum[LSB_DATA]);
volume->volSeqNum[MSB_DATA] = *(uint16*)buffer;
buffer += sizeof(volume->volSeqNum[MSB_DATA]);
volume->logicalBlkSize[LSB_DATA] = *(uint16*)buffer;
buffer += sizeof(volume->logicalBlkSize[LSB_DATA]);
volume->logicalBlkSize[MSB_DATA] = *(uint16*)buffer;
buffer += sizeof(volume->logicalBlkSize[MSB_DATA]);
volume->pathTblSize[LSB_DATA] = *(uint32*)buffer;
buffer += sizeof(volume->pathTblSize[LSB_DATA]);
volume->pathTblSize[MSB_DATA] = *(uint32*)buffer;
buffer += sizeof(volume->pathTblSize[MSB_DATA]);
volume->lPathTblLoc[LSB_DATA] = *(uint16*)buffer;
buffer += sizeof(volume->lPathTblLoc[LSB_DATA]);
volume->lPathTblLoc[MSB_DATA] = *(uint16*)buffer;
buffer += sizeof(volume->lPathTblLoc[MSB_DATA]);
volume->optLPathTblLoc[LSB_DATA] = *(uint16*)buffer;
buffer += sizeof(volume->optLPathTblLoc[LSB_DATA]);
volume->optLPathTblLoc[MSB_DATA] = *(uint16*)buffer;
buffer += sizeof(volume->optLPathTblLoc[MSB_DATA]);
volume->mPathTblLoc[LSB_DATA] = *(uint16*)buffer;
buffer += sizeof(volume->mPathTblLoc[LSB_DATA]);
volume->mPathTblLoc[MSB_DATA] = *(uint16*)buffer;
buffer += sizeof(volume->mPathTblLoc[MSB_DATA]);
volume->optMPathTblLoc[LSB_DATA] = *(uint16*)buffer;
buffer += sizeof(volume->optMPathTblLoc[LSB_DATA]);
volume->optMPathTblLoc[MSB_DATA] = *(uint16*)buffer;
buffer += sizeof(volume->optMPathTblLoc[MSB_DATA]);
volume->joliet_level = 0;
InitNode(volume, &volume->rootDirRec, buffer, NULL);
volume->rootDirRec.id = ISO_ROOTNODE_ID;
buffer += ISO_ROOT_DIR_REC_SIZE;
const size_t kVolSetIDStringLen = sizeof(volume->volSetIDString) - 1;
volume->volSetIDString[kVolSetIDStringLen] = '\0';
strncpy(volume->volSetIDString, buffer, kVolSetIDStringLen);
buffer += kVolSetIDStringLen;
TRACE(("InitVolDesc - volume set id string is %s\n", volume->volSetIDString));
const size_t kPubIDStringLen = sizeof(volume->pubIDString) - 1;
volume->pubIDString[kPubIDStringLen] = '\0';
strncpy(volume->pubIDString, buffer, kPubIDStringLen);
buffer += kPubIDStringLen;
TRACE(("InitVolDesc - volume pub id string is %s\n", volume->pubIDString));
const size_t kDataPreparerLen = sizeof(volume->dataPreparer) - 1;
volume->dataPreparer[kDataPreparerLen] = '\0';
strncpy(volume->dataPreparer, buffer, kDataPreparerLen);
buffer += kDataPreparerLen;
TRACE(("InitVolDesc - volume dataPreparer string is %s\n", volume->dataPreparer));
const size_t kAppIDStringLen = sizeof(volume->appIDString) - 1;
volume->appIDString[kAppIDStringLen] = '\0';
strncpy(volume->appIDString, buffer, kAppIDStringLen);
buffer += kAppIDStringLen;
TRACE(("InitVolDesc - volume app id string is %s\n", volume->appIDString));
const size_t kCopyrightLen = sizeof(volume->copyright) - 1;
volume->copyright[kCopyrightLen] = '\0';
strncpy(volume->copyright, buffer, kCopyrightLen);
buffer += kCopyrightLen;
TRACE(("InitVolDesc - copyright is %s\n", volume->copyright));
const size_t kAbstractFNameLen = sizeof(volume->abstractFName) - 1;
volume->abstractFName[kAbstractFNameLen] = '\0';
strncpy(volume->abstractFName, buffer, kAbstractFNameLen);
buffer += kAbstractFNameLen;
const size_t kBiblioFNameLen = sizeof(volume->biblioFName) - 1;
volume->biblioFName[kBiblioFNameLen] = '\0';
strncpy(volume->biblioFName, buffer, kBiblioFNameLen);
buffer += kBiblioFNameLen;
init_volume_date(&volume->createDate, buffer);
buffer += ISO_VOL_DATE_SIZE;
init_volume_date(&volume->modDate, buffer);
buffer += ISO_VOL_DATE_SIZE;
init_volume_date(&volume->expireDate, buffer);
buffer += ISO_VOL_DATE_SIZE;
init_volume_date(&volume->effectiveDate, buffer);
buffer += ISO_VOL_DATE_SIZE;
volume->fileStructVers = *(uint8*)buffer;
return B_OK;
}
static status_t
parse_rock_ridge(iso9660_volume* volume, iso9660_inode* node, char* buffer,
char* end, bool relocated)
{
char* altName = NULL;
char* slName = NULL;
char* newSlName = NULL;
uint16 altNameSize = 0;
uint16 slNameSize = 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;
if (length == 0)
break;
switch (((int)buffer[0] << 8) + buffer[1]) {
case 'PX':
{
uint8 bytePos = 3;
TRACE(("RR: found PX, length %u\n", length));
node->attr.pxVer = *(uint8*)(buffer + bytePos++);
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;
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;
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;
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;
case 'SL':
{
uint8 bytePos = 3;
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));
node->attr.slVer = *(uint8*)(buffer + bytePos++);
#if TRACE_ISO9660
uint8 slFlags = *(uint8*)(buffer + bytePos++);
TRACE(("sl flags are %u\n", slFlags));
#else
++bytePos;
#endif
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:
slNameSize += compLen;
if (useSeparator)
slNameSize++;
newSlName = (char*)realloc(slName,
slNameSize + 1);
if (newSlName == NULL) {
free(slName);
return B_NO_MEMORY;
}
slName = newSlName;
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;
newSlName = (char*)realloc(slName,
slNameSize + 1);
if (newSlName == NULL) {
free(slName);
return B_NO_MEMORY;
}
slName = newSlName;
memcpy(slName + addPos, "./", 2);
useSeparator = false;
break;
case SLCP_PARENT:
slNameSize += 3;
newSlName = (char*)realloc(slName,
slNameSize + 1);
if (newSlName == NULL) {
free(slName);
return B_NO_MEMORY;
}
slName = newSlName;
memcpy(slName + addPos, "../", 3);
useSeparator = false;
break;
case SLCP_ROOT:
TRACE(("InitNode - found link to root directory\n"));
slNameSize += 1;
newSlName = (char*)realloc(slName,
slNameSize + 1);
if (newSlName == NULL) {
free(slName);
return B_NO_MEMORY;
}
slName = newSlName;
memcpy(slName + addPos, "/", 1);
useSeparator = false;
break;
case SLCP_VOLROOT:
slDone = true;
break;
case SLCP_HOST:
slDone = true;
break;
}
if (slName != NULL)
slName[slNameSize] = '\0';
bytePos += compLen;
TRACE(("Current sl name is \'%s\'\n", slName));
}
node->attr.slName = slName;
TRACE(("InitNode = symlink name is \'%s\'\n", slName));
break;
}
case 'NM':
{
uint8 bytePos = 3;
uint8 flags = 0;
uint16 oldEnd = altNameSize;
altNameSize += length - 5;
char* newAltName = (char*)realloc(altName, altNameSize + 1);
if (newAltName == NULL) {
free(altName);
return B_NO_MEMORY;
}
altName = newAltName;
TRACE(("RR: found NM, length %u\n", length));
node->attr.nmVer = *(uint8 *)(buffer + bytePos++);
flags = *(uint8 *)(buffer + bytePos++);
TRACE(("RR: nm buffer is %s, start at %p\n", (buffer + bytePos),
buffer + bytePos));
memcpy(altName + oldEnd, buffer + bytePos, length - 5);
altName[altNameSize] = '\0';
TRACE(("RR: alt name is %s\n", altName));
if (!(flags & NM_CONTINUE)) {
if (node->name != NULL)
free(node->name);
node->name = altName;
node->name_length = altNameSize;
}
break;
}
case 'CL':
{
TRACE(("RR: found CL, length %u\n", length));
node->startLBN[LSB_DATA] = *(uint32*)(buffer+4);
node->startLBN[MSB_DATA] = *(uint32*)(buffer+8);
char* buffer = (char*)block_cache_get(volume->fBlockCache,
node->startLBN[FS_DATA_FORMAT]);
if (buffer == NULL)
break;
InitNode(volume, node, buffer, NULL, true);
block_cache_put(volume->fBlockCache,
node->startLBN[FS_DATA_FORMAT]);
break;
}
case 'PL':
TRACE(("RR: found PL, length %u\n", length));
break;
case 'RE':
TRACE(("RR: found RE, length %u\n", length));
if (!relocated)
return B_UNSUPPORTED;
break;
case 'TF':
TRACE(("RR: found TF, length %u\n", length));
break;
case 'RR':
TRACE(("RR: found RR, length %u\n", length));
break;
case 'SF':
TRACE(("RR: found SF, sparse files not supported!\n"));
return B_UNSUPPORTED;
default:
if (buffer[0] == '\0') {
TRACE(("RR: end of extensions\n"));
done = true;
} else
TRACE(("RR: Unknown tag %c%c\n", buffer[0], buffer[1]));
break;
}
}
return B_OK;
}
status_t
ISOMount(const char *path, uint32 flags, iso9660_volume **_newVolume,
bool allowJoliet)
{
char buffer[ISO_PVD_SIZE];
bool done = false;
bool isISO = false;
off_t offset = 0x8000;
ssize_t retval;
partition_info partitionInfo;
int deviceBlockSize;
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));
volume->fdOfSession = open(path, O_RDONLY);
if (volume->fdOfSession >= 0) {
if (ioctl(volume->fdOfSession, B_GET_PARTITION_INFO, &partitionInfo,
sizeof(partition_info)) < 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) {
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]));
#if TRACE_ISO9660
int multiplier = deviceBlockSize / volume->logicalBlkSize[FS_DATA_FORMAT];
TRACE(("ISOMount: block size multiplier is %d\n", multiplier));
#endif
if (partitionInfo.size != 0) {
maxBlocks = (partitionInfo.size + partitionInfo.offset)
/ volume->logicalBlkSize[FS_DATA_FORMAT];
} else
maxBlocks = volume->volSpaceSize[FS_DATA_FORMAT];
TRACE(("ISO9660: cache init: dev %d, max blocks %lld\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) {
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));
if (volume->joliet_level > 0) {
InitNode(volume, &volume->rootDirRec, &buffer[156],
NULL);
}
}
} else if (*(unsigned char *)buffer == 0xff) {
done = true;
} else
TRACE(("found header %d\n",*buffer));
}
offset += 0x800;
}
if (!isISO) {
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;
}
status_t
ISOReadDirEnt(iso9660_volume *volume, dircookie *cookie, struct dirent *dirent,
size_t bufferSize)
{
int result = B_NO_ERROR;
bool done = false;
TRACE(("ISOReadDirEnt - ENTER\n"));
while (!done) {
off_t totalRead = cookie->pos + (cookie->block - cookie->startBlock)
* volume->logicalBlkSize[FS_DATA_FORMAT];
char *blockData;
while (true) {
blockData
= (char*)block_cache_get(volume->fBlockCache, cookie->block);
if (blockData != NULL && *(blockData + cookie->pos) == 0) {
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;
}
off_t cacheBlock = cookie->block;
if (blockData != NULL && totalRead < cookie->totalSize) {
iso9660_inode node;
size_t bytesRead = 0;
result = InitNode(volume, &node, blockData + cookie->pos,
&bytesRead);
if (result != B_OK && result != B_UNSUPPORTED)
break;
if (result == B_OK && (node.flags & ISO_IS_ASSOCIATED_FILE) == 0) {
size_t nameBufferSize = bufferSize - offsetof(struct dirent, d_name);
dirent->d_dev = volume->id;
dirent->d_ino = ((ino_t)cookie->block << 30)
+ (cookie->pos & 0x3fffffff);
dirent->d_reclen = offsetof(struct dirent, d_name) + node.name_length + 1;
if (node.name_length <= nameBufferSize) {
strlcpy(dirent->d_name, node.name, node.name_length + 1);
TRACE(("ISOReadDirEnt - success, name is %s, block %lld, "
"pos %lld, inode id %lld\n", dirent->d_name, cookie->block,
cookie->pos, dirent->d_ino));
} else {
TRACE(("ISOReadDirEnt - ERROR, name %s does not fit in "
"buffer of size %d\n", node.name, (int)nameBufferSize));
result = B_BAD_VALUE;
}
done = true;
}
cookie->pos += bytesRead;
if (cookie->pos == volume->logicalBlkSize[FS_DATA_FORMAT]) {
cookie->pos = 0;
cookie->block++;
}
} else {
if (totalRead >= cookie->totalSize)
result = B_ENTRY_NOT_FOUND;
else
result = B_NO_MEMORY;
done = true;
}
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_volume* volume, iso9660_inode* node, char* buffer,
size_t* _bytesRead, bool relocated)
{
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;
if (!relocated) {
node->cache = NULL;
node->name = NULL;
node->attr.slName = NULL;
memset(node->attr.stat, 0, sizeof(node->attr.stat));
} else
free(node->attr.slName);
node->extAttrRecLen = *(uint8*)buffer++;
TRACE(("InitNode - ext attr length is %d\n", (int)node->extAttrRecLen));
node->startLBN[LSB_DATA] = *(uint32*)buffer;
buffer += 4;
node->startLBN[MSB_DATA] = *(uint32*)buffer;
buffer += 4;
TRACE(("InitNode - data start LBN is %d\n",
(int)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 %d\n",
(int)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 %d\n", (int)node->volSeqNum));
nameLength = *(uint8*)buffer;
buffer++;
if (!relocated) {
node->name_length = nameLength;
TRACE(("InitNode - file id length is %" B_PRIu32 "\n",
node->name_length));
}
node->attr.stat[FS_DATA_FORMAT].st_mode |= (node->flags & ISO_IS_DIR) != 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;
}
if (!relocated) {
if (node->name_length == 1 && buffer[0] == 0) {
node->name = strdup(".");
node->name_length = 1;
} else if (node->name_length == 1 && buffer[0] == 1) {
node->name = strdup("..");
node->name_length = 2;
} else if (volume->joliet_level > 0) {
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;
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(volume, node, buffer, end, relocated);
}
status_t
ConvertRecDate(ISORecDate* inDate, time_t* outDate)
{
time_t time;
int days, i, year;
int8_t 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 (-48 <= tz && tz <= 52)
time -= tz * 15 * 60;
}
*outDate = time;
return 0;
}